标记组件为 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>
一般来说,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>
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重渲染导致的性能问题,但是在实际中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个
元素将其动态组件包裹起来。
未优化的代码
<template>
<div id="app">
<router-view/>
</div>
</template>
优化完成的代码
<template>
<div id="app">
<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
,传送门