tree 树组件大数据卡顿问题处理

问题背景

项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术(即不渲染这么多的节点)。

解决方案

如果是vue3,那么直接使用element-plus提供的Tree V2 虚拟化树形控件组件即可。但是因为这个项目是一个vue2的项目,并且它原先用的是iview的组件来实现的,我这边不可能因为这个优化就把项目升级到vue3,所以有两个解决思路: 1.从网上找轮子 2.自己造轮子(时间太紧,放弃) 。找了很久终于找到一个比较好用的轮子,分享给大家使用,以后有遇到相同问题的时候可以参考下。

解决过程:

使用vue-easy-tree来优化树组件(文档地址

1.安装虚拟树组件,以及安装sass和sass-loader

vue 复制代码
npm i @fortawesome/fontawesome-free@6.7.2 -s

由于这个项目依赖了saas,所以要把这个也安装下

vue 复制代码
npm i sass@1.89.1 sass-loader@7.3.1 -D

2.导入使用

vue 复制代码
import VueEasyTree from '@wchbrad/vue-easy-tree'
import '@wchbrad/vue-easy-tree/src/assets/index.scss'

   components: {
    VueEasyTree
  },

3.替换el-tree来使用

注意:该组件和element-ui的tree组件的prop是一致的(所以使用的使用可以参考element的tree组件),但是加了height属性时就会开启虚拟列表

4.完整代码

vue 复制代码
<template>
  <div class="home">
    <div class="left_box">
      <!-- <el-tree :data="treeData" :props="props" ref="veTree" node-key="id" :default-expanded-keys="['Root']"
        class="op-tree" :render-content="treeRender"></el-tree> -->
        <vue-easy-tree
          ref="veTree"
          node-key="id"
          class="op-tree"
          height="calc(100vh - 110px)"
          :default-expanded-keys="['Root']"
          :data="treeData"
          :props="props"
          :render-content="treeRender"
        ></vue-easy-tree>
    </div>

  </div>
</template>

<script>
import treeData from './treeData'
import VueEasyTree from '@wchbrad/vue-easy-tree'
import '@wchbrad/vue-easy-tree/src/assets/index.scss'

export default {
  name: 'HomeView',
  components: {
    VueEasyTree
  },
  computed: {
  },
  data() {
    return {
      treeData: treeData,
      props: {
        children: 'children',
        label: 'title'
      },
      localFile: {
        title: '',
        nodeId: '',
        nodeType: '',
        pId: ''
      },
    }
  },
  created() {
    console.log('treeData', this.treeData)
  },
  methods: {
    treeRender(h, { data }) {
      // nodeType 'file','文件','dir','文件夹'
      return (
        <div class={this.localFile.nodeId === `${data.id === 'Root' ? '/' : data.id.replace('Root', '')}` ? 'active tree-item' : 'tree-item'}>
          <span on-click={() => { this.changeCode(data, `${data.nodeType}Detail`) }} class={this.localFile.nodeId === `${data.id === 'Root' ? '/' : data.id.replace('Root', '')}` ? 'colorBlue tree-item-title textOverflow' : 'tree-item-title textOverflow'}>
            {
              data.nodeType === 'file' ? <i class="fa fa-file"></i> : data.nodeType === 'dir' ? <i class="fa fa-folder-open"></i> : <span></span>
            }
            &ensp;
            {data.title}
          </span>
          <div class="button-group">
            {
              data.nodeType !== 'file'
                ? <tooltip content="新增" transfer placement="top">
                  <i class="fa fa-plus" on-click={() => { this.changeCode(data, 'add') }}></i>
                </tooltip> : <span></span>
            }
            {
              data.id !== 'Root'
                ? <tooltip content="修改" transfer placement="top">
                  <i class="fa fa-edit" on-click={() => { this.changeCode(data, 'modify') }}></i>
                </tooltip> : <span></span>
            }
            {
              data.id !== 'Root'
                ? <tooltip content="删除" transfer placement="top">
                  <i class="fa fa-trash" on-click={() => { this.changeCode(data, 'delete') }}></i>
                </tooltip> : <span></span>
            }
          </div>
        </div>
      )
    },
    changeCode(data = '', type) {
      this.view = ''
      this.$nextTick(() => {
        if (data.title && data.id) {
          this.localFile = {
            title: data.title,
            nodeId: `${data.id === 'Root' ? '/' : data.id.replace('Root', '')}`,
            nodeType: data.nodeType,
            pId: data.pId
          }
          type === `${data.nodeType}Detail` ? this.handleDetail(data.nodeType)
            : type === 'add' ? this.handleAdd()
              : type === 'modify' ? this.handleEdit()
                : type === 'delete' ? this.handleDelete() : ''
        } else {
          this.$Notice.warning({
            title: '提醒',
            desc: '找不到当前信息',
            duration: 3
          })
        }
      })
    },
    handleDetail(){
      console.log('详情')
    },
    handleEdit() {
      console.log('编辑')
    },
    handleAdd() {
      console.log('新增')
    },
    handleDelete() {
      console.log('删除')
    },
  },

};
</script>
<style lang="less" scoped>
.home {
  .left_box {
    width: 300px;
    height: 90vh;
    border: 1px solid #ccc;
    overflow-y: auto;
  }
}
</style>

总结

很多项目由于前期数据量不大,所以组件可以正常使用,但是当用户量或者数据量大了之后,浏览器就会变得卡顿,这种优化就是必须的。大家可以把代码拉下来运行对比下,没有使用虚拟列表技术的树真的很卡。

项目地址

gitHub:github.com/rui-rui-an/...

相关推荐
姜 萌@cnblogs42 分钟前
Saga Reader 0.9.9 版本亮点:深入解析核心新功能实现
前端·ai·rust
gnip1 小时前
实现elementplus官网主题切换特效
前端·css
Darling02zjh1 小时前
HTML5
前端·html·html5
成长ing121381 小时前
闪白效果
前端·cocos creator
Lazy_zheng1 小时前
React架构深度解析:从 Stack 到 Fiber,解决 CPU 和 I/O 瓶颈问题
前端·react.js·前端框架
张元清1 小时前
什么是React并发模式中的Tearing(撕裂)
前端·面试
AndyLaw1 小时前
统计字符数错一半,我被 length 坑了两次
前端·javascript
关羽的小刀1 小时前
Element-UI最新版暗藏Lodash漏洞?一次真实项目安全排查记录
前端
张志鹏PHP全栈1 小时前
Vue3第五天,ref 和 reactive的介绍和区别
前端·vue.js
郭邯1 小时前
import.meta对象是什么?
前端