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/...

相关推荐
zwjapple3 小时前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20205 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem6 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊6 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术6 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing6 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止7 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall7 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴7 小时前
简单入门Python装饰器
前端·python
袁煦丞8 小时前
数据库设计神器DrawDB:cpolar内网穿透实验室第595个成功挑战
前端·程序员·远程工作