需求描述

  • 树结构表格
  • 可展开折叠,有children子集项
  • 并且对应列还需要合并单元格(大类合并)
  • 笔者试了试 使用el-table自带的树结构表格似乎没法实现
  • 就这个::tree-props="{children: 'children', hasChildren: 'hasChildren'}">
  • 于是,只能换种思路实现了
  • 添加行、删除行方式,同时动态计算需要合并的单元格信息

效果图

思路一:计算出现次数,并按照大类,给到对应单元格合并信息

完整代码,复制粘贴即用

<template>
  <div>
    <el-table ref="myTableRef" :data="tableData" border :span-method="arraySpanMethod">
      <el-table-column prop="month" label="月份" width="72" />
      <el-table-column prop="incomeType" label="收益类别" width="180">
        <template slot-scope="scope">
          <span class="arrow" v-if="scope.row.children" @click="handleExpand(scope)">
            <span v-if="scope.row.expand">⬇️</span>
            <span v-else>➡️</span>
          </span>
          <span :class="{ isChild: scope.row.level === 2 }">{{
            scope.row.incomeType
          }}</span>
        </template>
      </el-table-column>
      <el-table-column prop="value" label="金额" width="180"> </el-table-column>
      <el-table-column prop="unit" label="单位" width="180"> </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      mergeInfo: {},
      tableData: [
        {
          id: 1,
          month: "三月",
          incomeType: "工资",
          unit: "元",
          value: 2000,
          level: 1,
        },
        {
          id: 2,
          month: "三月",
          incomeType: "奖金",
          unit: "元",
          value: 500,
          expand: false,
          level: 1,
          children: [
            {
              id: 21,
              month: "三月",
              incomeType: "个人奖金",
              unit: "元",
              value: 300,
              level: 2,
            },
            {
              id: 22,
              month: "三月",
              incomeType: "团队奖金",
              unit: "元",
              value: 200,
              level: 2,
            },
          ],
        },
        {
          id: 3,
          month: "三月",
          incomeType: "外快",
          unit: "元",
          value: 80,
          level: 1,
        },
        {
          id: 4,
          month: "四月",
          incomeType: "奖金",
          unit: "元",
          value: 600,
          expand: false,
          level: 1,
          children: [
            {
              id: 41,
              month: "四月",
              incomeType: "个人奖金",
              unit: "元",
              value: 300,
              level: 2,
            },
            {
              id: 42,
              month: "四月",
              incomeType: "团队奖金",
              unit: "元",
              value: 200,
              level: 2,
            },
            {
              id: 43,
              month: "四月",
              incomeType: "绩效奖金",
              unit: "元",
              value: 100,
              level: 2,
            },
          ],
        },
        {
          id: 5,
          month: "四月",
          incomeType: "外快",
          unit: "元",
          value: 80,
          level: 1,
        },
        {
          id: 6,
          month: "五月",
          incomeType: "奖金",
          unit: "元",
          value: 600,
          expand: false,
          level: 1,
          children: [
            {
              id: 61,
              month: "五月",
              incomeType: "个人奖金",
              unit: "元",
              value: 300,
              level: 2,
            },
            {
              id: 62,
              month: "五月",
              incomeType: "团队奖金",
              unit: "元",
              value: 200,
              level: 2,
            },
            {
              id: 63,
              month: "五月",
              incomeType: "绩效奖金",
              unit: "元",
              value: 100,
              level: 2,
            },
          ],
        },
        {
          id: 7,
          month: "五月",
          incomeType: "外快",
          unit: "元",
          value: 80,
          level: 1,
        },
      ],
    };
  },
  mounted() {
    this.calCellMerge(this.tableData);
  },
  methods: {
    handleExpand({ $index, row, column, $event }) {
      row.expand = !row.expand;
      if (row.expand) {
        // 从索引处把子集的元素取出,添加进去(新增行)
        this.tableData.splice($index + 1, 0, ...row.children);
      } else {
        // 从索引处把子集的元素直接去除(删除行)
        this.tableData.splice($index + 1, row.children.length);
      }
      this.calCellMerge(this.tableData);
    },
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      // 针对于月份列进行合并
      if (column.label != "月份") return;

      if (row.month == "三月") {
        if (rowIndex == this.tableData.findIndex((item) => item.month == "三月")) {
          // 头一个出现的往下走对应行数
          return {
            rowspan: this.mergeInfo["三月"],
            colspan: 1,
          };
        } else {
          // 剩下的直接 0 0 即去掉单元格
          return {
            rowspan: 0,
            colspan: 0,
          };
        }
      }
      if (row.month == "四月") {
        if (rowIndex == this.tableData.findIndex((item) => item.month == "四月")) {
          return {
            rowspan: this.mergeInfo["四月"],
            colspan: 1,
          };
        } else {
          return {
            rowspan: 0,
            colspan: 0,
          };
        }
      }
      if (row.month == "五月") {
        if (rowIndex == this.tableData.findIndex((item) => item.month == "五月")) {
          return {
            rowspan: this.mergeInfo["五月"],
            colspan: 1,
          };
        } else {
          return {
            rowspan: 0,
            colspan: 0,
          };
        }
      }
    },
    calCellMerge(tableData) {
      // 统计月份出现的次数
      let obj = {};
      tableData.forEach((item) => {
        if (!obj[item.month]) {
          obj[item.month] = 1;
        } else {
          obj[item.month] = obj[item.month] + 1;
        }
      });
      this.mergeInfo = obj;
    },
  },
};
</script>

