vue 生命周期

关于 vue 的生命周期

关于 vue 的生命周期有不说的理由。文档读了几遍,项目也能跑起来,跟后端的交互也是妥妥的,生命周期的钩子也在使用,但对于整个生命周期的理解还是挺懵的。通过对生命周期系统的整理,自己对生命周期里面钩子的使用场景也弄的大概明白了。


生命钩子表 vue ^2.0

选项/生命周期钩子 类型/type 详细/功能
beforeCreate Function 实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created Function 实例创建完成后,数据观测 (data observer),属性和方法的运算,watch/event 事件回调。 挂载还没开始,$el 属性不可见
beforeMount Function 挂载之前,render 函数首次被调用。该钩子在服务器端渲染期间不被调用
mounted Function 挂载到实例后,$el 被新创建的 vm.$el 替换。不保证所有实例均在 document 中。 使用 vm.$nextTick 可以等到整个视图都渲染完毕。 该钩子在服务器端渲染期间不被调用。
beforeUpdate Function 数据更新时,组件 DOM 已经更新前。比如手动移除已添加的事件监听器。 该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行
updated Function 组件 DOM 已经更新,不保证所有自组件都一起被重绘。使用 vm.$nextTick 可等到整个视图都重绘完毕。 该钩子在服务器端渲染期间不被调用
activated Function keep-alive 组件激活时调用。 该钩子在服务器端渲染期间不被调用。
deactivated Function keep-alive 组件停用时调用。 该钩子在服务器端渲染期间不被调用。
beforeDestroy Function 实例销毁之前调用。在这一步,实例仍然完全可用。 该钩子在服务器端渲染期间不被调用。
destroyed Function Vue 实例销毁后调用。调用后,Vue 实例解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。
errorCaptured Boolean 当捕获一个来自子孙组件的错误时被调用。三个参数:错误对象、发生错误的组件实例,一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

生命周期探索

执行下面代码,对比每个钩子调用时的不同

1
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<!DOCTYPE html>

<html>
<head>
<title></title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
</head>
<body>

<div id="app">
<p>{{ message }}</p>
</div>

<script type="text/javascript">

var app = new Vue({
el: '#app',
data: {
message : "test vue life cycle"
},
beforeCreate: function () {
console.group('beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message); //undefined
},
created: function () {
console.group('created 创建完毕状态===============》');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function () {
console.group('beforeMount 挂载前状态===============》');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
mounted: function () {
console.group('mounted 挂载结束状态===============》');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
})
</script>

</body>
</html>

打印结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
beforeCreate 创建前状态===============》// el 和 data 并未初始化
el : undefined
data : undefined
message: undefined

created 创建完毕状态===============》// 完成了 data 数据的初始化,el没有
el : undefined
data : [object Object]
message: test vue life cycle

beforeMount 挂载前状态===============》// 完成了 el 和 data 初始化
el : [object HTMLDivElement]
<div id=​"app">​<p>​{{ message }}​</p>​</div>​ // 使用虚拟 dom 进行站位
data : [object Object]
message: test vue life cycle

mounted 挂载结束状态===============》// 完成挂载
el : [object HTMLDivElement]
<div id=​"app">​<p>​test vue life cycle​</p>​</div>​
data : [object Object]
message: test vue life cycle

虚拟 dom

虚拟 dom : 之前看到一个解释何为 虚拟 dom 的解释,感觉说的还蛮清楚的。

vue 实例和 DOM节点是两个分开的概念。
虚拟DOM节点,准确的说是vue实例的虚拟DOM节点,为啥是虚拟的,你可以对比beforeMount 和 mounted 这两个阶段的不同,你会发现,区别是:数据在beforeMount是没有渲染出来,使用的是占位符,可以理解为vue的虚拟DOM技术。

document.getElementById(“app-8”) 这个是HTML自带的节点,在beforeCreate阶段,也可以获取。不信,你试试。
只有到了beforeMount阶段,vue实例和DOM节点,才会扯上关系。

参考文献

生命周期探索 代码来源:
https://segmentfault.com/a/1190000008010666?utm_source=tag-newest#articleHeader7

感谢为探索 vue 付出努力的小伙伴们!