1.Vue 生命周期
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载 dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
2.Vue 生命周期函数
Vue 的生命周期共有 8 个阶段,即创建前/后、载入前/后、更新前/后、销毁前/销毁后,并对应地有很多钩子函数,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
3.Vue 生命周期图
4. Vue 生命周期进程
根据上面的图来分析 Vue 生命周期的进程:
1. 实例化 Vue(组件)对象,确定 this 指向 Vue 实例
2. 初始化事件(events)和生命周期(cycle)
3. beforeCreate
函数
这一阶段,虽然 Vue 对象已经创建,但是它的属性还没有绑定,诸如 data、computed 这些属性还没有赋值。所以 $el
,$data
以及 message
都是 undefined。
4. 初始化注入和响应
这一阶段,Vue 对象的属性注入绑定,完成属性赋值。
5. Created
函数
这一阶段可以访问数据,但是还没有挂载 dom,不能访问到 $el
。因为这个原因,此时改变数据不会触发 updated 函数。
6. 两次判断
这个阶段会进行两次判断:
- 判断对象是否有 el 选项
如果有则继续向下编译;如果没有则停止编译,也即停止生命周期,直到在实例上再次调用vm.$mount(el)
才会继续向下编译 - 判断 el 是否有 template 模板
如果有则将该模板编译为渲染函数,最后渲染出来;如果没有则直接调用 $el 的 outerHTML 进行渲染。另外,如果 Vue 对象中有渲染函数(render function),则它会优先于 template 进行渲染。
综上,优先级是:render function > template > outerHTML
7. beforeMount
函数
这个阶段,this.$el 有值,但是数据还没有挂载到页面上,`{{}}` 还没有被替换
8. 用 vue 对象的数据(属性)替换模板中的内容
9. mounted
函数
模板编译完成,数据挂载完毕,页面上已经能够看到正确的数据了。
10. beforeUpdate
函数
数据更新后首先触发该函数,但更新的只是数据,innerHTML 尚未更新
11. 虚拟 dom 重新渲染并打补丁
12. updated
函数
这一阶段,innerHTML 已经得到更新。
PS:这里解释一个问题。在 beforeUpdate 函数中访问 this.$el
,innerHTML
时得到的是旧数据,这是正常的;但访问 this.$el
的时候,得到的却是新数据,这是因为:
- console.log 是异步的,我们期望打印的时候是打印那一刻的快照,但实际上它不能做到这一点,所以在后面点击展开
this.$el
的内容时,实际上只能访问到最新更新的对象; this.$el
保存的是对象的引用。
13. beforeDestroy
函数
这一阶段,实例还没有销毁,仍然完全可用
14. 销毁实例
14. destroyed
函数
实例销毁之后调用该函数,使 Vue 实例指示的所有东西解绑定,所有的监听器被移除,所有的子实例销毁。
5.通过控制台观察生命周期的过程
<!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 : "Vue"
},
beforeCreate: function () {
console.group('beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red" , "el : " + this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
created: function () {
console.group('created 创建完毕状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
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 : "); 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 : "); 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 : "); console.log(this.$el);
console.log("%c%s", "color:red","el.outerHTML : " + this.$el.outerHTML);
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 : "); console.log(this.$el);
console.log("%c%s", "color:red","el.outerHTML : " + this.$el.outerHTML);
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>
第一次渲染,可以在控制台看到:
之后手动修改 message 的值为“Vue2”,可以在控制台看到:
这里注意之前提到的 log 异步的问题,看 outerHTML 可以知道 beforeUpdate 的时候视图实际上还没有重新渲染。