前言
大家好,我是梁木由。相信大家在我们实际项目中会经常碰到*Tree* 树形控件,多层次的结构列表。大部分业务会用到可搜索的树,进行模糊查找。那大家有没有考虑过数据量在比较大并且还可以对树进行增删改的情况下,会呈现什么样的效果呢。我们应该怎么样优化
antd tree树形控件
图例
下图一所示为antd官网的例子,图二所示为搜索后的树结果展示
根据上图所示呢,我们会觉得很棒呀,效果也没什么问题,立马复制粘贴到自己项目里。我也太棒了吧,这么利索的就完成了一个需求。
那事实如此吗?嗯,对,没错。对于没有特殊数据量的需求来说,的确可以满足。那如果要实现复杂一点的功能比如可以对树进行增删改查呢,那我们来说说会出现哪些问题。
实现功能
- 对树增加节点
- 对树修改节点
- 对树删除节点
那对于上述三个功能,以上antd 示例,还可以满足吗,答案肯定是不行,那就需要我们在它的基础上进行二次开发,或者自己从零开始开发。
功能优化
那么首先需要想到重点是什么,还用说吗,当然是完成需求呀,那作为我们开发人员来说,soeasy。那这个时候产品又来了,说我们这个树呢数据量是比较大的,我们要考虑到用户的体验。比如说呢
- 用户搜索中呢,我们的树结果展示需要做到,非常快的更新,不希望用户对着loading发呆,趁此机会喝口咖啡,我们要他全神贯注的使用我们的系统。
- 搜索后呢,节点的显示以及展开要明确,无关节点及对应的父节点不需要展示,不需要呈现在页面
- 并且呢用户的增删改也需要做无痕更新,
此时我不屑的眼神。
优化方法
首先呢我们需要知道的如何避免上述几种比较差的体验感。我们都知道,树形格式化的数据都是以children进行嵌套的。那我们需要操作某个节点时,就需要一直在递归直到获取到相应节点。那我们只需要避免这种递归操作不就可以了吗。
如何避免呢,我们可以将树形数据转化为扁平化的数据,只要对树进行任何操作,都在扁平化的数据中处理各种操作,然后再将扁平化数据转为树形数据就可以了,通过操作扁平化数据这种方法呢,我认为可以解决大部分的体验问题。
那么看下代码如何实现
格式化树形数据结构为扁平数据结构
/**
* @description 格式化树形数据结构为扁平数据结构
* @param data 传入初始数据
* @param treeData return 的返回结果
* @param _params 替换初始数据中 key,title,children 字段为树组件中对应的字段
* @param _level 层级级别
* @param parentIds 父节点id集合用来设置pid
* @param _params.other 自定义添加需要返回的字段
*/
export function formatFlatTree(
data,
_params: any = {},
_level = 1,
parentIds: string[] = [],
treeData: TreeDataState[] = []
) {
if (!data.length) {
return treeData;
}
const list: TreeDataState[] = [];
const param = {
id: _params.id || 'key',
title: _params.title || 'title',
children: _params.children || 'children',
other: _params.other || [],
};
const pIds: string[] = [];
const obj = {};
for (let i = 0; i < data.length; i++) {
const node = data[i];
const key = node[param.id];
const child = node[param.children] || [];
if (param.other.length) {
param.other.forEach((element) => {
obj[element] = node[element];
});
}
treeData.push({
key: key,
title: node[param.title],
pid: parentIds[i] || '0',
level: _level,
...obj,
});
list.push(...child);
pIds.push(...new Array(child.length).fill(key));
}
return formatFlatTree(list, param, _level + 1, pIds, treeData);
}
扁平化数据转为树形数据
/** 格式化扁平数据结构为树形数据结构*/
export function formatTree(list) {
const data = JSON.parse(JSON.stringify(list));
const obj = {},
trees: ftDataState[] = [];
data.forEach((item) => {
obj[item.key] = item;
});
data.forEach((item) => {
const parent = obj[item.pid];
if (parent) (parent.children || (parent.children = [])).push(item);
else trees.push(item);
});
return trees;
}