前言
在开发的过程中遇见一个需求,就是要求合并行。UI设计的效果图如下
大致需求就是, 1.将订单号、创建人、创建日期和操作列合并; 2.将父订单号合并。只是他们合并的逻辑不一样,前者这需要判断订单号一样就合并,而后者需要判断父订单号一样且订单号也一样时才合并。
这个需求倒是没有什么难度,项目用的是 vue3 + element Plus组件库开发的,所以我就去element官网逛了逛。链接如下,感兴趣的大佬可以自行跳转过去看看。
https://element-plus.org/zh-CN/component/table#%E5%90%88%E5%B9%B6%E8%A1%8C%E6%88%96%E5%88%97
el-table组件的 span-method 属性,接受一个函数, 用来计算合并行或列的方法。该方法有四个参数 row: any, column: any, rowIndex: number, columnIndex: number
以数组形式返回
const arraySpanMethod = ({
row,
column,
rowIndex,
columnIndex,
}: SpanMethodProps) => {
if (rowIndex % 2 === 0) {
if (columnIndex === 0) {
return [1, 2]
} else if (columnIndex === 1) {
return [0, 0]
}
}
}
以对象形式返回
const objectSpanMethod = ({
row,
column,
rowIndex,
columnIndex,
}: SpanMethodProps) => {
if (columnIndex === 0) {
if (rowIndex % 2 === 0) {
return {
rowspan: 2,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
但是,官网的例子比较简单,合并逻辑还是得根据自己的需求写业务逻辑。
这里提供两种实现方式,实现逻辑有所区别,第一种是在合并方法里面写合并逻辑,第二种获取数据过后,将需要合并的数据先处理,在合并方法里面直接用处理好的数据。这里更推荐第二种,因为性能更好些。
代码实现
第一种实现方式(直接在合并方法里面些合并逻辑)
function spanMethod1({ row, column, rowIndex, columnIndex }) {
// 合并的列,从0开始。这里是合并1、4、5、6列
if ([1, 4, 5, 6].includes(columnIndex)) {
console.log("进入打印")
if (
rowIndex === 0 || (
rowIndex > 0 &&
row.orderNo !== tableData.value[rowIndex - 1].orderNo
)) {
let rowspan = 1;
for (let i = rowIndex + 1; i < tableData.value.length; i++) {
console.log("循环打印")
if (row.orderNo === tableData.value[i].orderNo) {
rowspan++;
} else {
break;
}
}
return [rowspan, 1];
} else {
return [0, 0];
}
}
}
这样的缺点是,只要页面大小发生变化,都会触发合并方法,对性能不友好。
Video_2025-03-02_131438
接下来是第二种(提前计算好合并逻辑,直接使用)
function spanMethod({ row, column, rowIndex, columnIndex }) {
if ([1, 4, 5, 6].includes(columnIndex)) {
console.log("进入打印")
let rowSpan = mergeInfo.value.orderNos[rowIndex];
const colSpan = rowSpan > 0 ? 1 : 0;
return [rowSpan, colSpan];
}
if (columnIndex === 2) {
let rowSpan = mergeInfo.value.children[rowIndex];
const colSpan = rowSpan > 0 ? 1 : 0;
return [rowSpan, colSpan];
}
}
function handleMergeData() {
let orderNoIndex = 0;
let childrenIndex = 0;
tableData.value.forEach((item, index) => {
if (index === 0) {
mergeInfo.value.orderNos.push(1);
mergeInfo.value.children.push(1);
orderNoIndex = 0;
childrenIndex = 0;
} else {
if (item.orderNo === tableData.value[index - 1].orderNo) {
mergeInfo.value.orderNos[orderNoIndex] += 1;
mergeInfo.value.orderNos.push(0);
} else {
mergeInfo.value.orderNos.push(1);
orderNoIndex = index;
}
if (item.orderNo === tableData.value[index - 1].orderNo &&
item.parentOrderNo === tableData.value[index - 1].parentOrderNo
) {
mergeInfo.value.children[childrenIndex] += 1;
mergeInfo.value.children.push(0);
} else {
mergeInfo.value.children.push(1);
childrenIndex = index;
}
}
});
}
Video_2025-03-02_132800
从视频中可以直观的看出来,后者比前者性能更好些,每次渲染不用再次进行计算合并逻辑。