动态层级表格合并
之前写了两层和三层数据的表格合并,数据处理.这种事先确定了表格的层级
如果表格的层级在一定范围内不固定,就需要动态处理了,最近研究了下,把方法记录下来
代码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}`来判断