Vue生命周期
Vue生命周期流程图
官方原图
自己对照的简单翻译了一下
生命周期的解析和应用
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。通俗说就是 Vue 实例从创建到销毁的过程,就是生命周期。
生命周期的解析
生命周期钩子 | 解析 |
---|---|
beforeCreate | 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。 |
created | 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用。 |
mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。 |
beforeUpdate | 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。 |
updated | 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。 |
activated | keep-alive 组件激活时调用。 |
deactivated | keep-alive 组件停用时调用。 |
beforeDestroy | 实例销毁之前调用。在这一步,实例仍然完全可用。 |
destroyed | Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 |
生命周期的应用
- beforecreate:完成实例初始化,初始化非响应式变量,this指向创建的实例,可以在这加个loading事件,
data
、computed
、watch
、methods
上的方法和数据均不能访问。 - created: 实例创建完成,完成数据(
data
、props
、computed
)的初始化 导入依赖项,可访问data
、computed
、watch
、methods
上的方法和数据,未挂载DOM
,不能访问$el
,$ref
为空数组。可在这结束loading,还做一些初始化,实现函数自执行, 可以对data
数据进行操作,可进行一些请求,请求不易过多,避免白屏时间太长。若在此阶段进行的DOM
操作一定要放在Vue.nextTick()
的回调函数中。 - berofeMount:有了
el
,编译了template
或者outerHTML
,能找到对应的template
,并编译成render
函数。 - mounted:完成创建
vm.$el
和双向绑定,完成挂载DOM
和渲染;可访问DOM
节点和$ref
,可在这发起后端请求,拿回数据,配合路由钩子做一些事情;可对DOM
进行操作。 - beforeUpdate:数据更新之前可在更新前访问现有的
DOM
,如手动移除添加的事件监听器; - updated :完成虚拟
DOM
的重新渲染和打补丁;组件DOM
已完成更新;可执行依赖的DOM
操作。注意:不要在此函数中操作数据,会陷入死循环的。 - activated:在使用
vue-router
时有时需要使用<keep-alive></keep-alive>
来缓存组件状态,这个时候created
钩子就不会被重复调用了,如果我们的子组件需要在每次加载的时候进行某些操作,可以使用activated
钩子触发。 - deactivated:
keep-alive
组件被移除时使用。 - beforeDestroy:在执行
app.$destroy()
之前可做一些删除提示,如:你确认删除XX吗? 可用于销毁定时器,解绑全局时间 销毁插件对象。 - destroyed:当前组件已被删除,销毁监听事件,组件,子实例也被销毁。这时组件已经没有了,你无法操作里面的任何东西了。
测试DEMO
<!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 : "Hello World!"
},
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)
},
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>
打开F12可以查看生命周期各个时期的钩子函数的状态:
由上图知:
- beforeCrete: 此时
$el
和data
都为undefined
,没有初始化。 - created: 创建后
data
初始化了,而$el
没有。 - brforeMount: 挂在之前,
$el
和data
都初始化了。 - mounted: Vue实例挂载完成了。
注意: beforeMount里是{{message}}
,mounted里是Hello World,说明挂载前$el
的值为'虚拟'的元素节点,挂载后'虚拟'的Dom
节点被真实的Dom
节点替换。
在控制台里输入app.message = '数据更新'
由此可见,当data数据变化时只会触发update。
在控制台里输入app.$destroy()
,然后再输入app.message = '数据销毁'
,数据已经不会再有变化。
执行完destroy操作后,data里的数据没有变化,但是Dom结构还存在,也就是Vue实例不再受控制了,完成了解耦。