介绍
因为最近项目中遇到合并表格行的需求,所以用这篇文章记录下实现思路。
看下实现效果:

实现逻辑
element plus 实现 table 的合并行或者列需要实现 span-method 方法。 官网地址element-plus-table。
案例中的代码是实现行的合并,假设接口返回的数据是嵌套的模式,父级就是需要合并的列表,内层的数据长度就是需要合并的行数。当然如果嵌套的层次比较深,就需要遍历内层的数量统计最外层需要合并的数量。
案例代码是三层的结构,使用简单的嵌套循环,一般项目中也够用了,更多层级的数据结构也是一样的道理,多加n 次循环,此时建议使用递归来实现了。
代码实现
vue
<script setup>
import { ref } from "vue";
// 模拟数据
const testData = [
{
fromMajorCity: 'BFN',
data: [
{
level: 1,
toMajorCity: 'BFN,CPT',
data: [
{
weightGt: 0,
weightLte: 15,
basic_weight: 5,
starting_price: 10,
thereafter_price: 4,
per_nkg: 1
},
{
weightGt: 15,
weightLte: null,
basic_weight: 5,
starting_price: 9.5,
thereafter_price: 4,
per_nkg: 1
}
]
},
{
level: 2,
toMajorCity: 'DUR,ELS,KIM,WLK.Other',
data: [
{
weightGt: 0,
weightLte: null,
basic_weight: 5,
starting_price: 10,
thereafter_price: 5,
per_nkg: 1
}
]
}
]
}
]
// 扁平化数据并且计算合并行的 rowspan
const flattenDataWithRowspan = (nestData) => {
const flatData = []
nestData.forEach((row) => {
let firstRowSpan = 0 // 最外层合并行数
row.data?.forEach((item) => {
const secondRowSpan = item.data.length // 第二层合并行数
item.secondRowSpan = secondRowSpan
firstRowSpan += secondRowSpan
})
row.firstRowSpan = firstRowSpan
})
nestData.forEach((row) => {
row.data?.forEach((item, i) => {
item.data?.forEach((val, index) => {
flatData.push({
fromMajorCity: row.fromMajorCity,
level: item.level,
toMajorCity: item.toMajorCity,
...val,
firstRowSpan: (index === 0 && i == 0) ? row.firstRowSpan : 0,
secondRowSpan: index === 0 ? item.secondRowSpan : 0,
})
})
})
})
return flatData
}
// 合并行的方法
function spanMethod({ row, columnIndex, column }) {
if (column.label === 'From Major City' || column.label === 'No' || column.label === 'Action') {
// 如果有值需要合并
if (row.firstRowSpan > 0) {
return {
rowspan: row.firstRowSpan,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
if (column.label === 'Level' || column.label === 'To Major City') {
// 如果有值需要合并
if (row.secondRowSpan > 0) {
return {
rowspan: row.secondRowSpan,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
const tableData = ref(flattenDataWithRowspan(testData))
</script>
<template>
<div>
<el-table :data="tableData" :span-method="spanMethod" border>
<el-table-column label="No" type="index" width="55" align="center"></el-table-column>
<el-table-column label="From Major City" prop="fromMajorCity" width="200" align="center"></el-table-column>
<el-table-column label="Level" prop="level" width="100" align="center"></el-table-column>
<el-table-column label="To Major City" prop="toMajorCity" width="200" align="center"></el-table-column>
<el-table-column label="Weight (>)" prop="weightGt" width="150" align="center"></el-table-column>
<el-table-column label="Weight (<=)" prop="weightLte" width="150" align="center"></el-table-column>
<el-table-column label="Basic Weight (kg)" prop="basic_weight" width="150" align="center"></el-table-column>
<el-table-column label="Starting Price" prop="starting_price" width="150" align="center"></el-table-column>
<el-table-column label="Thereafter Price" prop="thereafter_price" width="150" align="center"></el-table-column>
<el-table-column label="per N Kg" prop="perNkg" width="150" align="center"></el-table-column>
<el-table-column label="Action" width="200" align="center" fixed="right">
<template #default>
<el-button type="primary">Edit</el-button>
<el-button type="primary">Copy</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<style scoped></style>