问题背景
项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术(即不渲染这么多的节点)。
解决方案
如果是vue3,那么直接使用element-plus提供的Tree V2 虚拟化树形控件组件即可。但是因为这个项目是一个vue2的项目,并且它原先用的是iview的组件来实现的,我这边不可能因为这个优化就把项目升级到vue3,所以有两个解决思路: 1.从网上找轮子 2.自己造轮子(时间太紧,放弃) 。找了很久终于找到一个比较好用的轮子,分享给大家使用,以后有遇到相同问题的时候可以参考下。
解决过程:
使用vue-easy-tree来优化树组件(文档地址)
1.安装虚拟树组件,以及安装sass和sass-loader
npm i @fortawesome/fontawesome-free@6.7.2 -s
由于这个项目依赖了saas,所以要把这个也安装下
npm i sass@1.89.1 sass-loader@7.3.1 -D
2.导入使用
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.完整代码
<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-treeref="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>} {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:https://github.com/rui-rui-an/virtual_tree