动态层级表格合并

之前写了两层和三层数据的表格合并,数据处理.这种事先确定了表格的层级
如果表格的层级在一定范围内不固定,就需要动态处理了,最近研究了下,把方法记录下来
代码githup地址: https://github.com/shengbid/vue3-vite-demo/tree/main/src/views/table/mutilSpanTable
页面效果:

全部代码
<template>
  <div style="margin-top: 20px">
    <p>动态层级表格合并</p>
    <div style="margin-bottom: 10px">
      表格层级(2-5):
      <a-input-number
        :value="maxLevel"
        :min="2"
        :max="5"
        style="width: 220px"
        @change="changeLevel"
      />
    </div>
    <a-table
      :columns="columns"
      :data-source="tableData"
      :pagination="false"
      bordered
    >
      <template #bodyCell="{ column, text }">
        <template v-if="column.dataIndex === 'name'">
          <a href="javascript:;">{{ text }}</a>
        </template>
      </template>
    </a-table>
  </div>
</template>

<script>
import { ref } from "vue";
import { omit } from "lodash";

export default {
  name: "mutilSpan",
  setup() {
    const maxLevel = ref(2);
    const tableData = ref([]);
    const treeData = ref([]);
    const columns = [
      {
        title: "Name",
        dataIndex: "name",
        customCell: (record, index) => {
          if (record.level < 2) return {};
          return {
            rowSpan: record.rowSpan1 ? record.rowSpan1 : 0,
          };
        },
      },
      {
        title: "Age",
        dataIndex: "age",
        customCell: (record, index) => {
          if (record.level < 3) return {};
          return {
            rowSpan: record.rowSpan2 ? record.rowSpan2 : 0,
          };
        },
      },
      {
        title: "Home phone",
        dataIndex: "tel",
        customCell: (record, index) => {
          if (record.level < 4) return {};
          return {
            rowSpan: record.rowSpan3 ? record.rowSpan3 : 0,
          };
        },
      },
      {
        title: "Phone",
        dataIndex: "phone",
        customCell: (record, index) => {
          if (record.level < 5) return {};
          return {
            rowSpan: record.rowSpan4 ? record.rowSpan4 : 0,
          };
        },
      },
      {
        title: "Address",
        dataIndex: "address",
      },
    ];
    // 获取表格children length
    const getChildLength = (data, spanLengths = []) => {
      let newLeg = 0;
      data.forEach((item) => {
        if (item.children && item.children.length) {
          getChildLength(item.children, spanLengths);
        } else {
          newLeg++;
        }
      });
      spanLengths.push(newLeg);
      return spanLengths;
    };
    // 处理表格数据
    const handleTable = (data, parentItem) => {
      data.forEach((item, i) => {
        if (item.children && item.children.length) {
          item[`rowSpan${item.level}`] = getChildLength(item.children).reduce(
            (pre, cur) => {
              return pre + cur;
            },
            0
          );

          handleTable(
            item.children,
            i === 0
              ? {
                  ...parentItem,
                  ...omit(item, "children"),
                }
              : { ...omit(item, "children") }
          );
        } else {
          if (i === 0) {
            tableData.value.push({ ...parentItem, ...omit(item, "children") });
          } else {
            tableData.value.push(omit(item, "children"));
          }
        }
      });
    };

    // 生成表格树形数据
    const initTable = () => {
      const render = (level, key) => {
        let newLevel = level;
        const arr = [];
        // 两种情况都可满足
        const random = Math.floor(Math.random() * 3); // 1.children可以为空
        // const random = Math.ceil(Math.random() * 3); // 2.每层children下都有值
        for (let i = 0; i < random; i++) {
          const item = {
            key: `${key}${i}`,
            name: "John Brown",
            age: 32,
            tel: "0571-22098909",
            phone: 18889898989,
            address: "New York No. 1 Lake Park",
            level: newLevel,
          };
          if (newLevel < maxLevel.value) {
            item.children = render(newLevel + 1, item.key);
          }
          arr.push(item);
        }
        return arr;
      };
      treeData.value = render(1, "");
      tableData.value = [];
      handleTable(treeData.value);
    };
    initTable();
    // console.log(treeData.value, tableData.value);

    const changeLevel = (val) => {
      maxLevel.value = val;
      initTable();
      console.log(treeData.value, tableData.value);
    };
    return {
      maxLevel,
      columns,
      tableData,
      changeLevel,
    };
  },
};
</script>

<style>
</style>
emplate 部分就是 ant design UI 的 table 组件引用
主要看下 js 部分

里面有三个方法

1. initTable 生成表格数据
这里一般是后端给的数据,这里是纯前端的,就自己生成了数据
数据格式为 [{xx: xxx, children: [{}]}]
这里注意,如果你们后端返回的数据,是这种父级字段与字级字段不一致, [{parentName: 1, children: [{name: 'xx'}]}]
你需要再写个方法,循环处理把上一级的数据放到下一级 [{parentName: 1, name: [{parentName: 1, name: 'xx'}]}]
每一级数据加上一个 level 字段,方便之后的操作

2. getChildLength 获取当前 item 下所有 children 的长度
表格合并,最重要的是要知道合并的行数,其实就是嵌套 children 的 length
所以用这个方法获取每一个有 children 的 item 的合并 length

3. handleTable 将表格处理成一维数组
表格渲染时,实际设计一条一条的数据,需要把初始的树形数据转变成一维数组
表格的数据长度是以这个树形数据最后一级的 children 个数决定的,所以这里是一个递归,直到最后一级时,把数据 push 到 tableData 里面
这里对于合并行的处理, 需要合并的数据行都放在 i=0 的那一行
举例: 原始数据如下
const initData = [
  {
    key: "1",
    name: "John Brown",
    level: 1,
    children: [
      {
        key: "10",
        name: "John Brown",
        level: 2,
        children: [
          {
            key: "100",
            name: "John Brown",
            level: 3
          },
        ],
      },
      {
        key: "11",
        name: "John Brown",
        level: 2,
        children: [
          {
            key: "110",
            name: "John Brown",
            level: 3
          },
          {
            key: "111",
            name: "John Brown",
            level: 3
          },
        ],
      },
    ],
  }
]
展示出来的效果应该是:
最外层的合并行应该是 3 行 也就是最后一层 children 的个数
第二层的合并行 是 1 行 和 2 行
处理好的 tableData 就是这样
[
    {
        key: "100"
        name: "John Brown"
        rowSpan1: 3
        rowSpan2: 1
        level: 3
    },
    {
        key: "110"
        name: "John Brown"
        rowSpan2: 2
        level: 3
    }
    {
        key: "111"
        name: "John Brown"
        level: 3
    }
]
对于 columns 的设置,根据 level 和`${rowSpan}{level}`来判断
posted @ 2023-02-10 16:39  潇湘羽西  阅读(217)  评论(0编辑  收藏  举报