前言
Element-UI
el-tree
组件在大数据量的情况下进行编辑回显,会导致界面卡顿。为了解决这一问题,需要对el-tree
组件的编辑回显逻辑进行优化。本文将探讨如何在大数据量的情况下优化el-tree
组件的勾选回显性能。
问题分析
以下是模拟对5000+
条数据的编辑回显。
回显勾选耗时: 2285.337890625 ms
在回显勾选时,使用setChecked
设置勾选,每次都会触发源码中的getChildState
函数。该函数会循环改变子节点状态,并循环递归父级及父级下的子节点,主要是为了判断子节点是否还有勾选的状态,以判断父级或祖级设置半勾选还是未选中状态。每次子节点状态改变时,都会执行上述判断逻辑。
当循环去勾选节点时,就相当于执行了,5000+
次循环递归。导致循环次数指数级增长。
具体原因在element-ui el-tree大数据量取消勾选卡顿问题文章中有提及
解决方案
el-tree
组件提供了check-strictly
属性,该属性可以实现父子节点不关联。
在回显勾选时,只需要在开始勾选前对check-strictly
设为true
,在最后一个节点勾选前设为false
,让组件恢复成联动状态。分析起来是很简单,但真操作起来,还是有点繁琐的。
首先,check-strictly
属性,是用于TreeStore
类,且TreeStore
只初始化一次,所以动态改变check-strictly
是无效的。其次,想要动态改变check-strictly
,只能通过使用$refs
,获取组件实例来进行修改。
tree.vue 源码如下:
tree.vue 源码文件路径:packeages\tree\src\tree.vue
可以使用this.$refs.xxx.store.checkStrictly
,强制修改checkStrictly
。
PS:如果是懒加载el-tree
,使用this.$refs.xxx.checkStrictly
修改参数。
使用checkStrictly
效果预览:
5000+
回显勾选,效率提升99%
回显勾选耗时: 8.691162109375 ms
源码
<template>
<div>
<button @click="setCheck">勾选</button>
<el-tree
ref="tree"
height="600px"
:data="data"
@check="check"
show-checkbox
node-key="id"
:default-expanded-keys="[]"
:props="defaultProps">
</el-tree>
</div>
</template>
<script>
export default {
data() {
return {
data: [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}, {
id: 99,
label: 'asasa'
},
{
id: 88,
label: 'vcvcvc'
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}],
defaultProps: {
children: 'children',
label: 'label'
},
ids: [10, 8]
};
},
created() {
for (let i = 0; i < 5000; i++) {
this.ids.push(i + 100)
this.data[0].children.push({
id: i + 100,
label: i
})
}
},
methods: {
/**
* 勾选
**/
setCheck() {
console.time('勾选耗时')
let node = null
let obj = {};
let key = null
this.$refs.tree.store.checkStrictly = true; // 父子节点不关联
this.ids.map(item => {
node = this.$refs.tree.getNode(item)
key = node.parent.key || node.key
this.$refs.tree.setChecked(item, true, true)
// 用于,触发勾选函数,实现级联勾选
if (!obj[key]) {
obj[key] = node.data;
}
})
this.$refs.tree.store.checkStrictly = false; // 父子节点关联
// 触发勾选函数,实现级联勾选
this.$nextTick(() => {
for (let key in obj) {
this.$refs.tree.setChecked(obj[key], true);
}
});
console.timeEnd('勾选耗时')
},
check(a) {
let node = this.$refs.tree.getNode(a.id)
}
}
};
</script>