Cookbook组件形式:优化 Vue 组件的运行时性能

2020-06-14 06:17:18易采站长站整理

我们可以更换为在一个可见节点的计算属性上进行遍历:


<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);
},