目录

卡顿假死

预研

开发

业务中使用

组件中引入

功能列表

使用


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
  }
}

功能列表

  1.  大数据量支持虚拟滚动
  2.  基本树形数据的展示
  3.  支持checkbox选择
  4.  支持懒加载
  5.  默认展开和默认选中
  6.  禁用节点
  7.  通过多种方式选中节点和获取选中的节点信息
  8.  支持自定义节点内容
  9.  支持节点过滤
  10.  非虚拟滚动下,支持手风琴模式
  11.  非懒加载时,支持节点拖拽

支持与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如下图所示:

github:https://github.com/wchbrad/vue-easy-treehttps://github.com/wchbrad/vue-easy-treehttps://github.com/wchbrad/vue-easy-tree

npm:https://www.npmjs.com/package/@wchbrad/vue-easy-treehttps://www.npmjs.com/package/@wchbrad/vue-easy-treehttps://www.npmjs.com/package/@wchbrad/vue-easy-tree


2021-12-23添加:

对于引入有问题的同学,可以参考这篇文章:从零开始使用vue-easy-tree_Brad_chao的博客-CSDN博客

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