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

问题背景

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

解决方案

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

解决过程:

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

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

vue 复制代码
npm i @fortawesome/[email protected] -s

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

vue 复制代码
npm i [email protected] [email protected] -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/...

相关推荐
wandongle几秒前
HTML面试整理
前端·面试·html
liucan233几秒前
JS执行速度似乎并不比Swift或者C语言慢
前端·ios
一只小风华~3 分钟前
HTML前端开发:JavaScript 常用事件详解
前端·javascript·html
Revol_C5 分钟前
【调试日志】我只是用wangeditor上传图片而已,页面咋就崩溃了呢~
前端·vue.js·程序员
天天码行空9 分钟前
GruntJS-前端自动化任务运行器从入门到实战
前端
smallzip10 分钟前
node大文件拷贝优化(显示进度)
前端·性能优化·node.js
mouseliu11 分钟前
python之二:docker部署项目
前端·python
要加油哦~22 分钟前
css | class中 ‘.‘ 和 ‘:‘ 的使用 | 如,何时用 &.is-selected{ ... } 何时用 &:hover{...}?
前端·css
不浪brown1 小时前
开源!矢量建筑白模泛光特效以及全国77个大中城市的矢量shp数据获取!
前端·cesium
山有木兮木有枝_1 小时前
JavaScript 数据类型与内存分配机制探究
前端