问题背景
项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为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>
}
 
{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/...