寫在前面:接觸Vue的時間不多码荔,進行一些項目實踐的時候砸脊,總會涉及到關(guān)于生命周期鉤子或多或少的使用是偷。因此覺得有必要單獨梳理一下相關(guān)的知識點拳氢,如有理解錯誤的地方懇請告知修改。
總體感知
首先貼一張Vue文檔給出的生命周期圖示蛋铆,并添加了一些注釋
Vue2.0的生命周期鉤子一共有10個馋评,同樣結(jié)合官方文檔作出了下表
生命周期鉤子 | 詳細 |
---|---|
beforeCreate | 在實例初始化之后,數(shù)據(jù)觀測(data observer) 和 event/watcher 事件配置之前被調(diào)用刺啦。 |
created | 實例已經(jīng)創(chuàng)建完成之后被調(diào)用留特。在這一步,實例已完成以下的配置:數(shù)據(jù)觀測(data observer)玛瘸,屬性和方法的運算蜕青, watch/event 事件回調(diào)。然而糊渊,掛載階段還沒開始右核,$el 屬性目前不可見。 |
beforeMount | 在掛載開始之前被調(diào)用:相關(guān)的 render 函數(shù)首次被調(diào)用渺绒。 |
mounted | el 被新創(chuàng)建的 vm.$el 替換贺喝,并掛載到實例上去之后調(diào)用該鉤子。如果 root 實例掛載了一個文檔內(nèi)元素宗兼,當 mounted 被調(diào)用時 vm.$el 也在文檔內(nèi)躏鱼。 |
beforeUpdate | 數(shù)據(jù)更新時調(diào)用,發(fā)生在虛擬 DOM 重新渲染和打補丁之前殷绍。你可以在這個鉤子中進一步地更改狀態(tài)染苛,這不會觸發(fā)附加的重渲染過程。 |
updated | 由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和打補丁主到,在這之后會調(diào)用該鉤子茶行。當這個鉤子被調(diào)用時贸呢,組件 DOM 已經(jīng)更新,所以你現(xiàn)在可以執(zhí)行依賴于 DOM 的操作拢军。 |
activated | keep-alive 組件激活時調(diào)用楞陷。 |
deactivated | keep-alive 組件停用時調(diào)用。 |
beforeDestroy | 實例銷毀之前調(diào)用茉唉。在這一步固蛾,實例仍然完全可用。 |
destroyed | Vue 實例銷毀后調(diào)用度陆。調(diào)用后艾凯,Vue 實例指示的所有東西都會解綁定,所有的事件監(jiān)聽器會被移除懂傀,所有的子實例也會被銷毀趾诗。 |
(除了beforeCreate和created鉤子之外,其他鉤子均在服務(wù)器端渲染期間不被調(diào)用蹬蚁。)
實際操作
我們來可視化的觀察一下生命周期鉤子函數(shù)執(zhí)行時狀態(tài)變化的情況
測試過程基于以下代碼執(zhí)行恃泪,引入vue.js后可直接執(zhí)行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="app">
<p>{{message}}</p>
<keep-alive>
<my-components msg="hello" v-if="show"></my-components>
</keep-alive>
</div>
</body>
<script>
var child = {
template: '<div>from child: {{msg}}</div>',
props: ['msg'],
data: function () {
return {
childMsg: 'child'
};
},
deactivated: function () {
console.log('component deactivated!');
},
activated: function () {
console.log('component activated');
}
};
var app = new Vue({
el: '#app',
data: function () {
return {
message: 'father',
show: true
};
},
beforeCreate: function () {
console.group('beforeCreate 創(chuàng)建前狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(state);
},
created: function () {
console.group('created 創(chuàng)建完畢狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(state);
},
beforeMount: function () {
console.group('beforeMount 掛載前狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
},
mounted: function () {
console.group('mounted 掛載結(jié)束狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
// this.message = 'change';
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
// this.message = 'change2';
},
updated: function () {
console.group('updated 更新完成狀態(tài)===============》');
var state = {
'el': this.$el,
'data': this.$data,
'message': this.message
}
console.log(this.$el);
console.log(state);
},
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>
首先來梳理一下結(jié)構(gòu):
1.我們創(chuàng)建了一個Vue根實例命名為app,將其掛載到頁面id為app的dom元素上犀斋。
2.局部注冊的一個組件child并在根實例中將其注冊使其可以在根實例的作用域中使用贝乎。
3.將子組件用<keep-alive> 包裹,為接下來的測試作準備叽粹。
在谷歌瀏覽器打開開發(fā)者工具览效,開始測試!
create 和 mounted 相關(guān)
測試效果圖如下:
根據(jù)測試結(jié)果虫几,可以看出
1.beforeCreate執(zhí)行時:data和el均未初始化锤灿,值為undefined
2.created執(zhí)行時:Vue 實例觀察的數(shù)據(jù)對象data已經(jīng)配置好,已經(jīng)可以得到app.message的值辆脸,但Vue 實例使用的根 DOM 元素el還未初始化
3.beforeMount執(zhí)行時:data和el均已經(jīng)初始化但校,但從{{message}}等現(xiàn)象可以看出此時el并沒有渲染進數(shù)據(jù),el的值為“虛擬”的元素節(jié)點
4.mounted執(zhí)行時:此時el已經(jīng)渲染完成并掛載到實例上
activated 和 destroyed相關(guān)
在前面的測試圖中每强,我們發(fā)現(xiàn)了activated周期鉤子已經(jīng)被觸發(fā)始腾,這是因為子組件my-components被<keep-alive> 包裹,隨el的掛載觸發(fā)空执。
??現(xiàn)在我們將此組件停用進行測試:由于子組件具有一個v-if指令v-if="show",因此我們可以通過將show的值置為false將其銷毀穗椅。
??控制臺輸入 app.show = false;測試結(jié)果如下:
由于在這里我們修改了data的值辨绊,所以會觸發(fā)beforeUpdate和updated鉤子,這里先不討論這一組鉤子匹表,我們看到deactivated鉤子已經(jīng)觸發(fā)门坷,表示<keep-alive>已經(jīng)停用宣鄙,符合預(yù)期結(jié)果。
現(xiàn)在我們對Vue實例進行銷毀默蚌,調(diào)用app.$destroy()方法即可將其銷毀冻晤,控制臺測試如下:
我們發(fā)現(xiàn)實例依然存在,但是此時變化已經(jīng)發(fā)生在了其他地方绸吸,根據(jù)官方文檔描述:Vue 實例指示的所有東西都會解綁定鼻弧,所有的事件監(jiān)聽器會被移除,所有的子實例也會被銷毀锦茁。
繼續(xù)測試攘轩,現(xiàn)在修改 data中的數(shù)據(jù)查看結(jié)果,如下:
這里我們將data中的message屬性改成了'world'码俩,發(fā)現(xiàn)dom并沒有進行相應(yīng)的響應(yīng)度帮,這證實了之前的說法。同樣稿存,如果你在子組件也加入destroyed鉤子笨篷,發(fā)現(xiàn)該鉤子也會被觸發(fā),這也證明了子實例也會被一起銷毀瓣履。這里的銷毀并不指代'抹去'冕屯,而是表示'解綁'。
updated相關(guān)
beforeUpdate和updated是最后一對周期鉤子了拂苹。
為了能看出測試的具體效果安聘,我們需要在原來的代碼上添加兩行代碼:
在c鉤子和updated鉤子中分別加上
console.log('beforeUpdate == ' + document.getElementsByTagName('p')[0].innerHTML);
控制臺輸入app.message = 'abc';效果如下:
我們發(fā)現(xiàn)beforeUpdate和updated觸發(fā)時,el中的數(shù)據(jù)都已經(jīng)渲染完成瓢棒,但根據(jù)beforeUpdate == father而updated == abc可知浴韭,只有updated鉤子被調(diào)用時候,組件dom才被更新脯宿。
結(jié)尾
到這里已經(jīng)總結(jié)完成了念颈,感覺只有理解的生命周期鉤子的使用,才能更好配合其他方法事件使用连霉。如果您發(fā)現(xiàn)錯誤的地方榴芳,請告訴我及時修改,謝謝跺撼!