白筱汐

想都是问题,做都是答案

0%

element plus 根据嵌套数据合并表格

介绍

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

看下实现效果:

合并单元格

实现逻辑

element plus 实现 table 的合并行或者列需要实现 span-method 方法。 官网地址element-plus-table

案例中的代码是实现行的合并,假设接口返回的数据是嵌套的模式,父级就是需要合并的列表,内层的数据长度就是需要合并的行数。当然如果嵌套的层次比较深,就需要遍历内层的数量统计最外层需要合并的数量。

案例代码是三层的结构,使用简单的嵌套循环,一般项目中也够用了,更多层级的数据结构也是一样的道理,多加n 次循环,此时建议使用递归来实现了。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<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>