Element UI 里面的树组件 el-tree 在业务开发里面比较常见。同时也有很多令人迷惑的地方【坑】。在此文章中做一次简单的总结。常规的使用方法请参考官方文档。
迷惑 (一). 懒加载的树,节点更新问题
- 官方文档里面更新树或者节点的方法如下:
-
这些方法在 非 懒加载树情况下,均没有问题。
-
但是: lazy load 模式下append 或 remove 后不更新 ,我最近业务需求需要操作懒加载的tree,更新append后发现效果,也很郁闷。关于这个问题:可以参考这个文章。可以解决部分业务场景问题。
-
我这边业务里面使用的更新树逻辑:每次数据更新,只更新引起数据改变的数据的父节点node,达到类似单条更新的效果【非真正意义的单条更新,因为业务需求 需要当前的 一片段 的 树的数据最新】
注释:单条数据【单个node】数据更新方法: 方法:通过getNode拿到节点,更新data即可:
let needOpeaterNode = (this.$refs.taskTree as any).getNode(keyPointId)
needOpeaterNode.data = XXX
版本一:每次更新需要先让更新数据节点模拟第一次加载清空,如果当前的 节点已展开,会出现 “先收起、后打开”的效果。卡顿感比较明显。
refreshNodeBy(keyPointId?: any) {
// 记录需要打开的节点
const nodeMap: any = (this.$refs.taskTree as any).store.nodesMap;
let needOpenId: any = [];
Object.values(nodeMap).forEach((ele: any) => {
if (ele.expanded) {
needOpenId.push(ele.data.keyPointId);
}
});
this.expandedKeys = needOpenId;
//开始更新树
this.$nextTick(async () => {
let node = (this.$refs.taskTree as any).getNode(keyPointId); // 通过节点id找到对应树节点对象
if (node) {
node.loaded = false;
node.expand(); // 主动调用展开节点方法,重新查询该节点下的所有子节点
return;
} else {
// 更新根节点
let node: any = this.$refs.taskTree;
let rootNode = node.root;
//更改根节点 loaded 属性 为 FALSE,然后调用打开节点方法,触发数据查询
rootNode.loaded = false;
rootNode.expand(); // 主动调用展开节点方法,重新查询该节点下的所有子节点
}
});
}
版本二:相对于版本1,只是修改了数据更新逻辑顺序,不再操作节点的打开状态,手动请求最新的数据后,利用源码里面提供的方法用最新数据渲染树。修改后。体验更流畅。
refreshNodeBy(keyPointId?: any) {
// 记录需要打开的节点
const nodeMap: any = (this.$refs.taskTree as any).store.nodesMap;
let needOpenId: any = [];
Object.values(nodeMap).forEach((ele: any) => {
if (ele.expanded) {
needOpenId.push(ele.data.keyPointId);
}
});
this.expandedKeys = needOpenId;
//开始更新树
this.$nextTick(async () => {
let needOpeaterNode = (this.$refs.taskTree as any).getNode(keyPointId); // 通过节点id找到对应树节点对象
let isRefreshRoot = false;
if (!needOpeaterNode) {
// 更新根节点
let node: any = this.$refs.taskTree;
needOpeaterNode = node.root;
isRefreshRoot = true;
}
//================= 主要修改代码================
let childs = needOpeaterNode.childNodes;
let newData = await this.getTaskList(
isRefreshRoot ? undefined : needOpeaterNode
);
//清除原来tree node挂载的数据节点。否则会导致数据被“拼接”处理
childs.splice(0, childs.length);
//调用源码 tree node方法,根据数据生成子节点
needOpeaterNode.doCreateChildren(newData);
//================= 主要修改代码================
});
}
迷惑 (二). element-plus Tree V2 虚拟化树形控件解决大数据渲染问题,为什么不能将这个组件下发兼容 vue2?
- 因为业务需求,我们需要做 树结构 的 一键展开 和 一键收起 逻辑。用 懒加载树 或 非 懒加载树显然会存在比较大的性能问题。百度之后,发现element-plus提供了虚拟树组件。但是不支持vue2,没有向下兼容。
没办法,自己找思路吧:
1)思路一【懒加载树】
- 将需求,修改为“打开下一级”。效果如下:
部分demo代码:
openNextLevel() {
let needOpen: any = [];
let allNode: any = this.$refs.taskTree.store.nodesMap;
Object.keys(allNode).forEach((ele: any) => {
if (!allNode[ele].isLeaf) {
needOpen.push(ele);
}
});
//TODO 正式代码需要去重
this.openKeys = [...this.openKeys, ...needOpen];
}
这种方案其实没有解决性能问题,只是一个比较大的性能开销分几次而已。治标不治本。
1)思路二【懒加载树】
暂无 ==》》 冥想中~~~