- 在实际项目开发中,当 tree 的某个节点大于 2000 个时,dom 渲染起来就非常慢,整个页面就会卡了起来.
- 基于 vue elementUI 来开发,用到了 InfiniteScroll 无限滚动 Tree 树形控件
- 来个 demo,具体看下 tree 子节点过多时的卡顿吧。
- 优化思路就是 前端刚开始只加载 10 个子节点,当滚动到底部时,再增加 10 个。
<div id="app">
<div
class="tree-box1"
:infinite-scroll-immediate="false"
v-infinite-scroll="load"
>
<el-tree
:data="curList"
v-loading="loading"
default-expand-all
:props="defaultProps"
@node-click="handleNodeClick"
></el-tree>
</div>
</div>
<style>
.tree-box1 {
height: 200px;
overflow: auto;
}
</style>
<script>
var Main = {
data() {
return {
loading: false,
curtreePageSize: 10,
allList: [],
curList: [],
defaultProps: {
children: 'children',
label: 'label',
},
}
},
methods: {
//滚动轴滚动最底部触发,tree的数组动态增加
load() {
if (this.allList.length) {
console.log('滚动')
this.curtreePageSize += 10
this.curList = this.sliceTree(this.allList, this.curtreePageSize)
}
},
handleNodeClick(data) {
console.log(data)
},
//tree数组的截取,默认截取10个,可以动态配置
sliceTree(data, len = 10) {
return [
{
label: '一级 1',
children: data.slice(0, len),
},
]
},
// 这是模拟跟后端的请求;用setTimeout模拟
impersonationRequest() {
this.loading = true
let arr = []
for (let i = 1; i < 4000; i++) {
arr.push({ label: `二级 1-${i}` })
}
setTimeout(() => {
this.allList = arr
this.curList = this.sliceTree(this.allList)
this.loading = false
}, 1000)
},
},
mounted() {
this.impersonationRequest()
},
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
</script>
- 好了基本完结,假如你不用el-tree自带的关键字过滤树节点的话。
又或者后端大佬愿意帮你写个接口,返回过滤后的tree给你;
不然的话,你就自己来实现了。el-tree本身的过滤是没有问题的,但是你用了懒加载,例如只加载了10个,它只会在你10个里面来进行搜索;你就需要自己写个算法来实现;
核心代码如下
/**
* data 为 tree数据
* name 为 筛选关键词
**/
const filterTree = (data, name) => {
// 当name数据为空时,返回默认的10个数据dom
if (!name) {
this.curList = this.sliceTree(this.allList)
return
}
const PrimaryNode = [...data] //数组
// 递归的方法,来判断
function traverse (node) {
node.forEach(v => {
//假如当前节点的属性满足 关键词,则将当前节点的visible属性设置为tree
v.visible = v.label.includes(name)
//如果纯在子节点,就递归调用本函数
if (v.children) {
traverse(v.children)
}
/* 当前节点visible为false, 且有子节点的再判断一次
假如子节点存在visible为true,则父节点的visible也设置成tree
这个涉及到递归的执行顺序问题,我们假如搜索的孙子节点三级,
const tree = [{
label:'一级',
children:[{
label: '二级',
children:[{
label: '三级',
}]
}]
}]
下面代码执行顺序是从最深处开始执行,然后渐渐到外层的,所以不会有问题;
*/
if (!v.visible && v.children) {
v.visible = v.children.some(child => child.visible)
}
})
}
//第二个函数的作用,就是过滤掉visible为false的选项。比较容易理解
function filterName (node) {
const newNode = node.filter(v => v.visible)
newNode.forEach(v => {
if (v.children) {
v.children = filterName(v.children)
}
})
return newNode
}
traverse(PrimaryNode)
const filterNode = filterName(PrimaryNode).slice(0,100)
if(filterNode.length) {
this.curList = [{
label: '一级 1',
children: filterNode
}]
}else {
this.curList = []
}
},