需求有些变态,我们用一段话和一张图来演示下
效果如下:
如遇到每级展开层级不一致的,如【2级2】展开到第3级,那此时点击展开,所有已展开的不动,将未展开到第3级的其他元素全部展开到第3级
效果如下:所有3级展开
折叠同理:如下,【2级2-1】收起,但当前未折叠的最大层级为【5级】
此时需要注意,我们应把没有子元素的【1级】,及末级均去掉,不参与折叠展开事件
效果如下:【5级】收起
再点击收起:【4级】收起
话不多说,代码直接上:
import React, { useEffect, useState, useMemo, useRef } from 'react';
import {
Table,
Button,
} from 'antd';
import { connect } from 'umi';
import { cloneDeep, isEqual, xorWith, isEmpty } from 'lodash';
const QualityEvaluationAccount = () => {
// 所有已展开list
const [expandedList, setExpandedList] = useState([])
// 所有表格已展开key
const [expandedKeys, setExpandedKeys] = useState([])
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '12%',
},
{
title: 'Address',
dataIndex: 'address',
width: '30%',
key: 'address',
},
];
const dataSource = [
{
key: 1,
name: '我是一级(一)',
age: 60,
address: 'New York No. 1 Lake Park',
level: 1,
children: [
{
key: 11,
name: '2级1',
age: 42,
address: 'New York No. 2 Lake Park',
level: 2,
},
{
key: 12,
name: '2级2',
age: 30,
address: 'New York No. 3 Lake Park',
level: 2,
children: [
{
key: 121,
name: '3级3-1',
age: 16,
address: 'New York No. 3 Lake Park',
level: 3,
children: [
{
key: 1211,
name: '4级4-1',
age: 16,
address: 'New York No. 3 Lake Park',
level: 4,
children: [
{
key: 12111,
name: '5级5-1',
age: 16,
address: 'New York No. 3 Lake Park',
level: 5,
},
],
},
],
},
],
},
{
key: 13,
name: '2级3',
age: 72,
address: 'London No. 1 Lake Park',
level: 2,
children: [
{
key: 131,
name: '3级3-1',
age: 42,
address: 'London No. 2 Lake Park',
level: 3,
children: [
{
key: 1311,
name: '4级4-1',
age: 25,
address: 'London No. 3 Lake Park',
level: 4,
},
{
key: 1312,
name: '4级4-2',
age: 18,
address: 'London No. 4 Lake Park',
level: 4,
children: [
{
key: 13111,
name: '5级5-1',
age: 23,
address: 'London No. 31 Lake Park',
level: 5,
},
{
key: 13112,
name: '5级5-2',
age: 11,
address: 'London No. 41 Lake Park',
level: 5,
children: [
{
key: 131121,
name: '6级6-1',
age: 23,
address: 'London No. 31 Lake Park',
level: 6,
},
{
key: 131122,
name: '6级6-2',
age: 11,
address: 'London No. 41 Lake Park',
level: 6,
},
],
},
],
},
],
},
],
},
],
},
{
key: 2,
name: '我是一级(2)',
age: 32,
address: 'Sydney No. 1 Lake Park',
level: 1,
children: [
{
key: 21,
name: '2极2-1',
age: 23,
address: 'London No. 31 Lake Park',
level: 2,
children: [
{
key: 211,
name: '3极3-1',
age: 23,
address: 'London No. 31 Lake Park',
level: 2,
},
{
key: 212,
name: '3级3-2',
age: 11,
address: 'London No. 41 Lake Park',
level: 2,
},
],
},
{
key: 22,
name: '2级2-2',
age: 11,
address: 'London No. 41 Lake Park',
level: 2,
},
],
}, {
key: 3,
name: '我是一级(3)',
age: 32,
address: 'Sydney No. 1 Lake Park',
level: 1
}
];
// 获取树结构最大深度
const findDeep = (obj, level = 1) => {
let maxLev = level
obj.children?.forEach(item => {
if (item.children !== null) {
const nestLevel = findDeep(item, level + 1)
maxLev = Math.max(maxLev, nestLevel)
}
})
return maxLev
}
const maxLevel = findDeep(dataSource[0])
console.log('maxLevel', maxLevel)
let arrNew = []
const treeList = (arr) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i].hasOwnProperty("children")) {
treeList(arr[i].children)
}
// 所有没有子集的元素均不参与展开折叠,如1级与最深层级子集
// 因为最深层级子集无子集,所以参与展开折叠的为它的上一级
// 第一级也不参与展开折叠
if (!((arr[i].level === 1 || arr[i].level === maxLevel) && isEmpty(arr[i].children))) {
arrNew.push(child(arr[i]))
}
}
return arrNew;
}
const child = (arr) => {
arr.children = []
return arr;
}
const flatData = treeList(cloneDeep(dataSource))
console.log('flatData', flatData)
// 手动展开
const open = (expanded, record, event) => {
// console.log('expandedexpandedexpandedexpanded', expanded)
let data = cloneDeep(expandedKeys)
if (expanded) {
let keys = [...data, record.key]
setExpandedKeys(keys)
let arr = []
getSelectKeysData(keys, arr)
setExpandedList(arr)
} else {
data.forEach((item, index) => {
if (item === record.key) {
data.splice(index, 1)
}
})
setExpandedKeys(data)
let arr = []
getSelectKeysData(data, arr)
setExpandedList(cloneDeep(arr))
}
}
// 获取已展开的key
const getSelectKeysData = (data, arr) => {
flatData.forEach(item => {
data.forEach(ele => {
if (ele === item.key) {
arr.push(item)
}
})
})
};
// 展开逻辑
// 1.先看是否全部折叠状态,如果expandedKeys为空,则展开1级
const expand = () => {
let level = 1
let expandedData = cloneDeep(expandedList)
console.log('expandedList', expandedList, expandedKeys)
if (expandedKeys.length === 0) {
level = 1
} else {
// 比较已经选择的和所有数据,筛选出未选择的条目,然后找出未展开的最小层级
// 无需关注已展示的层级,只需要找出未选中的最小层级,去展开即可
// 寻找两数组差集
const unqi = xorWith(flatData, expandedData, isEqual)
console.log('unqi', unqi)
// 查找未展开的最小层级
level = Math.min.apply(Math, unqi.map(function (o) { return o.level }))
console.log('level', level)
}
let res = []
console.log('flatData', flatData, level)
flatData.forEach(item => {
if (item.level === level) {
// 将未展开key写入
if (!res.includes(item.key) && !expandedKeys.includes(item.key)) {
res.push(item.key)
}
}
})
const keys = [...expandedKeys, ...res]
setExpandedKeys(keys.sort((a, b) => a - b))
let arr = []
getSelectKeysData(cloneDeep(keys), arr)
setExpandedList(cloneDeep(arr))
}
// 折叠逻辑:
// 1.从已展开keys中找到level最大的,即为最大没有被收起的
const shouqi = () => {
let exList = cloneDeep(expandedList)
let exKeys = cloneDeep(expandedKeys)
// 只需要找出已展开的最大层级,去收起即可
let level = Math.max.apply(Math, exList.map(function (o) { return o.level }))
console.log('shouqi- level', level)
let keyList = []
exList.forEach((item, index) => {
if (item.level === level) {
keyList.push(item.key) // 找出要删除的key
}
})
console.log('exList', exList, keyList)
// 在已展开keys中删除key
// 取已展开列表和删除列表的两数组差集
const unqi = xorWith(exKeys, keyList, isEqual)
console.log('unqi', unqi)
setExpandedKeys(unqi)
let arr = []
getSelectKeysData(unqi, arr)
console.log('arr-====', arr)
setExpandedList(cloneDeep(arr))
}
return (
<>
<Button onClick={expand}>展开</Button>
<Button onClick={shouqi}>折叠</Button>
<Table
columns={columns}
dataSource={dataSource}
rowKey={record => record.key}
expandedRowKeys={expandedKeys}
onExpand={(record, event) => open(record, event)}
/>
</>
);
}
export default QualityEvaluationAccount;