1、前言
为什么要使用这种通用合并方案?
是不是每次用Element Plus/Element UI 的表格时总是默认是 “一行一条数据”,但是有的时候实际业务中经常需要 “主数据 + 子数据” 嵌套展示,而且还要绑定对应的数据,显得特别冗余麻烦,如果有一个工具函数直接合并就好了,每次只需要直接传合并哪几列,那么整个开发起来套用多个表就很轻松,而且封装起来后面维护只需要修改 这个工具函数就好了
2、实现效果
3、函数详细说明
参数说明
/**
* 通用表格单元格合并工具函数
* 适用场景:主数据包含多个子数据,表格中主数据字段需要跨行合并(如员工+生命周期、订单+订单项)
* @param {Object} params - 合并参数
* @param {any} params.currentRow - 当前行数据(表格行数据)
* @param {number} params.columnIndex - 当前列索引
* @param {number} params.rowIndex - 当前行索引
* @param {any[]} params.originData - 原始主数据列表(如员工列表,每个项包含子数据数组)
* @param {any[]} params.tableData - 格式化后的表格数据列表(子数据平铺后的列表)
* @param {number[]} params.mergeColumnIndexes - 需要合并的列索引数组
* @param {string} params.mainKey - 主数据唯一标识字段(如员工的realName、订单的orderNo)
* @param {string} params.childrenKey - 主数据中子数据数组的字段名(如lifeList、orderItems)
* @param {string} params.childUniqueKey - 子数据的唯一标识字段(如cycleId、itemId)
* @returns {Object} { rowspan: 合并行数, colspan: 合并列数 }
*/
合并函数工具代码
实现逻辑
代码实现
export const useTableSpanMerge =
({
currentRow,
columnIndex,
rowIndex,
originData,
tableData,
mergeColumnIndexes,
mainKey = 'id',
childrenKey = 'children',
childUniqueKey = 'id'
}: {
currentRow: any;
columnIndex: number;
rowIndex: number;
originData: any[];
tableData: any[];
mergeColumnIndexes: number[];
mainKey?: string;
childrenKey?: string;
childUniqueKey?: string;
}) => {
//非合并列直接返回默认值
if (!mergeColumnIndexes.includes(columnIndex)) {
return { rowspan: 1, colspan: 1 };
}
try {
// 根据主数据唯一标识找到原始主数据项
const mainKeyValue = currentRow[mainKey];
const currentMainItem = originData.find(item => item[mainKey] === mainKeyValue);
if (!currentMainItem) {
return { rowspan: 1, colspan: 1 };
}
// 获取主数据项下的子数据数量(即合并行数)
const childrenList = currentMainItem[childrenKey] || [];
const mergeRowCount = childrenList.length || 1;
// 找到该主数据项下第一条子数据在表格中的索引
const firstChildItem = childrenList[0];
const firstChildKey = firstChildItem ? firstChildItem[childUniqueKey] : '';
const firstRowIndex = tableData.findIndex(item =>
item[mainKey] === mainKeyValue && item[childUniqueKey] === firstChildKey
);
// 核心合并逻辑:第一条行显示并合并,其他行隐藏
if (rowIndex === firstRowIndex) {
return {
rowspan: mergeRowCount,
colspan: 1
};
} else {
return {
rowspan: 0,
colspan: 0
};
}
} catch (error) {
console.error('表格单元格合并失败:', error);
return { rowspan: 1, colspan: 1 }; // 异常兜底,避免表格渲染崩溃
}
};
4、在页面中使用通用函数
这里以员工列表为例,一个员工可能从实习生->软件开发工程师->中级软件开发工程师->高级软件开发工程师四个阶段,那么这个员工的基础信息就要合并成一行,对应的职位信息为四行
那么我们在Element Plus的组件中直接使用就可以啦
vue
<template>
<el-table
v-loading="loading"
:data="tableData"
border
style="width: 100%;"
:span-method="handleTableSpanMethod" <!-- 绑定业务处理函数 -->
:header-cell-style="{ background: '#f5f7fa', fontWeight: 'bold' }"
fit
:cell-style="{ textAlign: 'center' }"
>
<!-- 表格列定义不变 -->
</el-table>
</template>
javascript
<script setup lang="ts">
import { useTableSpanMerge } from '@/utils/tableSpanHelper'; // 引入通用工具函数
// 业务层表格合并处理函数(传递参数)
const handleTableSpanMethod = ({ row, columnIndex, rowIndex }: {
row: any;
columnIndex: number;
rowIndex: number;
}) => {
// 调用通用合并函数,传入员工列表的业务参数
return useTableSpanMerge({
currentRow: row, // 当前行数据
columnIndex: columnIndex, // 当前列索引
rowIndex: rowIndex, // 当前行索引
originData: originData.value, // 原始员工列表(主数据)
tableData: tableData.value, // 格式化后的表格数据(子数据平铺)
mergeColumnIndexes: [0, 1, 2, 3, 8], // 需要合并的列索引(工号/姓名/状态/部门/操作)
mainKey: 'realName', // 主数据唯一标识(员工姓名)
childrenKey: 'lifeList', // 子数据数组字段(生命周期列表)
childUniqueKey: 'cycleId' // 子数据唯一标识(生命周期ID)
});
};
</script>