el-table动态合并行列及表头合并

980 阅读1分钟

需求

在最近的项目中有这样一个需求:

  1. eltable需要根据左侧点击不同的树上的数据来动态渲染;
  2. 要动态实现表格的数据和头的合并。

最终效果

2022-07-04-20-20-09.gif

代码实现

代码基于vue2.x 和elementui2.10实现

动态表头的实现主要是将表头通过循环的方式来渲染。

表格数据的合并主要是用到了span-method方法

模版部分

     <el-table
                border
                :data="tableData"
                :span-method="arraySpanMethod"
                :header-cell-style="handerMethod"
                style="width: 100%"
                id="export-table"
              >
              
              // 这种写法是用的header-cell-style来实现合并表头的     
                <el-table-column prop="level2Data" align="center">
                </el-table-column>
                <el-table-column prop="level3Data" label="项目" align="center">
                </el-table-column>
                
                // 这种写法是用的表头嵌套来实现的合并表头
                //tabelMonthData授右上角的select控制
                //tabelColumData 受经营数据控制
                <el-table-column
                  v-for="item in tabelMonthData"
                  :key="item"
                  align="center"
                  :label="item"
                >
                  <el-table-column
                    v-for="c in tabelColumData"
                    :key="c.label"
                    :label="c.label"
                    align="center"
                  >
                  </el-table-column>
                </el-table-column>
              </el-table>

js部分

    // 表格合并项处理方法
    arraySpanMethod({ rowIndex, columnIndex }) {
      let r = rowIndex;
      let c = columnIndex;

      // 统计有多少重复的数据
      let rowObj = this.tableData.reduce((pre, cur) => {
        cur.level2Data in pre
          ? pre[cur.level2Data]++
          : (pre[cur.level2Data] = 1);
        return pre;
      }, {});
      // 将重复的数据转换成数组
      let rowArray = Object.values(rowObj);

      // 动态生成合并的起始点和合并数量
      let tempArr = [];
      let vArr = [];
      rowArray.reduce((pre, acc, i) => {
        if (i === 0) {
          tempArr.push({ v: 0, col: acc });
          vArr.push(0);
        } else {
          tempArr.push({ v: pre, col: acc });
          vArr.push(pre);
        }
        return pre + acc;
      }, 0);

      //  执行合并并删除被合并的单元格
      if (c === 0) {
        const i = tempArr.findIndex((item) => item.v === r);
        return i === -1 && !vArr.includes(r) ? [0, 0] : [tempArr[i].col, 1];
      }
    },

// 点击数据经营的函数
formatData 数据:
[
  { level2Data: '经营数据', level3Data: '资产负载状况', id: 10 },
  { level2Data: '经营数据', level3Data: '损益状况', id: 11 },    
  { level2Data: '资产负载状况', level3Data: '资产总额', id: 101 },
  { level2Data: '资产负载状况', level3Data: '负载总额', id: 102 },
  { level2Data: '损益状况', level3Data: '营业收入', id: 110 },
  { level2Data: '损益状况', level3Data: '营业支出', id: 111 },
  { level2Data: '损益状况', level3Data: '净利润', id: 112 }
]
    handleTreeCheck(v, data) {
      this.tableData = [];
      let { checkedKeys } = data;
      this.treeOneCheckedKeys = checkedKeys;
      for (let i = 0; i < this.formatData.length; i++) {
        const item = this.formatData[i];
        if (item.pLabel === "经营数据") continue;
        if (checkedKeys.includes(item.id)) {
          this.tableData.push({
            level2Data: item.pLabel,
            level3Data: item.label,
          });
        }
      }
    },
    // 合并表头
    handerMethod({ row ,columnIndex }) {
      if (row[0].level == 1) {
        row[0].colSpan = 0;
        row[1].colSpan = 2;
        if (columnIndex === 0) {
          return { display: "none" };
        }
      }
    },
    
       // 勾选附加数据
    handleRowTreeCheck(v, data) {
    // 数据重置
      this.tabelColumData = this.$options.data().tabelColumData;
      let { checkedNodes, checkedKeys } = data;
      this.tree2CheckedKeys = checkedKeys;
      let temp = checkedNodes.filter((i) => !i.children);
      if (temp)
        temp.forEach((item) => {
          if (item.label.endsWith("变化")) {
            this.tabelColumData.push(
              {
                label: `${item.label}值`,
              },
              {
                label: `${item.label}比例`,
              }
            );
          } else {
            this.tabelColumData.push({
              label: "指标完成比例",
            });
          }
        });
    },
    
        // 右上角的时间选中
    handleTimeChange(v) {
        this.tabelMonthData = this.timeOptions
          .filter((i) => i.value === v)
          .map((item) => {
            return item.month;
          })
          .flat();
    },