在后台管理系统中,el-table 展示分组数据时经常需要合并单元格。Element UI 提供的 span-method 可以把“哪些单元格合并、哪些单元格隐藏”变成可计算的规则。本文围绕它的参数、返回值、固定合并、按数据动态合并以及常见问题展开,代码基于原文示例整理。
一、span-method 的调用机制
span-method 是 el-table 的函数属性。表格渲染每个单元格时会调用该方法,由它返回当前单元格的合并规则。方法接收一个对象参数,包含 row、column、rowIndex、columnIndex:row 是当前行数据,column 是当前列配置,rowIndex 和 columnIndex 都从 0 开始。
返回值可以是 { rowspan, colspan },也可以是数组 [rowspan, colspan]。含义如下:
1. rowspan > 1 或 colspan > 1:当前单元格作为合并区域的左上角,显示内容。
2. rowspan = 0 或 colspan = 0:当前单元格被合并隐藏,不显示内容,也不占位置。
3. rowspan = 1、colspan = 1:默认值,不合并,正常显示。
关键点是:合并区域只有返回 rowspan > 1 或 colspan > 1 的那个单元格会显示内容,其他返回 0 的单元格全部隐藏。理解这一点,后续的动态合并才不会出现重复内容或错位。
二、基础用法:固定规则合并第一列
下面示例把员工数据按每两行合并第一列。模板中给 el-table 绑定 span-method,表格列为序号、姓名、部门。
- <template>
- <el-table :data="tableData" :span-method="objectSpanMethod" border>
- <el-table-column prop="id" label="序号" width="80"></el-table-column>
- <el-table-column prop="name" label="姓名"></el-table-column>
- <el-table-column prop="department" label="部门"></el-table-column>
- </el-table>
- </template>
- <script>
- export default {
- data() {
- return {
- tableData: [
- { id: 1, name: '张三', department: '技术部' },
- { id: 2, name: '李四', department: '技术部' },
- { id: 3, name: '王五', department: '产品部' },
- { id: 4, name: '赵六', department: '产品部' }
- ]
- }
- },
- methods: {
- objectSpanMethod({ row, column, rowIndex, columnIndex }) {
- if (columnIndex === 0) {
- if (rowIndex % 2 === 0) {
- return { rowspan: 2, colspan: 1 }
- } else {
- return { rowspan: 0, colspan: 0 }
- }
- }
- }
- }
- }
- </script>
复制代码
这段代码只处理 columnIndex === 0 的第一列。偶数行索引 0、2、4 作为合并起点,返回 rowspan: 2;奇数行返回 rowspan: 0、colspan: 0,被隐藏。其他列没有返回值,按默认方式每行独立显示。
三、按数据内容动态合并
实际业务中,合并行数通常由数据内容决定。例如按部门合并部门列,相同部门只显示一次,姓名和薪资仍然逐行显示。
核心思路分为两步:预处理阶段遍历原始数据,计算每一行在目标列需要占用的行数,存入辅助数组 spanArr;应用阶段在 span-method 中根据 columnIndex 和 rowIndex 读取 spanArr,生成合并规则。
- <template>
- <el-table :data="tableData" :span-method="objectSpanMethod" border>
- <el-table-column prop="department" label="部门" width="120"></el-table-column>
- <el-table-column prop="name" label="姓名"></el-table-column>
- <el-table-column prop="salary" label="薪资(元)"></el-table-column>
- </el-table>
- </template>
- <script>
- export default {
- data() {
- return {
- tableData: [
- { department: '技术部', name: '张三', salary: 10000 },
- { department: '技术部', name: '李四', salary: 12000 },
- { department: '技术部', name: '王五', salary: 11000 },
- { department: '产品部', name: '赵六', salary: 15000 },
- { department: '产品部', name: '孙七', salary: 14000 },
- { department: '人事部', name: '周八', salary: 9000 }
- ],
- spanArr: []
- }
- },
- created() {
- this.getSpanArr(this.tableData)
- },
- methods: {
- getSpanArr(data) {
- this.spanArr = []
- for (let i = 0; i < data.length; i++) {
- if (i === 0) {
- this.spanArr.push(1)
- this.pos = 0
- } else {
- if (data[i].department === data[i - 1].department) {
- this.spanArr[this.pos] += 1
- this.spanArr.push(0)
- } else {
- this.spanArr.push(1)
- this.pos = i
- }
- }
- }
- },
- objectSpanMethod({ columnIndex, rowIndex }) {
- if (columnIndex === 0) {
- const rowspan = this.spanArr[rowIndex]
- if (rowspan > 0) {
- return { rowspan: rowspan, colspan: 1 }
- } else {
- return { rowspan: 0, colspan: 0 }
- }
- }
- }
- }
- }
- </script>
复制代码
代码要点如下:spanArr 的长度与 tableData 一致,每个元素表示该行在合并列应占的行数;值为 0 表示隐藏,大于 0 表示作为合并起点显示内容;pos 记录当前分组的起始索引,遇到新部门时更新;span-method 只对 columnIndex === 0 应用规则,姓名和薪资列不处理,从而形成“第一列合并、其他列独立展示”的效果。
四、数据变化后必须重新计算
合并规则依赖当前表格数据。筛选、排序、增删记录后,spanArr 如果还是旧数据,就会出现合并行数错误或单元格错位。因此数据变化后要重新调用预处理方法,例如监听 tableData:
- watch: {
- tableData: {
- handler(newVal) {
- this.getSpanArr(newVal)
- },
- deep: true
- }
- }
复制代码
这样表格数据更新时,合并规则同步刷新,避免显示异常。
五、多列合并与性能注意点
如果同时合并多列,各列的合并起点必须保持一致,否则同一个视觉分组在不同列上会错位。另一个问题是性能:预处理遍历一次数据,时间复杂度为 O(n),对于大多数后台表格数据量完全够用。如果数据量极大,可以考虑由后端直接返回合并规则,减少前端重复计算。
实践上建议把数据预处理独立封装,保持 span-method 逻辑简洁;返回值优先使用 { rowspan, colspan } 对象形式,语义比数组更清晰;始终用 columnIndex 限定需要合并的列,其他列直接放行;数据变化后立即重新计算 spanArr。掌握这些要点后,按部门、按日期或按其他分组字段合并 el-table 单元格都可以用同一套思路实现。 |