工作中经常遇到要把树状结构的数据展示在表格上的需求,这样可以让使用者更直观的查看一些数据。在网上找到了一些例子,觉得很不错,所以就把这些例子使用下来,并且用自己的一些经验完善一下,现在记录下,以备以后使用。
实现后的样子是这样的:
样式方面,如果有自己的需求,可以自行调节。
话不多说上代码:
<template>
<div class="table-box">
<el-table
:span-method="arraySpanMethod"
:data="tableData"
border
highlight-current-row
style="width: 100%"
>
<el-table-column
v-for="tt in tableTitle"
:key="tt.prop"
:label="tt.title"
:prop="tt.prop"
:type="tt.type"
:width="tt.width"
:align="tt.align"
:show-overflow-tooltip="tt.showoverflowtooltip"
>
<template slot-scope="scope">
<template v-if="tt.scopeType == 'spanClick'">
<span @click="spanClick(scope.row, tt.prop)">{{
scope.row[tt.prop]
}}</span>
</template>
<template v-else-if="tt.scopeType == 'checkBox'">
<el-checkbox
v-model="scope.row[tt.prop]"
@change="checkChange(scope.row, tt.prop)"
></el-checkbox>
</template>
<template v-else-if="tt.scopeType == 'selectBox'">
<el-select v-model="scope.row[tt.prop]" placeholder="请选择">
<el-option
v-for="item in subprojectContainsTypeS"
:key="item.value"
:label="item.label"
:value="item.value"
@click.native="selectClick(item, scope.row, tt.prop)"
>
</el-option>
</el-select>
</template>
<template v-else-if="tt.scopeType == 'operation'">
<template v-if="tt.operationContent.type == 'button'">
<el-button
v-for="btn in tt.operationContent.content"
:key="btn.id"
type="primary"
@click="btnClick(scope.row, btn.type)"
>{{ btn.title }}</el-button
>
</template>
</template>
<template v-else>
{{ scope.row[tt.prop] }}
</template>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "multi_table",
data() {
return {
tableData: [
{
SN: 1,
projectType: "配置项顶级软件",
softType: "非嵌入",
developmentType: "一类",
lifeCycleType: "一类模型",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 2,
projectType: "配置项顶级软件",
softType: "非嵌入",
developmentType: "二类",
lifeCycleType: "二类模型",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 3,
projectType: "配置项顶级软件",
softType: "非嵌入",
developmentType: "三类",
lifeCycleType: "三类模型",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 4,
projectType: "配置项顶级软件",
softType: "非嵌入",
developmentType: "四类",
lifeCycleType: "四类瀑布",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 5,
projectType: "配置项顶级软件",
softType: "非嵌入",
developmentType: "四类",
lifeCycleType: "四类迭代",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 6,
projectType: "配置项顶级软件",
softType: "应用软件",
developmentType: "一类",
lifeCycleType: "一类模型",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 7,
projectType: "配置项顶级软件",
softType: "应用软件",
developmentType: "二类",
lifeCycleType: "二类模型",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
{
SN: 8,
projectType: "配置项顶级软件",
softType: "应用软件",
developmentType: "三类",
lifeCycleType: "三类模型",
changeIsRequired: false,
changeIsShow: false,
subprojectContainsType: "",
isMustIncludeConfigurationItems: false,
isIncludeDevelopmentPlan: false,
},
],
tableTitle: [
{
title: "序号",
type: "index",
width: "50",
prop: "SN",
align: "center",
},
{
title: "项目类别",
prop: "projectType",
align: "left",
showoverflowtooltip: true,
scopeType: "spanClick",
},
{
title: "软件类型",
prop: "softType",
align: "left",
showoverflowtooltip: true,
scopeType: "spanClick",
},
{
title: "研制类型",
prop: "developmentType",
align: "center",
showoverflowtooltip: true,
scopeType: "spanClick",
},
{
title: "生命周期类型",
prop: "lifeCycleType",
align: "center",
showoverflowtooltip: true,
scopeType: "spanClick",
},
{
title: "更改规模是否必填",
prop: "changeIsRequired",
align: "center",
scopeType: "checkBox",
},
{
title: "更改规模是否显示",
prop: "changeIsShow",
align: "center",
scopeType: "checkBox",
},
{
title: "子项目包含类型",
prop: "subprojectContainsType",
align: "center",
scopeType: "selectBox",
},
{
title: "是否必须包含配置项",
prop: "isMustIncludeConfigurationItems",
align: "center",
scopeType: "checkBox",
},
{
title: "是否包含开发计划",
prop: "isIncludeDevelopmentPlan",
align: "center",
scopeType: "checkBox",
},
{
title: "操作",
prop: "operation",
align: "center",
scopeType: "operation",
operationContent: {
type: "button",
content: [{ title: "移除", type: "del", id: "delBtn" }],
},
},
],
subprojectContainsTypeS: [
{
value: "A",
label: "A",
},
{
value: "B",
label: "B",
},
{
value: "C",
label: "C",
},
{
value: "D",
label: "D",
},
{
value: "E",
label: "E",
},
],
needMergeArr: [
"projectType",
"softType",
"developmentType",
"lifeCycleType",
"subprojectContainsType",
"isMustIncludeConfigurationItems",
"isIncludeDevelopmentPlan",
], //需要进行合并的column的prop值
rowMergeArrs: {}, //处理过后得到的每个column的合并规则
};
},
created() {
this.rowMergeArrs = this.rowMergeHandle(this.needMergeArr, this.tableData); // 处理数据
},
methods: {
rowMergeHandle(needMergeArr, tableData) {
if (!Array.isArray(needMergeArr) && !needMergeArr.length) return false;
if (!Array.isArray(tableData) && !tableData.length) return false;
let needMerge = {};
needMergeArr.forEach((i) => {
needMerge[i] = {
rowArr: [], //该数组用来记录在目前列中的每一行的cell应该向下合并几行还是应该被合并。如果对应数组的数据==0,则说明该cell应该被合并。
rowMergeNum: 0, //用来记录在目前列的第几行的行数,rowNum
};
tableData.forEach((item, index) => {
if (index === 0) {
needMerge[i].rowArr.push(1);
needMerge[i].rowMergeNum = 0;
} else {
if (item[i] === tableData[index - 1][i]) {
needMerge[i].rowArr[needMerge[i].rowMergeNum] += 1;
needMerge[i].rowArr.push(0);
} else {
needMerge[i].rowArr.push(1);
needMerge[i].rowMergeNum = index;
}
}
});
});
return needMerge;
},
arraySpanMethod({ column, rowIndex }) {
// console.log("arraySpanMethod", row, column, rowIndex, columnIndex);
if (column.property === "projectType") {
return this.mergeAction("projectType", rowIndex, column);
} else if (column.property === "softType") {
return this.mergeAction("softType", rowIndex, column);
} else if (column.property === "developmentType") {
return this.mergeAction("developmentType", rowIndex, column);
} else if (column.property === "lifeCycleType") {
return this.mergeAction("lifeCycleType", rowIndex, column);
} else if (column.property === "subprojectContainsType") {
return this.mergeAction("projectType", rowIndex, column);
} else if (column.property === "isMustIncludeConfigurationItems") {
return this.mergeAction("projectType", rowIndex, column);
} else if (column.property === "isIncludeDevelopmentPlan") {
return this.mergeAction("projectType", rowIndex, column);
}
},
mergeAction(val, rowIndex) {
let _row = this.rowMergeArrs[val].rowArr[rowIndex];
let _col = _row > 0 ? 1 : 0;
return [_row, _col];
},
spanClick(row, prop) {
console.log("spanClick row prop", row, prop);
},
checkChange(row, prop) {
console.log("checkChange row prop", row, prop);
},
selectClick(item, row, prop) {
console.log("selectClick item,row,prop", item, row, prop);
},
btnClick(row, type) {
console.log("btnClick row type", row, type);
},
},
};
</script>
<style></style>
- 首先,虽然表格的样式是树状结构,但是建议数据采取普通的表格数据结构,如果后台返回的数据是树状的,反而不好处理。
- 处理tableData的方法就是,把你要进行合并的column遍历出来,然后根据他们展示数据如果相同,就让他们进行合并,然后获取到整个表格所有column的合并处理方式的数据,然后再el-table的处理col和row合并的方法span-method中对row和col进行相应的处理即可。