Element Plus表格组件---单元格合并函数封装

214 阅读3分钟

1、前言

为什么要使用这种通用合并方案?

是不是每次用Element Plus/Element UI 的表格时总是默认是 “一行一条数据”,但是有的时候实际业务中经常需要 “主数据 + 子数据” 嵌套展示,而且还要绑定对应的数据,显得特别冗余麻烦,如果有一个工具函数直接合并就好了,每次只需要直接传合并哪几列,那么整个开发起来套用多个表就很轻松,而且封装起来后面维护只需要修改 这个工具函数就好了

2、实现效果

image.png

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: 合并列数 }
 */

合并函数工具代码

实现逻辑

image.png

代码实现

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>