<style>
.arrow {
  cursor: pointer;
  font-size: 16px;
}
.isChild {
  padding-left: 20px;
}
</style>

思路二:把单元格合并信息,添加到tableData中的每一项中,直接使用

完整代码

<template>
  <div>
    <el-table ref="myTableRef" :data="tableData" border :span-method="arraySpanMethod">
      <el-table-column prop="month" label="月份" width="72" />
      <el-table-column prop="incomeType" label="收益类别" width="180">
        <template slot-scope="scope">
          <span class="arrow" v-if="scope.row.children" @click="handleExpand(scope.row)">
            <span v-if="scope.row.expand">⬇️</span>
            <span v-else>➡️</span>
          </span>
          <span :class="{ isChild: scope.row.level === 2 }">{{
            scope.row.incomeType
          }}</span>
        </template>
      </el-table-column>
      <el-table-column prop="value" label="金额" width="180"> </el-table-column>
      <el-table-column prop="unit" label="单位" width="180"> </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tableData: [
        {
          id: 1,
          month: "三月",
          incomeType: "工资",
          unit: "元",
          value: 2000,
          level: 1,
        },
        {
          id: 2,
          month: "三月",
          incomeType: "奖金",
          unit: "元",
          value: 500,
          expand: false,
          level: 1,
          children: [
            {
              id: 21,
              month: "三月",
              incomeType: "个人奖金",
              unit: "元",
              value: 300,
              level: 2,
            },
            {
              id: 22,
              month: "三月",
              incomeType: "团队奖金",
              unit: "元",
              value: 200,
              level: 2,
            },
          ],
        },
        {
          id: 3,
          month: "三月",
          incomeType: "外快",
          unit: "元",
          value: 80,
          level: 1,
        },
        {
          id: 5,
          month: "四月",
          incomeType: "奖金",
          unit: "元",
          value: 600,
          expand: false,
          level: 1,
          children: [
            {
              id: 51,
              month: "四月",
              incomeType: "个人奖金",
              unit: "元",
              value: 300,
              level: 2,
            },
            {
              id: 52,
              month: "四月",
              incomeType: "团队奖金",
              unit: "元",
              value: 200,
              level: 2,
            },
            {
              id: 53,
              month: "四月",
              incomeType: "绩效奖金",
              unit: "元",
              value: 100,
              level: 2,
            },
          ],
        },
        {
          id: 6,
          month: "四月",
          incomeType: "外快",
          unit: "元",
          value: 80,
          level: 1,
        },
        {
          id: 7,
          month: "五月",
          incomeType: "奖金",
          unit: "元",
          value: 600,
          expand: false,
          level: 1,
          children: [
            {
              id: 71,
              month: "五月",
              incomeType: "个人奖金",
              unit: "元",
              value: 300,
              level: 2,
            },
            {
              id: 72,
              month: "五月",
              incomeType: "团队奖金",
              unit: "元",
              value: 200,
              level: 2,
            },
            {
              id: 73,
              month: "五月",
              incomeType: "绩效奖金",
              unit: "元",
              value: 100,
              level: 2,
            },
          ],
        },
        {
          id: 8,
          month: "五月",
          incomeType: "外快",
          unit: "元",
          value: 80,
          level: 1,
        },
      ],
    };
  },
  mounted() {
    // 把合并信息设置到表格数据中
    this.addMergeInfoInToTableItem(this.tableData);
  },
  methods: {
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      // 第0列,月份列进行控制
      if ([0].includes(columnIndex)) {
        return row.dateSpan;
      }
    },
    addMergeInfoInToTableItem(datas = [], arraySpan = {}) {
      // 遍历后,把合并信息添加到表格数据中
      datas.forEach((it, idx) => {
        it.idx = idx;
        if (!arraySpan[it.month]) {
          it.dateSpan = {
            rowspan: 1,
            colspan: 1,
          };
          arraySpan[it.month] = it;
        } else if (arraySpan[it.month]) {
          arraySpan[it.month].dateSpan.rowspan++;
          it.dateSpan = {
            rowspan: 0,
            colspan: 0,
          };
        }
      });
    },
    handleExpand(row) {
      row.expand = !row.expand;
      if (row.expand) {
        this.tableData.splice(row.idx + 1, 0, ...row.children);
      } else {
        this.tableData.splice(row.idx + 1, row.children.length);
      }
      this.addMergeInfoInToTableItem(this.tableData);
      this.reDraw();
    },
    // 重绘表格很有用
    reDraw() {
      this.$nextTick(() => {
        this.$refs.myTableRef.doLayout();
      });
    },
  },
};
</script>

<style>
.arrow {
  cursor: pointer;
  font-size: 16px;
}
.isChild {
  padding-left: 20px;
}
</style>

水冗水孚
1.1k 声望589 粉丝

每一个不曾起舞的日子,都是对生命的辜负