我们可以更换为在一个可见节点的计算属性上进行遍历:
<li
v-for="node in visibleNodes"
:key="node.key"
class="tree-node"
:style="{ 'padding-left': `${node.level * 16}px` }"
>
...
</li><script>
export {
// ...
computed: {
visibleNodes() {
return this.nodes.filter(node => this.status[node.key].visible);
},
},
// ...
}
</script>
优化后的性能耗时如下:
first rendering: 194.7890625ms
expanded change: 204.01904296875ms你可以通过改进后的示例 (Demo2) 来观察组件的性能损耗,相比优化前有很大的提升。
双向绑定
在前面的示例中,我们使用
.sync 对
expanded-keys 进行了“双向绑定”,其实际上是 prop 和自定义事件的语法糖。这种方式能很方便地让 Tree 的父组件同步展开状态的更新。但是,使用 Tree 组件时,不传
expanded-keys ,会导致节点无法展开或折叠,即使你不关心展开或折叠的操作。这里把
expanded-keys 作为外界的副作用了。
<!-- 无法展开 / 折叠节点 -->
<tree :data="data"></tree>这里还存在一些性能问题,展开或折叠某一节点时,触发父组件的副作用更新
expanded-keys 。Tree 组件的
status 依赖了
expanded-keys ,会调用
this.getStatus 方法获取新的
status 。即使只是单个节点的状态改变,也会导致重新计算所有节点的状态。我们考虑将
status 作为一个 Tree 组件的内部状态,展开或折叠某个节点时,直接对
status 进行修改。同时定义默认的展开节点
default-expanded-keys 。
status 只在初始化时依赖
default-expanded-keys 。
export default {
props: {
data: Array,
// 默认展开节点
defaultExpandedKeys: {
type: Array,
default: () => [],
},
},
data() {
return {
status: null, // status 为局部状态
};
},
computed: {
nodes() {
return this.getNodes(this.data);
},










