Stories

Detail Return Return

實現el-table樹結構表格展開摺疊且合併單元格功能(兩種思路) - Stories Detail

需求描述

  • 樹結構表格
  • 可展開摺疊,有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>
user avatar kongsq Avatar congjunhua Avatar tonyyoung Avatar yujiaao Avatar laomao_5902e12974409 Avatar panpanpanya Avatar neronero Avatar xingzhaodezhaoxiansheng Avatar feixiangdeyumi Avatar hui_61e3b3803b922 Avatar echo_numb Avatar zhanglei_5b040a0fa2e41 Avatar
Favorites 13 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.