1、vue的生命周期
2焙蹭、實(shí)際操作
下面我們?cè)趯?shí)際的代碼執(zhí)行過(guò)程中理解父子組件生命周期創(chuàng)建過(guò)程以及鉤子函數(shù)執(zhí)行的實(shí)時(shí)狀態(tài)變化。
測(cè)試基于下面的代碼,引入vue.js文件后即可執(zhí)行祭芦。(打開(kāi)頁(yè)面后,再按一次刷新會(huì)自動(dòng)進(jìn)入debugger狀態(tài))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
</style>
</head>
<body>
<div id="app">
<p>{{message}}</p>
<keep-alive>
<my-components :msg="msg1" v-if="show"></my-components>
</keep-alive>
</div>
</body>
<script src="../../node_modules/vue/dist/vue.js"></script>
<script>
var child = {
template: '<div>from child: {{childMsg}}</div>',
props: ['msg'],
data: function() {
return {
childMsg: 'child'
}
},
beforeCreate: function () {
debugger;
},
created: function () {
debugger;
},
beforeMount: function () {
debugger;
},
mounted: function () {
debugger;
},
deactivated: function(){
alert("keepAlive停用");
},
activated: function () {
console.log('component activated');
},
beforeDestroy: function () {
console.group('beforeDestroy 銷毀前狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
},
destroyed: function () {
console.group('destroyed 銷毀完成狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
},
};
var vm = new Vue({
el: '#app',
data: {
message: 'father',
msg1: "hello",
show: true
},
beforeCreate: function () {
debugger;
},
created: function () {
debugger;
},
beforeMount: function () {
debugger;
},
mounted: function () {
debugger;
},
beforeUpdate: function () {
alert("頁(yè)面視圖更新前");
},
updated: function () {
alert("頁(yè)面視圖更新后");
},
beforeDestroy: function () {
console.group('beforeDestroy 銷毀前狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
},
destroyed: function () {
console.group('destroyed 銷毀完成狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
},
components: {
'my-components': child
}
});
</script>
</html>
3.1憔鬼、生命周期調(diào)試
首先我們創(chuàng)建了一個(gè)Vue實(shí)例vm龟劲,將其掛載到頁(yè)面中id為“app”的元素上。
3.1.1轴或、根組件的beforeCreate階段
可以看出昌跌,在調(diào)用beforeCreate()函數(shù)時(shí),只進(jìn)行了一些必要的初始化操作(例如一些全局的配置和根實(shí)例的一些屬性初始化)照雁,此時(shí)data屬性為undefined蚕愤,沒(méi)有可供操作的數(shù)據(jù)。
3.1.2饺蚊、根組件的Created階段
調(diào)用Created()函數(shù)萍诱,在這一步,實(shí)例已完成以下的配置:數(shù)據(jù)代理和動(dòng)態(tài)數(shù)據(jù)綁定(data observer)污呼,屬性和方法的運(yùn)算裕坊, watch/event 事件回調(diào)。然而燕酷,掛載階段還沒(méi)開(kāi)始籍凝,$el 屬性目前不可見(jiàn)周瞎。
3.1.3、根組件的beforeMount階段
在調(diào)用boforeMount()函數(shù)前首先會(huì)判斷對(duì)象是否有el選項(xiàng)饵蒂。如果有的話就繼續(xù)向下編譯声诸,如果沒(méi)有el選項(xiàng),則停止編譯苹享,也就意味著停止了生命周期双絮,直到在該vue實(shí)例上調(diào)用vm.$mount(el)
在這個(gè)例子中,我們有el元素得问,因此會(huì)調(diào)用boforeMount()函數(shù),此時(shí)已經(jīng)開(kāi)始執(zhí)行模板解析函數(shù)囤攀,但還沒(méi)有將$el元素掛載頁(yè)面,頁(yè)面視圖因此也未更新宫纬。在標(biāo)紅處焚挠,還是 {{message}},這里就是應(yīng)用的 Virtual DOM(虛擬Dom)技術(shù)漓骚,先把坑占住了蝌衔。到后面mounted掛載的時(shí)候再把值渲染進(jìn)去。
3.1.4蝌蹂、子組件的beforeCreate噩斟、Created、beforeMount孤个、Mounted階段
在父組件執(zhí)行beforeMount階段后剃允,進(jìn)入子組件的beforeCreate、Created齐鲤、beforeMount階段斥废,這些階段和父組件類似,按下不表给郊。beforeMount階段后牡肉,執(zhí)行的是Mounted階段,該階段時(shí)子組件已經(jīng)掛載到父組件上淆九,并且父組件隨之掛載到頁(yè)面中统锤。
由下圖可以知道,在beforeMount階段之后炭庙、Mounted階段之前跪另,數(shù)據(jù)已經(jīng)被加載到視圖上了,即$el元素被掛載到頁(yè)面時(shí)觸發(fā)了視圖的更新煤搜。
3.1.5、子組件的activated階段
我們發(fā)現(xiàn)在子父組件全部掛載到頁(yè)面之后被觸發(fā)唧席。這是因?yàn)樽咏M件my-components被<keep-alive> 包裹擦盾,隨$el的掛載被觸發(fā)嘲驾。如果子組件沒(méi)有被<keep-alive>包裹,那么該階段將不會(huì)被觸發(fā)迹卢。
3.1.6辽故、父組件的mounted階段
mounted執(zhí)行時(shí):此時(shí)el已經(jīng)渲染完成并掛載到實(shí)例上。
至此腐碱,從Vue實(shí)例的初始化到將新的模板掛載到頁(yè)面上的階段已經(jīng)完成誊垢,退出debugger。下面我們來(lái)看一下deactivated症见、beforeUpdate喂走、updated、beforeDestroy谋作、destroyed鉤子函數(shù)芋肠。
3.2、deactivated遵蚜、beforeUpdate帖池、updated階段
由生命周期函數(shù)可知:當(dāng)數(shù)據(jù)變化后、虛擬DOM渲染重新渲染頁(yè)面前會(huì)觸發(fā)beforeUpdate()函數(shù)吭净,此時(shí)視圖還未改變睡汹。當(dāng)虛擬DOM渲染頁(yè)面視圖更新后會(huì)觸發(fā)updated()函數(shù)。
我們不妨改變vm.show = false寂殉,當(dāng)修改這個(gè)屬性時(shí)囚巴,不僅會(huì)觸發(fā)beforeUpdate、updated函數(shù)不撑,還會(huì)觸發(fā)deactivated函數(shù)(因?yàn)閗eep-alive 組件停用時(shí)調(diào)用)文兢。我們不妨想一下deactivated函數(shù)會(huì)在beforeUpdate后還是updated后調(diào)用。
我們?cè)诳刂婆_(tái)輸入vm.show = false焕檬。得到三者的調(diào)用順序分別為beforeUpdate姆坚、deactivated、updated实愚。我們可以知道的是deactivated函數(shù)的觸發(fā)時(shí)間是在視圖更新時(shí)觸發(fā)兼呵。因?yàn)楫?dāng)視圖更新時(shí)才能知道keep-alive組件被停用了。
3.3腊敲、beforeDestroy和destroyed鉤子函數(shù)間的生命周期
現(xiàn)在我們對(duì)Vue實(shí)例進(jìn)行銷毀击喂,調(diào)用app.$destroy()方法即可將其銷毀,控制臺(tái)測(cè)試如下:
我們發(fā)現(xiàn)實(shí)例依然存在碰辅,但是此時(shí)變化已經(jīng)發(fā)生在了其他地方懂昂。
beforeDestroy鉤子函數(shù)在實(shí)例銷毀之前調(diào)用。在這一步没宾,實(shí)例仍然完全可用凌彬。
destroyed鉤子函數(shù)在Vue 實(shí)例銷毀后調(diào)用沸柔。調(diào)用后,Vue 實(shí)例指示的所有東西都會(huì)解綁定铲敛,所有的事件監(jiān)聽(tīng)器會(huì)被移除褐澎,所有的子實(shí)例也會(huì)被銷毀(也就是說(shuō)子組件也會(huì)觸發(fā)相應(yīng)的函數(shù))。這里的銷毀并不指代'抹去'伐蒋,而是表示'解綁'工三。
銷毀時(shí)beforeDestory函數(shù)的傳遞順序?yàn)橛筛傅阶樱琩estory的傳遞順序?yàn)橛勺拥礁浮?/p>
4先鱼、一些應(yīng)用鉤子函數(shù)的想法
在created鉤子中可以對(duì)data數(shù)據(jù)進(jìn)行操作俭正,這個(gè)時(shí)候可以進(jìn)行ajax請(qǐng)求將返回的數(shù)據(jù)賦給data。
雖然updated函數(shù)會(huì)在數(shù)據(jù)變化時(shí)被觸發(fā)型型,但卻不能準(zhǔn)確的判斷是那個(gè)屬性值被改變段审,所以在實(shí)際情況中用computed或match函數(shù)來(lái)監(jiān)聽(tīng)屬性的變化,并做一些其他的操作闹蒜。
在mounted鉤子對(duì)掛載的dom進(jìn)行操作寺枉,此時(shí),DOM已經(jīng)被渲染到頁(yè)面上绷落。
在使用vue-router時(shí)有時(shí)需要使用<keep-alive></keep-alive>來(lái)緩存組件狀態(tài)姥闪,這個(gè)時(shí)候created鉤子就不會(huì)被重復(fù)調(diào)用了,如果我們的子組件需要在每次加載或切換狀態(tài)的時(shí)候進(jìn)行某些操作砌烁,可以使用activated鉤子觸發(fā)筐喳。
所有的生命周期鉤子自動(dòng)綁定 this 上下文到實(shí)例中,所以不能使用箭頭函數(shù)來(lái)定義一個(gè)生命周期方法 (例如 created: () => this.fetchTodos())函喉。這是導(dǎo)致this指向父級(jí)避归。
5、 小結(jié)
- 加載渲染過(guò)程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
- 子組件更新過(guò)程
父beforeUpdate->子beforeUpdate->子updated->父updated
- 父組件更新過(guò)程
父beforeUpdate->父updated
- 銷毀過(guò)程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed