主题
Vue2 常见优化手段
使用 key
通过循环生成的列表,应该给每个列表项一个稳定且唯一的值作为 key,这利于在列表变动时,尽量少的删除、新增、改动元素。
示例:
vue
<template>
<ul>
<!-- 使用 id 而不是 index 作为 key -->
<li v-for="(item, index) in items" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
使用冻结对象
对于一些不会变动的数据,使用 Object.freeze(obj)
冻结对象,它不会被"响应化"。
示例:
vue
<script>
const obj = { name: '张三' }
Object.seal(obj)
export default {
data: {
myObj: obj,
},
}
</script>
使用函数式组件
👉 函数式组件
提升虽然比较小,但是仍然有提升:
- 渲染时间减少。
- 减少内存消耗:普通组件会创建一个组件实例,而函数式组件不会创建实例。
使用计算属性
如果模板中某个数据会使用多次,并且该对象是通过计算得到的,使用计算属性 缓存 它,
非实时地绑定表单项
当使用 v-model
绑定一个表单项时,当用户改变表单项的状态时,它会随之改变数据,从而导致 vue
发生重新渲染(rerender
),这会带来一些性能开销。
可以通过使用 lazy
或不使用 v-model
的方式解决该问题,但要注意的是,这样可能会导致在某一个时间段内数据和表单项的值是不一致的!
保持对象引用稳定
在绝大部分情况下,vue
触发 rerender
的时机是其依赖的数据发生变化。
若数据没有发生变化,哪怕是给数据重新赋值了,vue
也是不会做出任何处理的。
参考 vue
源码(判断数据没有变化):
js
function hasChanged(x, y) {
if (x === y) {
return x !== 0 || 1 / x === 1 / y
} else {
return x === x || y === y
}
}
因此,如果需要,只要能保证组件的依赖数据不发生变化,组件就不会重新渲染:
- 对于原始类型,保持其值不变即可。
- 对于引用类型,保持其引用不变即可。
使用 v-show 代替 v-if
对于频繁切换显示状态的元素,使用 v-show
可以保证虚拟 dom 树的稳定,避免频繁地新增和删除元素,特别是对于哪些内部包含大量 dom 元素的节点!
使用 v-show
的关键点:
- 频繁切换显示状态。
- 内部包含大量 dom 元素。
延迟装载(defer)
JS 传输完成后,浏览器会开始执行 JS 构造页面。
但是可能一开始要渲染的组件太多了,不仅 JS 执行的时间长,而且执行完后浏览器要渲染的元素过多,从而导致页面白屏。
一个可行的方法就是 延迟装载组件,让组件按照指定的先后顺序依次一个一个地渲染出来。
提示
延迟状态是一个思路,本质就是利用了 requestAnimationFrame
事件分批渲染内容,它的具体实现是多种多样的。
例如:
vue
<template>
<div>
<child-component v-for="(item, index) in loadedComponents" :key="index" :name="item" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: { ChildComponent },
data() {
return {
loadedComponents: [], // 已渲染的组件
components: ['A', 'B', 'C', 'D', 'E'], // 需要渲染的组件
}
},
methods: {
renderNext(index) {
if (index >= this.components.length) return
requestAnimationFrame(() => {
this.loadedComponents.push(this.components[index]) // 逐个添加组件
this.renderNext(index + 1) // 递归渲染下一个组件
})
},
},
mounted() {
this.renderNext(0)
},
}
</script>
使用 keep-alive
keep-alive
主要用于 优化性能,避免组件频繁销毁和创建。
长列表优化
当一个列表数据量很大(如 1 万条数据)时,直接渲染所有数据会导致严重的性能问题:
- DOM 节点过多,导致浏览器渲染变慢
- 内存占用过高,页面变卡顿
- 滚动体验变差
解决方案就是 虚拟列表,它只渲染可视区域的数据,而不是整个列表。
虚拟列表的核心思想是:
- 可见区域渲染:只渲染视口内的少量 DOM 节点,未滚动到的部分不渲染。
- 占位填充:用
padding
或 transform: translateY()
来模拟完整高度,让滚动条正常工作。 - 滚动更新:监听
scroll
事件,动态更新可见数据。
可以自己实现虚拟列表组件,或者使用第三方库 vue-virtual-scroller。
优化打包体积
参考工程化,如:webpack、vite、rollup 等。