element-ui中el-table的跨行,合并行计算方式

背景

在最近的一个迭代上,有一个功能点是在表格中做一个合并单元格的效果。大致如下图

在这里插入图片描述

只有第一列合并行,跨行。合并的规则是纵向相邻的连续N行,如果id一致,则合并。

看到这个需求一开始我以为很简单,表格跨行.跨列,不就是设置rowspancolspan。于是我就把这个功能点放到最后来实现了。

等到真正去做的时候,查了一下element的文档,发现并没那么简单。需要自己动手去写一个方法设置每个单元格的rowspan和 colspan。 眼看要提测了,想偷懒的想借他山之石。于是在前端群里问了一下,又没人写过类似的,解决一下。后来想想真是多此一举,关键时刻一定要相信自己。何况很久没有遇到有意思的题目了。看起来很有趣。在前端群里得到否定答案的我,决定加班好好研究一下这个合并的规则。为他人铺一个康庄大道。

认真研究

以下是官方提供的一个在第一列合并行的例子

代码语言:javascript
复制
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  if (columnIndex === 0) {
    if (rowIndex % 2 === 0) {
      return {
        rowspan: 2,
        colspan: 1,
      }
    } else {
      return {
        rowspan: 0,
        colspan: 0,
      }
    }
  }
}

el-table标签上设置 :span-method="objectSpanMethod" 就能实现在第一列的偶数行被合并。这个例子写的很简单。没有掺杂任何业务逻辑。该方法返回的数据可以是 一个包含rowspan和colspan的对象。 {rowspan: 2, colspan: 1} 表示当前单元格占用二行一列。 {rowspan: 0, colspan: 0} 表示当前单元格缺少,或被合并了。

row表示当前行。column表示当前列,rowIndex当前行的索引,columnIndex 当前列的索引。

在日常开发中,常见的合并行,或合并列的场景是根据后端返回的一个数组,依据其中的某一个属性来合并行。比如有一个表格,统计每个人车辆的所属情况。后端是以车辆为粒度返回数据。当一个人有多台车时,(比如我)就需要将姓名那一列合并行。这样做后,信息的层次和结构会更加清晰。表现得更加具体,形象。

思路实现

根据合并的规则可以知道,在我的需求中,只需要确定rowspan的值即可。也就是合并多少行,对于被合并的单元格,rowspan和colspan都为零。而合并的单元格,他的colspan为1,因为它不跨列。

于是拿到表格数据后,对表格数据进行以下处理。假设要合并的字段为runPeriod。相同的runPeriod单元格合并起来。

代码语言:javascript
复制
addSpanRows(tableData) {
  let pos = 0
  let len = tableData.length
  for (let i = 0; i < len; i++) {
    const item = tableData[i]
    if (i === 0) {
      item.$rows = 1
      pos = 0
    }
    if (i !== 0) {
      if (item.runPeriod === tableData[i - 1].runPeriod) {
        item.$rows = 0
        tableData[pos].$rows = tableData[pos].$rows + 1
      } else {
        item.$rows = 1
        pos = i
      }
    }
  }
}

使用pos记录出现重复的元素的索引,找到一个重复后就将索引为pos的记录的 $rows 加1,找不到就将pos设置为当前遍历的索引

代码语言:javascript
复制
spanMethod({row, _, __, columnIndex}) {
  if (columnIndex === 0) {
    return {
      rowspan: row.$rows,
      colspan: row.$rows ? 1 : 0,
    }
  }
}

当时第一列时使用$rows进行合并单元格。

这样配置一下即可。