Vue开发中一些可以提升性能的技巧
总结一些在Vue项目开发过程中可以提升性能的写法
避免模板中包含复杂计算
<template>
<div :style="{ width: width }">
{{ members.map(m => m.name.slice(0, 1)).join('、')}}
</div>
</template>
<script>
export default {
data() {
width: '100px',
members: [{ name: '王小明' }, ...]
}
}
</script>
div 依赖 width, members 两个响应式数据,任意一个数据变化都会触发组件的 render 和 patch,当 width 变化而 member 并没有发生变化时,依然会触发div中内容的计算,尤其是当width频繁变更时,会造成大量无意义的计算。这种计算牵扯到Vue2中的过滤器,Vue3中已移除,滥用过滤器很容易造成性能问题,所以应该避免封装计算过程复杂的过滤器,可以封装成通用的工具函数。
正确写法
<template>
<div :style="{ width: width }">
{{ brief }}
</div>
</template>
<script>
export default {
data() {
width: '100px',
members: [{ name: '王小明' }, ...]
},
computed: {
brief() {
return this.members.map(m => m.name.slice(0, 1)).join('、')
}
}
}
</script>
避免模板中重复的条件判断
<template>
<div>
<span
:style="{
width: width,
color: member.length > 20 ? '#333' : '#666'
}"
>
{{ members.length }}
</span>
<span
:class="[
member.length > 20 ? 'long' : 'short',
]">
人
</span>
</div>
</template>
<script>
export default {
data() {
width: '100px',
members: [{ name: '王小明' }, ...]
}
}
</script>
<style>
.long {
font-weight: bold;
color: #333;
}
.short {
color: #999;
}
</style>
模板中的重复的条件判断组件render时,一方面会导致很多无意义的判断,因为此时状态不可变,结果都是一致的。另一方面,条件依赖响应式数据,每次执行条件语句都会触发响应式数据的getter,执行依赖收集的相关逻辑
正确写法
<template>
<div
:class="[
member.length > 20 ? 'mode-long' : 'mode-short'
]"
>
<span class="count">{{ members.length }}</span>
<span class="desc">人</span>
</div>
</template>
<script>
export default {
data() {
width: '100px',
members: [{ name: '王小明' }, ...]
}
}
</script>
<style>
.mode-long .count{
color: #333;
}
.mode-short .count{
color: #666;
}
.mode-long .desc {
font-weight: bold;
color: #333;
}
.mode-short .desc {
color: #999;
}
</style>
优先使用局部变量
<template>
<div :style="{ width: width + 'px' }">
{{ brief }}
</div>
</template>
<script>
export default {
data() {
width: 100,
members: [{ name: '王小明', allowShort: true }, ...]
},
computed: {
brief() {
return this.members.map(m => {
return this.width < 200 && m.allowShort ? m.name.slice(0, 1) : m.name
}).join('、')
}
}
}
</script>
计算属性 brief 中,遍历 members 时,每次都会读取 data 中的 width,读取 width 是通过getter 获取,意味着每次都会触发 Vue 依赖收集相关的逻辑。
正确写法
<template>
<div :style="{ width: width + 'px' }">
{{ brief }}
</div>
</template>
<script>
export default {
data() {
width: 100,
members: [{ name: '王小明', allowShort: true }, ...]
},
computed: {
brief() {
const { width } = this
return this.members.map(m => {
return width < 200 && m.allowShort ? m.name.slice(0, 1) : m.name
}).join('、')
}
}
}
</script>
合理拆分组件
这里不做代码演示了,组件拆分粒度需要根据业务情况灵活去做,这是一个权衡和取舍问题。组件的创建是有开销的,过度的拆分意味着更多的内存消耗,每个组件都是一个vue实例,都会从创建到销毁的过程。
但对于一些频繁变更状态的dom,拆分成小的组件是最佳选择。vue的更新是以组件为粒度,拆分独立的组件可以减少 diff 的过程,同时也能减少每次重新渲染的dom数量。