一 分析
vue2时期PC端的UI库封神之作elementUI随着vue3的到来,发布了其续作elementPlus,并在2022年发布正式版本(根据更新日志的信息,全新的稳定版2.0.0于2022-02-07发布).点这里一键跳转至官方网站.
在elementPlus中,为了解决普通树形组件无法容纳大量数据的情况,提供了一款新的组件,来解决大量数据用树形组件展示问题,该组件便是我们今天要介绍的主角,Tree V2 虚拟化树形控件.
一般来说,在处理大量数据的渲染问题,我们一般采用两种方式,要么"时间分片",要么"虚拟列表",虚拟树组件则采用"虚拟列表"技术,避免一次性展示大量数据造成dom渲染过多最后导致浏览器崩溃问题.不过相对于普通的树组件,虚拟树组件虽然部分api相同,但是需要注意的是,虚拟树因为其"虚拟"的特性,要比普通树组件缺少一些功能,这些功能都主要与DOM操作有关.
在普通树组件中通过提供的node-click
事件,可以获得当前树的真实dom节点信息:
对比虚拟树组件
缺少是否选中属性,是否半选状态,以及子组件真实node节点信息;
基于上述对比,如果在实际项目中,想要实现普通树组件向虚拟树做迁移,需要注意所有对dom节点操作的功能都将失效.
例:获取子节点全选的父节点信息,其封装函数如下
getSimpleCheckedNodes(store) {
const checkedNodes = [];
const traverse = function(node) {
const childNodes = node.root ? node.root.childNodes : node.childNodes;
childNodes.forEach(child => {
if (child.checked) {
checkedNodes.push(child.data);
}
if (child.indeterminate) {
traverse(child);
}
});
};
traverse(store)
return checkedNodes;
}
....
// 调用
const tree = ref()
getSimpleCheckedNodes(tree.value.store);// el-tree的ref是tree
二 总结
以下是总结的关于虚拟树存在的问题及解决方法:
1 获取子节点全选的父节点信息
const getSimpleCheckedNodes = (checkedNodes)=>{
const traverse = (list) => {
list.forEach(item=>{
if(item.children && item.children.length){
item.children.forEach(childItem=>{
let checkedNodesIndex = checkedNodes.findIndex(e=>e && e.id == childItem.id)
if(checkedNodesIndex >= 0){
Reflect.deleteProperty(checkedNodes,checkedNodesIndex)
}
})
traverse(item.children)
}
})
}
traverse(checkedNodes)
return checkedNodes.filter(e=>e);
}
//调用
const tree = ref()
getSimpleCheckedNodes(tree.value.getCheckedNodes())
实现思路是调用官方的api获取所有勾选项,再利用父级勾选状态必然父级下的子也是勾选,然后从所有勾选集合中排除子级
2 只获取勾选子节点信息,不包含勾选的父级信息
const tree = ref()
tree.value.getCheckedNodes(false) //默认是true,传入false则只获取子节点勾选集合
3 异步获取数据情况下default-checked-keys无效问题
方法一:
利用setCheckedKeys
方法为树组件动态设置勾选情况
方法二:
设置一个开关,并作用于树组件上,使用 v-if
进行控制,在确保数据和勾选项的数据都获取到后再将开关置于true
,此方法同样适用于default-expanded-keys
属性无效问题.因虚拟树在渲染前就需要提供默认的勾选和展开情况用于计算虚拟列表的高度
4 default-expanded-keys默认展开异常
为虚拟树组件设置默认展开节点发现如果设置最外层的父级节点可以展开,而只设置里面的子节点却发现无法展开.在普通树组件中,如果设置了子级节点,会自动展开子级节点之上的所有父级节点,但是在虚拟树组件却无法做到,目前想到的做法是利用递归方式,拿到当前需要展开的子组件上层的父组件,一层层递归至最外层,拿到所有需要展开的层级.可以静待官方完善该方法.