表格实现合并单元格

实现的效果

表格实现合并单元格_第1张图片

一、列合并

此需求的列合并比较简单, 直接使用el-table-column包括即可


      
      

二、行合并

1. 排序

1)原因

因为哪些单元格需要合并,哪些单元格就必须挨着,不挨着就无法进行单元格合并

2)实现思路

1、使用sort
2、由于大多数场景判断的字段都是字符串格式,不能直接使用a-b的形式来判断,所以使用判断大小来代替;
3、由于可能存在多个判断条件,比如按照学校和专业排序,学校相同的还需要按专业排序;
4、排序规则

  • 如果a.xx < b.xx,则返回-1,代表升序;
  • 如果a.xx > b.xx,则返回1,代表降序;
  • 如果相等,则需要判断是否还有其他判断条件,如果没有,则返回0,代表不做处理;如果有,则执行递归,继续以其他判断条件按照以上两个步骤进行判断大小;

3)代码实现

/**
 * 按一系列参数排序
 * @param {*} table 原数组
 * @param {*} names 排序的列的数组
 */
getSortArr(table, names) {
  return table.sort((a, b) => {
    function sortFn(names, index) {
      const itemA = a[names[index]]
      const itemB = b[names[index]]
      if (itemA < itemB) {
        return -1;
      } else if (itemA > itemB) {
        return 1;
      } else {
        // 如果当前列的值相同
        // 如果最大列索引值还大于当前列索引,则递归, 判断下一列的值,否则返回0即可
        if (names.length - 1 > index) {
          return sortFn(names, index + 1);
        } else {
          return 0;
        }
      }
    }
    return sortFn(names, 0)
  });
},

2. 生成单元格数据

1)原因

因为每一个单元格是否需要合并、是否需要被合并,以及需要合并的话要合并多个单元格,需要用一个固定的数据来控制

2)实现思路?

1、遍历排序之后的数据,判断该项是否与前一项的条件相等(第一项无需判断)
2、判断条件是有层级的,比如需要判断学校和专业,如果当前是在判断学校是否相等,那么就不需要考虑专业的情况;但如果当前是在判断专业,那么必须保证两者学校也是同一个,否则不能作合并处理;
3、定义一个数组,用于存储各个单元格的值;当不需要作合并处理时,存储一个和所在列索引值一致的数据即可,当需要作合并处理时,存储一个大于所在列索引值的数据,当需要被合并(即该单元格不会显示)时,存储0;

  • 举例:存储数据为[0,1,3,0,4],
    - 索引为0,1,4的单元格,存储值和索引一致,代表不需要合并
    - 索引为2的单元格,存储值为3,代表需要合并到索引为3的单元格
    - 索引为3的单元格,存储值为0,代表需要被合并,该单元格不需要显示

3)代码实现

/**
 * 生成各单元格的数据
 * @param {*} tableData 原数据
 * @param {*} rowSpanType 判断条件列的数组
 */
handleTableData(tableData, rowSpanType) {
  const result = {}; // 存储数据
  // 由于是多个判断条件,所以需要遍历
  for (var i = 0; i < rowSpanType.length; i++) {
    const rowSpanArr = []; // 存储数据
    let position = 0; // 存储数据的索引值
    // 遍历原数据的每一项,与前一项对比
    tableData.forEach((item, index) => {
      // 第一项直接存储,不作处理
      if (index == 0) {
        rowSpanArr.push(0);
        position = 0;
      } else {
        // 判断与前一项的值是否相等(包括此列之前所有的列的值)
        function isEqual() {
          for (var j = i; j >= 0; j--) {
            if (item[rowSpanType[j]] == tableData[index - 1][rowSpanType[j]]) {
              continue;
            } else {
              return false;
            }
          }
          return true;
        }
        if (isEqual()) {
          rowSpanArr[position] += 1; // 前一项需要合并,存储值+1,代表需要合并到哪一行
          rowSpanArr.push(0); // 该项需要被合并,存储值为0,
        } else {
          // 与索引相等,代表不需要合并
          rowSpanArr.push(index);
          position = index;
        }
      }
    });
    result[rowSpanType[i]] = rowSpanArr;
  }
  return result;
},

3. 合并

思路分析

el-table提供了合并行或列的计算方法,即span-method,直接使用即可
参数: row当前行,column当前列的数据、rowIndex当前行索引、columnIndex当前列索引
返回值(可返回数组或对象)
- 没有处理,代表不需要合并,也不需要被合并
- 返回1,代表不作合并处理
- 返回0,代表被合并
- 返回值大于1,代表会合并到多少单元格
- 举例:当columnIndex=0, rowIndex=0时,return [2,1]或者{rowspan:2,colspan:1},代表第一行第一列合并了第二行第一列

难点

但是什么条件下返回,返回什么值是个问题,所以每个单元格都需要一个数据来控制自己是否需要合并,是否需要被合并,以及如果合并需要合并多少格,通过思路2我们已经实现。

代码实现

spanMethod({ row, column, rowIndex, columnIndex }) {
  // 由于是多个判断条件,多个列都需要合并,所以需要遍历
  for (var i = 0; i < this.rowSpanType.length; i++) {
  	// 作某一列的合并处理
    if (column.property === this.rowSpanType[i]) {
      // 拿到当前单元格的存储数据
      const rowspan = this.rowSpanArr[this.rowSpanType[i]][rowIndex];
      // rowspan == rowIndex 代表不需要合并单元格,此处只需处理需要合并、需要被合并的单元格
      if (rowspan != rowIndex) {
        // rowspan===0代表被合并,!=0代表合并的目标行数
        if (rowspan === 0) {
          // 被合并的单元格,返回0即可
          return { rowspan: 0 };
          // return [0, 1]
        } else {
          // 合并数 = rowspan合并到的行数 - 当前所在的行数 + 1
          return { rowspan: rowspan - rowIndex + 1, colspan: 1 };
          // return [rowspan - rowIndex + 1, 1]
        }
      }
    }
  }
},

三、整体代码实现

使用的话,直接更改data中两个值即可,其他地方不需要动。

  • tableData 改成你的表格数据
  • rowSpanType 存放你需要合并的列(有顺序)



你可能感兴趣的:(功能实现,vue)