目录
源
卡顿假死
预研
开发
业务中使用
组件中引入
功能列表
使用
2022-08-18 兼容性更新
发现不少同学在使用过程中未安装babel插件导致jsx无法解析的问题,基于上述原因,现在移除了babel插件,已升级到v1.0.9版本,不会出现类似如下报错
(图片来自某位同学的报错截图)
向前兼容旧版本。
源
由于业务开发过程中有树形数据,因此需要用到tree树形组件,鉴于项目是基于vue的,前期的ui组件库选型就是element-ui,于是采用了el-tree组件。但在实际使用过程中出现了几个意外。
卡顿假死
server端返回全部数据时,渲染全量的tree组件时前端直接卡死,排查发现业务数据大部分子节点的量级在万以上。页面卡死这种事是要直接“掉脑袋”的,马上换成懒加载模式。
改成懒加载模式后,前两层节点的渲染和展开明显改善,用户体验也正常了,但是逐层点开测试时,发现还是存在问题,第三层有些节点超过2万节点,点击渲染仍然没有解决问题,查了下element-ui的issue,发现有不少人存在这个问题,且element-ui维护者尚未解决此问题,只能自己解决这个问题了。
预研
首先搜集了下github上现有的虚拟滚动tree组件,发现大部分都没有提供完善的功能,如checkbox、懒加载、节点过滤、节点拖拽等功能。基于业务开发角度,element-ui的功能是比较齐全的,因此想法是基于el-tree融合虚拟滚动vue-virtual-scroller(github上最多星的虚拟滚动组件)开发一个多功能虚拟滚动tree组件。
开发
将el-tree的相关scss样式文件和js文件从element-ui包中抽取出来,重新组合后形成无虚拟滚动功能的完整tree组件。
vue-virtual-scroller需要设置virtual-scroller的高度,于是添加在tree组件中添加height props,正好作为区分是否使用虚拟滚动的参数。按照vue-virtual-scroller文档说明,vue-virtual-scroller有两个主要子组件,RecycleScroller主要用于固定size的item展示,优点是重用组件和dom元素,以尽可能提高效率和性能;DynamicScroller一般用于可变size的item展示。当前情况下,tree的节点一般都是固定高度,因此使用RecycleScroller组件。传入key-field、items、item-size、buffer、v-slot 等props。
虚拟滚动情况下,也需要checkbox、节点过滤等功能,结合非虚拟滚动时的方法,提取公用方法到同一个js文件中
最后增加虚拟滚动vue文件,将el-tree的父子dom结构转成item-list结构,形成虚拟滚动tree。
业务中使用
打包成组件后,发布npm,通过
npm install @wchbrad/vue-easy-tree
或
yarn add @wchbrad/vue-easy-tree
安装
组件中引入
import VueEasyTree from "@wchbrad/vue-easy-tree";
// 样式文件,可以根据需要自定义样式或主题
import "@wchbrad/vue-easy-tree/src/assets/index.scss"
export default {
components: {
VueEasyTree
}
}
功能列表
- 大数据量支持虚拟滚动
- 基本树形数据的展示
- 支持checkbox选择
- 支持懒加载
- 默认展开和默认选中
- 禁用节点
- 通过多种方式选中节点和获取选中的节点信息
- 支持自定义节点内容
- 支持节点过滤
- 非虚拟滚动下,支持手风琴模式
- 非懒加载时,支持节点拖拽
支持与element-ui完全相同的主题样式更换,提供与element-ui相同的图标供选用
使用
<template>
<div class="ve-tree" style="height:calc(100vh - 20px)">
<!-- 不使用虚拟滚动时只需去掉height参数即可 -->
<vue-easy-tree
ref="veTree"
node-key="id"
show-checkbox
height="calc(100vh - 20px)"
:data="treeData"
:props="props"
></vue-easy-tree>
</div>
</template>
<script>
export default {
data() {
return {
props: {
label: "name",
children: "children"
},
treeData: []
};
},
created() {
const data = [],
root = 8,
children = 3,
base = 1000;
for (let i = 0; i < root; i++) {
data.push({
id: `${i}`,
name: `test-${i}`,
children: []
});
for (let j = 0; j < children; j++) {
data[i].children.push({
id: `${i}-${j}`,
name: `test-${i}-${j}`,
children: []
});
for (let k = 0; k < base; k++) {
data[i].children[j].children.push({
id: `${i}-${j}-${k}`,
name: `test-${i}-${j}-${k}`
});
}
}
}
this.treeData = data;
}
};
</script>
demo如下图所示: