Vue 运行性能优化
函数式组件
标记组件为 functional
,这意味它是无状态 (没有响应式数据),无实例(没有 this
上下文)。
未优化的代码
<template> <div class="cell"> <div v-if="value" class="on"></div> <section v-else class="off"></section> </div> </template> <script> export default { props: ['value'] } </script>
优化完成的代码
<template functional> <div class="cell"> <div v-if="props.value" class="on"></div> <section v-else class="off"></section> </div> </template> <script> export default { props: ['value'] } </script>
拆分子组件
如果一个功能被多次使用,建议拆分为组件,组件的复用可以提高页面的渲染。
未优化的代码
<template> <div :style="{ opacity: number / 300 }"> <div>{{ heavy() }}</div> </div> </template> <script> export default { props: ['number'], methods: { heavy () { /* HEAVY TASK */ } } } </script>
优化完成的代码
<template> <div :style="{ opacity: number / 300 }"> <ChildComp/> </div> </template> <script> export default { props: ['number'], components: { ChildComp: { methods: { heavy () { /* HEAVY TASK */ } }, render (h) { return h('div', this.heavy()) } } } } </script>
本地变量
可以通过一个变量来保存 data
中的某个属性,比如 let msg = this.data.msg
,这样减少读取属性的时间。
未优化的代码
<template> <div :style="{ opacity: start / 300 }">{{ result }}</div> </template> <script> import { heavy } from '@/utils' export default { props: ['start'], computed: { base () { return 42 }, result () { let result = this.start for (let i = 0; i < 1000; i++) { result += heavy(this.base) } return result } } } </script>
优化的代码
<template> <div :style="{ opacity: start / 300 }"> {{ result }}</div> </template> <script> import { heavy } from '@/utils' export default { props: ['start'], computed: { base () { return 42 }, result () { const base = this.base let result = this.start for (let i = 0; i < 1000; i++) { result += heavy(base) } return result } } } </script>
复用DOM
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
未优化的代码
<template functional> <div class="cell"> <div v-if="props.value" class="on"> <Heavy :n="10000"/> </div> <section v-else class="off"> <Heavy :n="10000"/> </section> </div> </template>
优化完成的代码
<template functional> <div class="cell"> <div v-show="props.value" class="on"> <Heavy :n="10000"/> </div> <section v-show="!props.value" class="off"> <Heavy :n="10000"/> </section> </div> </template>
避免反复渲染
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题,但是在实际中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 <keep-alive>
元素将其动态组件包裹起来。
未优化的代码
<template> <div> <router-view/> </div> </template>
优化完成的代码
<template> <div> <keep-alive> <router-view/> </keep-alive> </div> </template>
延迟组件
延迟渲染组件,defer
的意思是 延迟,所以 deferred
特性的含义就是 延迟 到未来某个点再执行。
未优化的代码
<template> <div> <h2>I'm an heavy page</h2> <Heavy v-for="n in 10" :key="n"/> <Heavy class="super-heavy" :n="9999999"/> </div> </template>
优化完成的代码
<template> <div> <h2>I'm an heavy page</h2> <template v-if="defer(2)"> <Heavy v-for="n in 10" :key="n"/> </template> <Heavy v-if="defer(3)" class="super-heavy" :n="9999999"/> </div> </template> <script> import Defer from '@/mixins/Defer' export default { mixins: [ Defer() ] } </script>
deferred 特性的代码
export default function (count = 10) { return { data () { return { displayPriority: 0 } }, mounted () { this.runDisplayPriority() }, methods: { runDisplayPriority () { const step = () => { requestAnimationFrame(() => { this.displayPriority++ if (this.displayPriority < count) { step() } }) } step() }, defer (priority) { return this.displayPriority >= priority } } } }
时间分片
时间分片就是一个功能分多个阶段执行,确保页面能够正常渲染,需要使用到 requestAnimationFrame
方法。
虚拟滚动
对于渲染大量数据可以使用虚拟滚动,使用第三方提供的库 vue-virtual-scroller
,传送门。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论