最近一个需求涉及表格的动态合并,写完之后在这里记录一下实现过程,有需要的可以参考一下
大致效果图
主要的实现逻辑就是根据后端返回的数据中的唯一ID进行动态计算合并
1、可以通过比对上下数据是否相同来进行合并,所以首先需要把后端返回的数据进行处理。
示例
// 后端返回数据
const a = [
{
id: 1,
country: '美国',
address: '洛杉矶',
work: '销售',
height: '180cm',
children: [
{ name: '李四', age: 18, cid: 1 },
{ name: '王五', age: 18, cid: 2 }
]
},
{
id: 2,
country: '英国',
address: '伦敦',
work: '收银',
children: [
{ name: '赵六', age: 18, cid: 3 },
]
},
]
//需要处理成的数据格式
const b = [
{ id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '李四', age: 18, cid: 1 },
{ id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '王五', age: 18, cid: 2 },
{ id: 2, country: '英国', address: '伦敦', work: '收银', name: '赵六', age: 18, cid: 3 },
]
//cid用于给表格添加row-key 所以cid必须是唯一值不能重复
这样就会根据比对上下两条数据是否相同来进行合并
合并主要是通过el-table的span-method方法进行合并
<template>
<div>
<el-table
row-key="cid"
border
:data="tableData"
:span-method="mergeCellsMethod"
highlight-current-row
>
<el-table-column prop="country" label="国家"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column prop="work" label="工作"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="age" label="年龄"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{ id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '李四', age: 18, cid: 1 },
{ id: 1, country: '美国', address: '洛杉矶', work: '销售', name: '王五', age: 18, cid: 2 },
{ id: 2, country: '英国', address: '伦敦', work: '收银', name: '赵六', age: 18, cid: 3 }
]
}
},
methods: {
mergeCellsMethod({ row, column, rowIndex }) {
// 根据行id进行合并,这样不会导致上下数据相同但id不同时会合并错误的问题
switch (column.property) {
case 'country':
return this.setTableRowCol(row, rowIndex, ['id', 'country'])
case 'address':
return this.setTableRowCol(row, rowIndex, ['id', 'address'])
case 'work':
return this.setTableRowCol(row, rowIndex, ['id', 'work'])
default:
break
}
},
setTableRowCol(row, rowIndex, keys) {
let firstIndex = 0
let rowspan = 1
let colspan = 1
// 找到需要合并的行的下标
firstIndex = this.tableData.findIndex((item) => {
return this.filterSameKeys(item, row, keys)
})
if (rowIndex === firstIndex) {
// 需要合并的行数
rowspan = this.tableData.filter((item) => {
return this.filterSameKeys(item, row, keys)
}).length
colspan = 1
} else {
// 被合并的行需要设置成0
rowspan = 0
colspan = 0
}
return {
rowspan,
colspan
}
},
// 根据keys数组所有字段去做合并
filterSameKeys(item, row, keys) {
let flag = true
keys.forEach((key) => {
flag = flag && item[key] === row[key]
})
return flag
}
}
}
</script>
以下是上述代码运行后的结果
也可以这样
只需要在
mergeCellsMethod方法中根据字段名去匹配即可
2、但是在上图可以看到合并之后hover的样式不是我们预想的效果
我们可以通过cell-mouse-enter和cell-mouse-leave事件以及row-class-name方法来解决
// methods
// 鼠标移入
cellMouseEnter(row) {
//currentIndex在data中定义,我这里就不写了
this.currentIndex = row.id
},
// 鼠标移出
cellMouseLeave() {
this.currentIndex = ''
},
// 设置行class
tableRowClassName({ row }) {
let flag = row.id === this.currentIndex
return flag ? 'table-hover-row' : ''
}
//style
// 注意!!!!处理hover样式不加scoped才能生效
<style lang="scss">
.el-table .table-hover-row {
background: #e0f3ff !important;
}
.el-table tbody tr:hover > td {
background-color: #e0f3ff !important;
}
</style>
这样hover样式就解决了 如果是点击高亮有问题则同理使用
row-click事件给currentIndex赋值即可。
先写到这,如果有问题就发在评论区或者私信我