table合并单元格算法(内含demo和封装方法)

94 阅读1分钟

业务中常常需要对表格相同内容进行合并,如何通过后端来实现,需要添加很多没必要的字段,因此前端直接通过内容判断是否相同为最佳方案。来看看合并单元格遇到的问题。

Step1

// 由于demo使用的是element-ui,这里的`obj`是el-table的默认参数{ row, rowIndex, column }, 我们要关注的是第二个参数`mergeRule`
:span-method="obj => spanMethod(obj, mergeRule)"

Step2

需要声明合并规则mergeRule和合并方法spanMethod

export default {
  data() {
    return {
      mergeRule: {
        name: {
          deps: [], // 无依赖,直接合并
          merge: true,
        },
        age: {
          deps: ['name'], // 依赖name列
          merge: true,
        },
        address: {
          deps: ['name', 'age'], // 依赖name和age列
          merge: true,
        },
        phone: {
          merge: false, // 不参与合并
        },
      },
    };
  },
  methods: {
    spanMethod({ row, rowIndex, column }, mergeRule) {
      const property = column.property;

      // 如果列不需要合并,返回默认值
      if (!mergeRule[property]?.merge) {
        return { rowspan: 1, colspan: 1 };
      }

      const { deps = [] } = mergeMap[property];
      const prevRow = this.tableData[rowIndex - 1];

      // 检查是否需要与上一行合并
      const shouldMergeWithPrev =
        prevRow &&
        prevRow[property] === row[property] && // 当前列值相同
        deps.every((dep) => prevRow[dep] === row[dep]); // 所有依赖列的值都相同

      if (shouldMergeWithPrev) {
        return { rowspan: 0, colspan: 0 };
      }

      // 计算向下合并的行数
      let mergeCount = 1;
      for (let i = rowIndex + 1; i < this.tableData.length; i++) {
        const nextRow = this.tableData[i];
        const canMerge = nextRow[property] === row[property] && deps.every((dep) => nextRow[dep] === row[dep]);

        if (!canMerge) break;
        mergeCount++;
      }

      return {
        rowspan: mergeCount,
        colspan: 1,
      };
    },
  },
};

Api

mergeMap

属性类型说明
keystringtable 列属性
value{deps: array, merge: boolean}deps 为基准字段列表,merge 为是否要合并