},
watch: {
nodes: {
// nodes 改变时重新计算 status
handler() {
this.status = this.getStatus(this.nodes);
},
// 初始化 status
immediate: true,
},
// defaultExpandedKeys 改变时重新计算 status
defaultExpandedKeys() {
this.status = this.getStatus(this.nodes);
},
},
methods: {
getNodes(data, level = 0, parent = null) {
// ...
},
getStatus(nodes) {
// ...
},
// 展开或折叠节点时直接修改 status,并通知父组件
changeExpanded(key) {
console.time('expanded change');
const node = this.nodes.find(n => n.key === key); // 找到该节点
const newExpanded = !this.status[key].expanded; // 新的展开状态
// 递归该节点的后代节点,更新 status
const updateVisible = (n, visible) => {
n.children.forEach((child) => {
this.status[child.key].visible = visible && this.status[n.key].expanded;
if (child.children) updateVisible(child, visible);
});
};
this.status[key].expanded = newExpanded;
updateVisible(node, newExpanded);
// 触发节点展开状态改变事件
this.$emit('expanded-change', node, newExpanded, this.nodes.filter(n => this.status[n.key].expanded));
this.$nextTick(() => {
console.timeEnd('expanded change');
});
},
},
beforeCreate() {
console.time('first rendering');
},
mounted() {
console.timeEnd('first rendering');
},
};
使用 Tree 组件时,即使不传
default-expanded-keys ,节点也能正常地展开或收起。
<!-- 节点可以展开或收起 -->
<tree :data="data"></tree><!-- 配置默认展开的节点 -->
<tree
:data="data"
:default-expanded-keys="['1', '1-1']"
@expanded-change="handleExpandedChange"
>
</tree>
优化后的性能耗时如下。
first rendering: 91.48193359375ms
expanded change: 20.4287109375ms你可以通过改进后的示例 (Demo3) 来观察组件的性能损耗。
冻结数据
到此为止,Tree 组件的性能问题已经不是很明显了。为了进一步扩大性能问题,查找优化空间。我们把节点数量增加到 10000 个。
// 生成 10000 个节点
this.getRandomData(4, 1000)这里,我们故意制造一个可能存在性能问题的改动。虽然这不是必须的,当它能帮助我们了解接下来所要介绍的问题。
将计算属性
nodes 修改为在
data 的
watcher 中去获取










