文章目录
1.代码优化
2.项目优化
3.其它优化
4.总结
本文主要针对的是 vue 2.x 版本的性能优化,并且从代码优化 和 其他的优化去讲下在项目开发时应该注意的优化事项。
首先从项目代码层面方面
1.代码优化
v-if / v-show
这两个指令在不同场景的使用下,会有不同的性能损耗情况,首先简单了解下两者的区别。
- v-if 指令在编译阶段就会编译成一个三元运算符,通过条件进行渲染。当条件的值变化时,会触发对应的组件更新,即会经过 diff 算法, 组件初始化、渲染 vnode、patch等过程。
- v-show 指令相比于 v-if 的优势就是它在更新阶段仅仅更新了 DOM 的显隐,少去了很多性能开销的操作。但是初始化的时候会把所有条件节点都渲染出来
Hello World!
Vue yyds
Hello World!
Vue yyds
- 使用场景:
初始化阶段: v-if 性能优于 v-show
频繁更新阶段: v-show 性能优于 v-if
v-for 和 v-if
避免把这两个指令放在同一个节点
因为 v-for 指令的优先级比 v-if 高,所以两个指令混用的话会导致每次节点render的结果都带上了条件渲染。当数据量和节点复杂的时候,就会有明显的性能差。
当我们要循环节点和条件判断的时候,我们可以先对数据进行处理后再进行 v-for 渲染,如下例子:
{{item.name}}
{{item.name}}
computed: {
filters () {
return this.list.filter(item => item.count > 10)
}
}
从上面例子不难看出,每个 v-for 节点处就加了 key 唯一标识,这也是提升性能的一个小点。使用 key 时,vue会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
keep-alive
部分场景可以使用 keep-alive 进行组件缓存
keep-alive 包裹的组件在经过渲染后的 vnode 以及 DOM 都会被缓存起来,然后下次再次渲染该组件的时,直接从缓存中拿到对应的 vnode 和 DOM 并且进行渲染,并不需要再走一次组件初始化,render 和 patch 等一系列流程,减少了 script 的执行时间,性能更好。
v-slot:slotName / slot="slotName"
vue 2.6
版本,可以使用 v-slot:slotName 的语法代替 slot="slotName"
- 旧的写法在更新时多了一个父组件更新的过程,而新的写法由于直接更新子组件,就会更加高效,性能更好,所以推荐始终使用语法 v-slot:slotName
函数式组件
vue 2.x 的版本,需要DOM层复用的情况且场景相对简单时,可以用 函数式组件 代替普通组件
函数式组件生成的是普通的 vnode,不会存在递归子组件的过程,所以会减少一定程度的性能开销
场景:我在多个页面都复用了一个页面渲染的组件,不需要一些复杂的操作,只需要根据传参进行条件渲染或者循环渲染等、就可以用如下的例子去进行组件的编写
Hello World
Hi~
- {{item.name}}
子组件拆分
除开代码维护的层面,从性能方面,组件的拆分也是有好处的。
- 因为vue 的更新是组件力度,如果组件中有数据发生变化,就会执行 render 函数生成新的 vnode 和旧的 vnode 进行 diff。哪怕这个数据只影响到一个元素渲染,其他元素也需要在 diff 过程中进行比较。极端情况是假设这个大组件里面有个倒计时。
- 如果组件拆分得当的话,大部分的数据改动只会影响到子组件本身进行 diff ==> 渲染。所以合理得对这种大组件进行拆分,应用的更新效率会更高。
例如:
{{ heavy() }}
响应式数据优化
data的优化
vue 在组件实例初始化的时候会对data进行响应式处理,能够减少一个数据就是减少一点点的性能开销。而且一些常量数据不应该在data里面进行定义,简单总结为以下三点:
减少无用的data数据
减少数据被observer
数据尽量扁平化
局部变量缓存响应式数据
先直接看对比代码
// 优化前
// ··········
computed: {
base () {
return 42
},
result () {
let result = this.start
for (let i = 0; i < 1000; i++) {
result += Math.sqrt(Math.cos(Math.sin(this.base))) + this.base * this.base + this.base + this.base * 2 + this.base * 3
}
return result
},
}
// 优化后
// ·········
computed: {
base () {
return 42
},
result ({ base, start }) {
let result = start
for (let i = 0; i < 1000; i++) {
result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3
}
return result
},
}
优化前每次调用 this.base
的时候,由于它是个响应式数据,每次都会调用都会触发它的 getter
,进而执行依赖收集等逻辑。
优化后先把 this.base
缓存到局部变量,后面重复调用的时候就不会频繁的触发到 getter
的逻辑处理
computed
计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 数据 还没有发生改变,多次访问 计算属性会立即返回之前的计算结果,可以极大提升性能。
例如:
{{count}}
2.项目优化
路由懒加载
在vue-router的配置文件里,定义一个能够被 Webpack 自动代码分割的异步组件
const Hello = () => import('//hello.vue')
const router = new VueRouter({
routes: [
{ path: '/hello', component: Hello },
{ path: '/world', component: import('//world.vue') }
]
})
组件按需加载
以 element-ui
为例子,有些项目用ui组件库的时候使用的并不多,可以按需加载适当优化项目的体积
import {Button} from 'element-ui'
Vue.use(Button)
3.其它优化
1.图片懒加载
2.节流 / 防抖
3.长列表的虚拟滚动
4.总结
1.减少没必要的渲染机制
2.减少全量加载,适当的懒加载
3.正确的使用vue的每个api,本身vue这个框架就对性能方面做了很多处理,正常使用就不会出现性能瓶颈