今天遇到这样一个问题,后端给一个一维数组,前端将数据展示在Element Plus的table组件中,要求要合并相同内容的单元格,自己觉得很难不会做。
在csdn上找到了答案,直接先拿来急用了,后续再去仔细琢磨 原帖子传送门blog.csdn.net/weixin_4820…
跳过基础部分直接来难点
Vue3 + Element Plus 创建动态多级表头
多级表头的实现比较简单,主要是通过 el-table-column 的嵌套来完成的,在 components 目录下新建 MultiHeaderTable.vue 文件:
<template>
<div>
<h2>Vue3 + Element plus 动态表格</h2>
<el-table :data="tableData" style="width: 100%">
<el-table-column
:prop="item.prop"
:label="item.label"
v-for="(item, index) in tableHeader"
:key="index"
>
<el-table-column
:prop="child.prop"
:label="child.label"
v-for="(child, childIndex) in item.children"
:key="childIndex"
></el-table-column>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "MultiHeaderTable",
data() {
return {
tableHeader: [
{
prop: "name",
label: "姓名",
},
{
prop: "birth",
label: "生日",
},
{
prop: "phone",
label: "电话",
},
{
label: "地址",
children: [
{
prop: "province",
label: "省份",
},
{
prop: "city",
label: "市区",
},
{
prop: "address",
label: "详细地址",
}
]
}
],
tableData: [{
name: '张三',
province: "上海市",
city: "普陀区",
address: "金沙江路 1518 弄",
birth: '2016-05-02',
phone: "12345678910",
}, {
name: '李四',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1517 弄',
age: 19,
phone: "12345678911",
}, {
name: '王五',
birth: '2016-05-01',
province: "上海市",
city: "普陀区",
address: '金沙江路 1519 弄',
phone: "12345678912",
}, {
name: '赵六',
birth: '2016-05-03',
province: "上海市",
city: "普陀区",
address: '金沙江路 1516 弄',
phone: "12345678913",
}]
}
},
}
</script>
Vue3 + Element Plus 表格中单元格行合并
我们的需求是把相同 birth 进行合并。在 components 目录下新建 RowMergeTable.vue 文件:
<template>
<div>
<h2>Vue3 + Element plus 动态行合并表格</h2>
<el-table
:data="tableData"
style="width: 100%"
:span-method="objectSpanMethod"
border
>
<el-table-column
:prop="item.prop"
:label="item.label"
v-for="(item, index) in tableHeader"
:key="index"
></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "RowMergeTable",
data() {
this.spanArr = [];
return {
tableHeader: [
{
prop: "birth",
label: "生日",
},
{
prop: "name",
label: "姓名",
},
{
prop: "phone",
label: "电话",
},
{
prop: "province",
label: "省份",
},
{
prop: "city",
label: "市区",
},
{
prop: "address",
label: "详细地址",
}
],
tableData: [{
name: '张三',
province: "上海市",
city: "普陀区",
address: "金沙江路 1518 弄",
birth: '2016-05-02',
phone: "12345678910",
}, {
name: '李四',
birth: '2016-05-02',
province: "上海市",
city: "普陀区",
address: '金沙江路 1517 弄',
age: 19,
phone: "12345678911",
}, {
name: '王五',
birth: '2016-05-03',
province: "上海市",
city: "普陀区",
address: '金沙江路 1519 弄',
phone: "12345678912",
}, {
name: '赵六',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1520 弄',
phone: "12345678913",
}, {
name: '孙七',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1521 弄',
phone: "12345678913",
}, {
name: '周八',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1522 弄',
phone: "12345678913",
}, {
name: '吴九',
birth: '2016-05-06',
province: "上海市",
city: "普陀区",
address: '金沙江路 1523 弄',
phone: "12345678913",
}]
}
},
created() {
this.getSpanArr(this.tableData);
},
methods: {
getSpanArr(data) {
for (var i = 0; i < data.length; i++) {
if (i === 0) {
this.spanArr.push(1);
this.pos = 0
} else {
if (data[i].birth === data[i - 1].birth) {
this.spanArr[this.pos] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.pos = i;
}
}
}
},
objectSpanMethod({ rowIndex, columnIndex }) {
if (columnIndex === 0) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col
}
}
}
}
}
</script>
因为表格的数据是动态的,所以我们需要事先通过计算,来得知哪些行是需要合并的,这里就是通过 getSpanArr 方法来实现的,全局维护了一个 spanArr 变量,用于记录每一行需要合并的数字,pos 是 spanArr 的索引,这样就可以根据索引来动态设置需要合并的行树。当 i === 0,说明是第一行数据,向 spanArr 数组中 push 1,当 i !== 0,此时就需要比较当前行与前一行数据的 birth 是否相等,如果相等,则利用索引,修改当前行需要合并的行数。
objectSpanMethod 方法,在 el-table 渲染每一行数据的时候都会执行,这样就可以通过 rowIndex 来获取每一行需要合并的行数信息,来实现行合并的功能。
那么如何实现多行合并?其实也是一样的思路,通过 spanMap 可以存储多个列的行合并信息。在 components 下新建 MultiRowMergeTable.vue:
<template>
<div>
<h2>Vue3 + Element plus 动态多行合并表格</h2>
<el-table
:data="tableData"
style="width: 100%"
:span-method="objectSpanMethod"
border
>
<el-table-column
:prop="item.prop"
:label="item.label"
v-for="(item, index) in tableHeader"
:key="index"
></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "MultiRowMergeTable",
data() {
this.spanMap = {};
this.mergedColumns = ["birth", "province", "city"]
return {
tableHeader: [
{
prop: "birth",
label: "生日",
},
{
prop: "name",
label: "姓名",
},
{
prop: "phone",
label: "电话",
},
{
prop: "province",
label: "省份",
},
{
prop: "city",
label: "市区",
},
{
prop: "address",
label: "详细地址",
}
],
tableData: [{
name: '张三',
province: "上海市",
city: "普陀区",
address: "金沙江路 1518 弄",
birth: '2016-05-02',
phone: "12345678910",
}, {
name: '李四',
birth: '2016-05-02',
province: "上海市",
city: "普陀区",
address: '金沙江路 1517 弄',
age: 19,
phone: "12345678911",
}, {
name: '王五',
birth: '2016-05-03',
province: "上海市",
city: "普陀区",
address: '金沙江路 1519 弄',
phone: "12345678912",
}, {
name: '赵六',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1520 弄',
phone: "12345678913",
}, {
name: '孙七',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1521 弄',
phone: "12345678913",
}, {
name: '周八',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1522 弄',
phone: "12345678913",
}, {
name: '吴九',
birth: '2016-05-06',
province: "上海市",
city: "普陀区",
address: '金沙江路 1523 弄',
phone: "12345678913",
}]
}
},
created() {
this.getSpanArr(this.tableData);
},
methods: {
getSpanArr(data) {
for (var i = 0; i < data.length; i++) {
if (i === 0) {
this.mergedColumns.forEach(column => {
this.spanMap[column] = {
spanArr: [1],
pos: 0
}
})
} else {
this.mergedColumns.forEach(column => {
if (data[i][column] === data[i - 1][column]) {
this.spanMap[column].spanArr[this.spanMap[column].pos] += 1;
this.spanMap[column].spanArr.push(0)
} else {
this.spanMap[column].spanArr.push(1);
this.spanMap[column].pos = i;
}
})
}
}
},
objectSpanMethod({ column, rowIndex }) {
if (this.spanMap[column.property]) {
const _row = this.spanMap[column.property].spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col
}
}
}
}
}
</script>
Vue3 + Element Plus 表格中单元格列合并
接下来,我们来看下如何实现列的合并,其实思路是和行合并类似的,也需要用到 span-method 这个方法,唯一不同的在于,列合并需要处理被合并列的原始数据,否则被合并列的原始数据会填充到合并之后的表格里,这样说可能有点抽象,我们写来写一个例子,在 components 下新建 ColumnMergeTable.vue:
<template>
<div>
<h2>Vue3 + Element plus 动态表格列合并</h2>
<el-table
:data="tableData"
style="width: 100%"
:span-method="objectSpanMethod"
border
>
<el-table-column
:prop="item.prop"
:label="item.label"
v-for="(item, index) in tableHeader"
:key="index"
></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: "ColumnMergeTable",
data() {
return {
tableHeader: [
{
prop: "birth",
label: "生日",
},
{
prop: "name",
label: "姓名",
},
{
prop: "phone",
label: "电话",
},
{
prop: "province",
label: "省份",
},
{
prop: "city",
label: "市区",
},
{
prop: "address",
label: "详细地址",
}
],
tableData: [{
name: '张三',
province: "上海市",
city: "普陀区",
address: "金沙江路 1518 弄",
birth: '2016-05-02',
phone: "12345678910",
}, {
name: '李四',
birth: '2016-05-02',
province: "上海市",
city: "普陀区",
address: '金沙江路 1517 弄',
age: 19,
phone: "12345678911",
}, {
name: '王五',
birth: '2016-05-03',
province: "上海市",
city: "普陀区",
address: '金沙江路 1519 弄',
phone: "12345678912",
}, {
name: '赵六',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1520 弄',
phone: "12345678913",
}, {
name: '孙七',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1521 弄',
phone: "12345678913",
}, {
name: '周八',
birth: '2016-05-04',
province: "上海市",
city: "普陀区",
address: '金沙江路 1522 弄',
phone: "12345678913",
}, {
name: '吴九',
birth: '2016-05-06',
province: "上海市",
city: "普陀区",
address: '金沙江路 1523 弄',
phone: "12345678913",
}]
}
},
methods: {
objectSpanMethod({ rowIndex, columnIndex }) {
// 隐藏第二行或者第三行的列
if (rowIndex === 1 || rowIndex === 2) {
// 合并第二行
if (columnIndex === 1) {
// 从第二列开始
return [1, 3]
//或者返回如下形式也可以
// return {
// rowspan: 1,
// colspan: 3
// }
// 这里的 else if 即使用来处理被合并列的原始数据的情况,需要隐藏原始单元格
} else if (columnIndex === 2 || columnIndex === 3) {
return [0, 0]
}
}
}
}
}
</script>
再次感谢原作者 版权声明:本文为CSDN博主「蒋川_卡拉云」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:blog.csdn.net/weixin_4820…