Vue&elementUI Table 使用column之间合并,来实现模拟树状结构在table上的展示

351 阅读1分钟

工作中经常遇到要把树状结构的数据展示在表格上的需求,这样可以让使用者更直观的查看一些数据。在网上找到了一些例子,觉得很不错,所以就把这些例子使用下来,并且用自己的一些经验完善一下,现在记录下,以备以后使用。

实现后的样子是这样的:

image.png

样式方面,如果有自己的需求,可以自行调节。

话不多说上代码:

<template>
  <div class="table-box">
    <el-table
      :span-method="arraySpanMethod"
      :data="tableData"
      border
      highlight-current-row
      style="width: 100%"
    >
      <el-table-column
        v-for="tt in tableTitle"
        :key="tt.prop"
        :label="tt.title"
        :prop="tt.prop"
        :type="tt.type"
        :width="tt.width"
        :align="tt.align"
        :show-overflow-tooltip="tt.showoverflowtooltip"
      >
        <template slot-scope="scope">
          <template v-if="tt.scopeType == 'spanClick'">
            <span @click="spanClick(scope.row, tt.prop)">{{
              scope.row[tt.prop]
            }}</span>
          </template>
          <template v-else-if="tt.scopeType == 'checkBox'">
            <el-checkbox
              v-model="scope.row[tt.prop]"
              @change="checkChange(scope.row, tt.prop)"
            ></el-checkbox>
          </template>
          <template v-else-if="tt.scopeType == 'selectBox'">
            <el-select v-model="scope.row[tt.prop]" placeholder="请选择">
              <el-option
                v-for="item in subprojectContainsTypeS"
                :key="item.value"
                :label="item.label"
                :value="item.value"
                @click.native="selectClick(item, scope.row, tt.prop)"
              >
              </el-option>
            </el-select>
          </template>
          <template v-else-if="tt.scopeType == 'operation'">
            <template v-if="tt.operationContent.type == 'button'">
              <el-button
                v-for="btn in tt.operationContent.content"
                :key="btn.id"
                type="primary"
                @click="btnClick(scope.row, btn.type)"
                >{{ btn.title }}</el-button
              >
            </template>
          </template>
          <template v-else>
            {{ scope.row[tt.prop] }}
          </template>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  name: "multi_table",
  data() {
    return {
      tableData: [
        {
          SN: 1,
          projectType: "配置项顶级软件",
          softType: "非嵌入",
          developmentType: "一类",
          lifeCycleType: "一类模型",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 2,
          projectType: "配置项顶级软件",
          softType: "非嵌入",
          developmentType: "二类",
          lifeCycleType: "二类模型",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 3,
          projectType: "配置项顶级软件",
          softType: "非嵌入",
          developmentType: "三类",
          lifeCycleType: "三类模型",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 4,
          projectType: "配置项顶级软件",
          softType: "非嵌入",
          developmentType: "四类",
          lifeCycleType: "四类瀑布",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 5,
          projectType: "配置项顶级软件",
          softType: "非嵌入",
          developmentType: "四类",
          lifeCycleType: "四类迭代",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 6,
          projectType: "配置项顶级软件",
          softType: "应用软件",
          developmentType: "一类",
          lifeCycleType: "一类模型",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 7,
          projectType: "配置项顶级软件",
          softType: "应用软件",
          developmentType: "二类",
          lifeCycleType: "二类模型",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
        {
          SN: 8,
          projectType: "配置项顶级软件",
          softType: "应用软件",
          developmentType: "三类",
          lifeCycleType: "三类模型",
          changeIsRequired: false,
          changeIsShow: false,
          subprojectContainsType: "",
          isMustIncludeConfigurationItems: false,
          isIncludeDevelopmentPlan: false,
        },
      ],
      tableTitle: [
        {
          title: "序号",
          type: "index",
          width: "50",
          prop: "SN",
          align: "center",
        },
        {
          title: "项目类别",
          prop: "projectType",
          align: "left",
          showoverflowtooltip: true,
          scopeType: "spanClick",
        },
        {
          title: "软件类型",
          prop: "softType",
          align: "left",
          showoverflowtooltip: true,
          scopeType: "spanClick",
        },
        {
          title: "研制类型",
          prop: "developmentType",
          align: "center",
          showoverflowtooltip: true,
          scopeType: "spanClick",
        },
        {
          title: "生命周期类型",
          prop: "lifeCycleType",
          align: "center",
          showoverflowtooltip: true,
          scopeType: "spanClick",
        },
        {
          title: "更改规模是否必填",
          prop: "changeIsRequired",
          align: "center",
          scopeType: "checkBox",
        },
        {
          title: "更改规模是否显示",
          prop: "changeIsShow",
          align: "center",
          scopeType: "checkBox",
        },
        {
          title: "子项目包含类型",
          prop: "subprojectContainsType",
          align: "center",
          scopeType: "selectBox",
        },
        {
          title: "是否必须包含配置项",
          prop: "isMustIncludeConfigurationItems",
          align: "center",
          scopeType: "checkBox",
        },
        {
          title: "是否包含开发计划",
          prop: "isIncludeDevelopmentPlan",
          align: "center",
          scopeType: "checkBox",
        },
        {
          title: "操作",
          prop: "operation",
          align: "center",
          scopeType: "operation",
          operationContent: {
            type: "button",
            content: [{ title: "移除", type: "del", id: "delBtn" }],
          },
        },
      ],
      subprojectContainsTypeS: [
        {
          value: "A",
          label: "A",
        },
        {
          value: "B",
          label: "B",
        },
        {
          value: "C",
          label: "C",
        },
        {
          value: "D",
          label: "D",
        },
        {
          value: "E",
          label: "E",
        },
      ],
      needMergeArr: [
        "projectType",
        "softType",
        "developmentType",
        "lifeCycleType",
        "subprojectContainsType",
        "isMustIncludeConfigurationItems",
        "isIncludeDevelopmentPlan",
      ], //需要进行合并的column的prop值
      rowMergeArrs: {}, //处理过后得到的每个column的合并规则
    };
  },
  created() {
    this.rowMergeArrs = this.rowMergeHandle(this.needMergeArr, this.tableData); // 处理数据
  },
  methods: {
    rowMergeHandle(needMergeArr, tableData) {
      if (!Array.isArray(needMergeArr) && !needMergeArr.length) return false;
      if (!Array.isArray(tableData) && !tableData.length) return false;
      let needMerge = {};
      needMergeArr.forEach((i) => {
        needMerge[i] = {
          rowArr: [], //该数组用来记录在目前列中的每一行的cell应该向下合并几行还是应该被合并。如果对应数组的数据==0,则说明该cell应该被合并。
          rowMergeNum: 0, //用来记录在目前列的第几行的行数,rowNum
        };
        tableData.forEach((item, index) => {
          if (index === 0) {
            needMerge[i].rowArr.push(1);
            needMerge[i].rowMergeNum = 0;
          } else {
            if (item[i] === tableData[index - 1][i]) {
              needMerge[i].rowArr[needMerge[i].rowMergeNum] += 1;
              needMerge[i].rowArr.push(0);
            } else {
              needMerge[i].rowArr.push(1);
              needMerge[i].rowMergeNum = index;
            }
          }
        });
      });
      return needMerge;
    },
    arraySpanMethod({ column, rowIndex }) {
      // console.log("arraySpanMethod", row, column, rowIndex, columnIndex);
      if (column.property === "projectType") {
        return this.mergeAction("projectType", rowIndex, column);
      } else if (column.property === "softType") {
        return this.mergeAction("softType", rowIndex, column);
      } else if (column.property === "developmentType") {
        return this.mergeAction("developmentType", rowIndex, column);
      } else if (column.property === "lifeCycleType") {
        return this.mergeAction("lifeCycleType", rowIndex, column);
      } else if (column.property === "subprojectContainsType") {
        return this.mergeAction("projectType", rowIndex, column);
      } else if (column.property === "isMustIncludeConfigurationItems") {
        return this.mergeAction("projectType", rowIndex, column);
      } else if (column.property === "isIncludeDevelopmentPlan") {
        return this.mergeAction("projectType", rowIndex, column);
      }
    },
    mergeAction(val, rowIndex) {
      let _row = this.rowMergeArrs[val].rowArr[rowIndex];
      let _col = _row > 0 ? 1 : 0;
      return [_row, _col];
    },
    spanClick(row, prop) {
      console.log("spanClick row prop", row, prop);
    },
    checkChange(row, prop) {
      console.log("checkChange row prop", row, prop);
    },
    selectClick(item, row, prop) {
      console.log("selectClick item,row,prop", item, row, prop);
    },
    btnClick(row, type) {
      console.log("btnClick row type", row, type);
    },
  },
};
</script>
<style></style>
  • 首先,虽然表格的样式是树状结构,但是建议数据采取普通的表格数据结构,如果后台返回的数据是树状的,反而不好处理。
  • 处理tableData的方法就是,把你要进行合并的column遍历出来,然后根据他们展示数据如果相同,就让他们进行合并,然后获取到整个表格所有column的合并处理方式的数据,然后再el-table的处理col和row合并的方法span-method中对row和col进行相应的处理即可。