vue性能
# vue 代码性能优化
# v-if / v-show
# v-if
切换过程中销毁和重建内部的事件监听和子组件
# v-show
DOM 元素的 display 样式
# 区别
v-if 有更高的切换消耗;v-show 有更高的初始渲染消耗;
# 场景
需要非常频繁地切换,使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
# 避免同时使用 v-if
v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。
# methods / computed / watch
# methods
可以定义方法来进行属性的修改,每次都会调用。
# computed
当依赖的数据发生改变时会调用,然后会更新视图, 起到缓存的作用,所以性能更好。
# watch
监听 的数据发生变化时可以做一系列事情,支持异步操作。
例如: 监听路由参数, 因为当路由参数发生变化时候, foo/:id 组件实例会被复用,生命周期不会重新走一遍,就可以用 watch 监听路由变化 做一些事情
// 三种方式分别实现:根据input的改变输出不同的数组。
new Vue({
el: "#app",
data() {
return {
input: "",
languages: [],
};
},
methods: {
handleSearch() {
this.languages = ["JavaScript", "Ruby", "Scala"].filter((item) =>
item.toLowerCase().includes(this.input.toLowerCase())
);
},
},
//
computed: {
filteredList() {
return this.languages.filter((item) => {
return item.toLowerCase().includes(this.input.toLowerCase());
});
},
},
watch: {
input: {
handler() {
this.languages = ["JavaScript", "Ruby", "Scala"].filter((item) =>
item.toLowerCase().includes(this.input.toLowerCase())
);
},
// 当 watch 一个变量的时候,初始化时并不会执行,添加immediate属性,这样初始化的时候也会触发
immediate: true,
},
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Object.freeze
Vue2.0 通过 Object.defineProperty 对数据进行劫持,实现双向绑定。
当有些时候就是纯粹的数据展示,不会有任何改变时,就不需要 Vue 来劫持数据。
使用 Object.freeze 冻结对象,能明显减少组件初始化的时间,一旦被冻结,就再也不能被修改了。
async created() {
const users = await axios.get("/api/users");
this.users = Object.freeze(users);
}
2
3
4
# 事件的销毁
组件销毁时,会自动清理解绑它的全部指令及事件监听器(只是自身的事件比如 @click 这种)
但是 addEventListene 等方式是不会自动销毁的。
所以需要在组件销毁时手动移除这些事件的监听,以免造成内存泄露。
// 常规写法
created() {
addEventListener('click', this.click, false)
},
beforeDestroy() {
removeEventListener('click', this.click, false)
}
// 优雅写法 hook 回调
this.$once("hook:beforeDestroy", () => {
window.removeEventListener("keydown", this.enterCallback);
});
2
3
4
5
6
7
8
9
10
11
12
# 图片懒加载
vue-lazyload 插件
# 本质实现原理
把图片的地址不赋值给 src 属性,赋值给 data 属性,当图片容器进入视野时,再赋值给 src
# 路由懒加载
单页应用首次加载一个 html 文件,每个路由都被打包成一个 js 文件,如果全部引入,首屏加载会很慢。
所以需要 懒加载,减少首屏加载的 js 文件。
// vue
// 先把组件的加载变成异步任务(promise)。
const Foo = () => Promise.resolve({ template: "<div>I am async!</div>" });
// 然后用webpack的import定义代码分块点。
import("./Foo.vue"); // 返回 Promise
// 结合起来就是定义一个能够被 Webpack 自动代码分割的异步组件:
const Foo = () => import("./Foo.vue");
// 在路由配置中什么都不需要改变,只需要像往常一样使用 Foo
routes: [{ path: "/foo", component: Foo }];
2
3
4
5
6
7
8
9
10
# 无限滚动列表
vue-virtual-scroll-list / vue-virtual-scroller 插件
原理:只需要渲染少部分区域的内容,减少重新渲染组件和创建 dom 节点的时间