el-table的横向和纵向动态渲染及每项求和

910 阅读2分钟

实现效果如下: 横向为不同的班级,纵向为不同的科目,行数和列数内容都是不确定的,需要动态生成。

image.png

1.数据格式

行数据对应tableData里每项的grade,列数据对应的是tableData里每项options的label。具体渲染几行和几列要看后台返回的数据,以下数据结构是参考示例。

// 用来渲染每列的表头
this.headerList = this.tableData?.[0]?.options?.map(item => ({ label: item.label }))
// table的数据格式
 this.tableData = [
        {
          id: 1,
          grade: "高一(1)",
          options: [
            { label: "语文", num: 200 },
            { label: "数学", num: 200 },
            { label: "英语", num: 200 },
            { label: "物理", num: 150 },
            { label: "历史", num: 80 },
          ],
        },
        {
          id: 2,
          grade: "高一(2)",
          options: [
            { label: "语文", num: 150 },
            { label: "数学", num: 150 },
            { label: "英语", num: 150 },
            { label: "物理", num: 70 },
            { label: "历史", num: 50 },
          ],
        },
      ]

2.html结构

列循环,匹配每个科目得到对应的num人数

 <el-table
      :data="tableData"
      border
      :summary-method="getSummaries"
      show-summary
    >
      <el-table-column label="班级/科目" align="center" prop="grade"  width="150"/>
      <el-table-column
        v-for="(item, index) in headerList"
        :key="index"
        :label="item.label"
        align="center"
        width="120"
      >
        <template slot-scope="scope">
          <span>{{ scope.row.options[index].num }}</span>
        </template>
      </el-table-column>
      <el-table-column label="班级人数汇总" align="center" prop="sum" width="180" />
    </el-table>

3.求和

横向求和:对班级人数进行汇总,加工数据结构,将每项options的num进行求和,定义一个sum元素来接收,用prop进行绑定渲染。

 this.tableData = this.tableData.map((item) => {
        const sum = item.options.reduce((prev, curr) => {
          return prev + Number(curr.num);
        }, 0);
        return {
          ...item,
          sum
        };
      });

纵向求和:使用summary-method并传入一个方法,返回一个数组,这个数组中的各项就会显示在合计行的各列中

  getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "科目人数汇总";
          return;
        }
        const values = data.map((item) => {
          const sameObj = item.options.find(
            (val) => val.label === columns[index].label
          );
          return sameObj ? Number(sameObj.num) : 0;
        });
        if (
          !values.every((value) => isNaN(value)) &&
          column.property !== "sum"
        ) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr);
            if (!isNaN(value)) {
              return prev + curr;
            } else {
              return prev;
            }
          }, 0);
        } else {
          sums[index] = "";
        }
      });
      // 如果需要对末项进行求和,需要单独处理,否则可忽略这段。
      let init = 0
      for (let i = 0; i < sums.length; i++) {
        if (typeof sums[i] === 'number') {
          init += sums[i]
        }
      }
      sums[sums.length - 1] = init
      return sums;
    }

大概就是这样,这些数据格式可以根据需要自行调整啦~