Vue實(shí)例有一個(gè)完整的生命周期江解,也就是說從開始創(chuàng)建、初始化數(shù)據(jù)徙歼、編譯模板犁河、掛在DOM、渲染-更新-渲染魄梯、卸載等一系列過程桨螺,我們稱為Vue 實(shí)例的生命周期(鉤子函數(shù))
附上網(wǎng)上找的一張圖解釋
當(dāng)我們 new vue 的時(shí)候,這些函數(shù)就會(huì)自動(dòng)執(zhí)行
生命周期鉤子的11個(gè)階段:
創(chuàng)建:
beforeCreate -- 數(shù)據(jù)初始化前
created -- 數(shù)據(jù)初始化之后
beforeMount -- 數(shù)據(jù)準(zhǔn)備渲染
Mounted -- 數(shù)據(jù)渲染完成
運(yùn)行:
beforeUpdata -- 數(shù)據(jù)更新前
updated -- 數(shù)據(jù)更新
銷毀:
beforeDestroy -- 結(jié)束之前執(zhí)行
destroyed -- 執(zhí)行結(jié)束
緩存:
activated -- 組件激活時(shí)執(zhí)行
deactivated -- 組件停用時(shí)執(zhí)行
錯(cuò)誤處理
errorCaptured -- 錯(cuò)誤處理機(jī)制
構(gòu)建vue實(shí)例
var vm = new Vue({
el:"#app",
data:{
circle:"生命周期"
},
beforeCreate -- 數(shù)據(jù)初始化前
在實(shí)例初始化之后,數(shù)據(jù)觀測(cè)和event|watcher事件配置之前使用,
這個(gè)時(shí)期,this變量還不能使用,在data下面的數(shù)據(jù)和methods下面的方法,watcher中的事件都獲取不到酿秸。
可以在這里加一個(gè)loading事件,在實(shí)例加載的時(shí)候觸
beforeCreate(){
console.group("beforeCreate 創(chuàng)建狀態(tài),初始化前");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log(this.$el);//undefined
console.log("%c%s","color:skyblue","el:"+this.$el);//el:undefined
console.log("%c%s","color:green","data:"+this.$data);//data:undefined
console.log("%c%s","color:blue","message:"+this.circle);//message:undefined
},
created -- 數(shù)據(jù)初始化之后
實(shí)例已經(jīng)創(chuàng)建完成之后被調(diào)用灭翔,在這一步,實(shí)例已經(jīng)完成以下的配置辣苏,數(shù)據(jù)觀測(cè)缠局,屬性和方法的運(yùn)算,event|watcher事件回調(diào);但是,掛載階段還沒有開始,$el屬性還不可見,這個(gè)時(shí)候可以操作vue實(shí)例中的數(shù)據(jù)和各種方法.但是還不能對(duì)DOM節(jié)點(diǎn)進(jìn)行操作
初始化完成時(shí)的事件寫在這里考润,比如在這里結(jié)束loading事件,異步請(qǐng)求也可以在這里調(diào)用
created(){
console.group("created 創(chuàng)建狀態(tài),初始化后");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:undefined
console.log(this.$el);//undefined
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
beforeMount -- 數(shù)據(jù)準(zhǔn)備渲染
在掛載開始之前被調(diào)用读处,相關(guān)的render函數(shù)首次被調(diào)用
這個(gè)時(shí)候可以獲取到DOM節(jié)點(diǎn),但還不能進(jìn)行操作
beforeMount(){
console.group("beforeMount 創(chuàng)建狀態(tài),準(zhǔn)備渲染");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log(this.$el);//<div id="app" >...</div>
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
Mounted -- 數(shù)據(jù)渲染完成
el 被新創(chuàng)建的vm.$el
替換并掛載到實(shí)例上去之后調(diào)用這個(gè)鉤子糊治,如果root實(shí)例掛載了一個(gè)文檔內(nèi)元素,當(dāng)Mounted被調(diào)用時(shí),vm. $el
也在文檔中罚舱。
掛載完畢井辜,DOM節(jié)點(diǎn)被渲染到文檔中,DOM操作可以正常進(jìn)行
mounted(){
console.group("mounted 創(chuàng)建狀態(tài),渲染完成");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log(this.$el);//<div id="app" >...</div>
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
beforeUpdata -- 數(shù)據(jù)更新前
數(shù)據(jù)更新時(shí)調(diào)用管闷,發(fā)生在虛擬 DOM 打補(bǔ)丁之前粥脚。這里適合在更新之前訪問現(xiàn)有的 DOM,比如手動(dòng)移除已添加的事件監(jiān)聽器包个。
這里獲取到data的數(shù)據(jù)是已經(jīng)更新之后的數(shù)據(jù)刷允,但還沒渲染到文檔流中冤留,所以如果在這里獲取DOM節(jié)點(diǎn),得到的是未更新的數(shù)據(jù)树灶。
beforeUpdata(){
console.group("beforeUpdata 執(zhí)行狀態(tài),數(shù)據(jù)更新前");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log(this.$el);//<div id="app" >...</div>
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
updated -- 數(shù)據(jù)更新
由于數(shù)據(jù)更改導(dǎo)致的虛擬 DOM 重新渲染和打補(bǔ)丁纤怒,在這之后會(huì)調(diào)用該鉤子。當(dāng)這個(gè)鉤子被調(diào)用時(shí)天通,組件 DOM 已經(jīng)更新泊窘,所以你現(xiàn)在可以執(zhí)行依賴于 DOM 的操作。然而在大多數(shù)情況下像寒,你應(yīng)該避免在此期間更改狀態(tài)烘豹。如果要相應(yīng)狀態(tài)改變,通常最好使用計(jì)算屬性或 watcher取而代之诺祸。
數(shù)據(jù)更新已經(jīng)完成
updated(){
console.group("updated 執(zhí)行狀態(tài),數(shù)據(jù)更新");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log(this.$el);//<div id="app" >...</div>
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
在這里綁定了一個(gè)按鈕携悯,改變數(shù)據(jù)
更新前 beforeUpdata:
點(diǎn)擊更新后 updated :
beforeDestroy -- 結(jié)束之前執(zhí)行
在實(shí)例銷毀之前調(diào)用,實(shí)例仍然完全可用序臂,這一步還可以用this來獲取實(shí)例蚌卤,一般在這一步做一些重置的操作,比如清除掉組件中的定時(shí)器 和 監(jiān)聽的dom事件
beforeDestroy(){
console.group("beforeDestroy 銷毀狀態(tài),銷毀前執(zhí)行");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log(this.$el);
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
destroyed -- 執(zhí)行結(jié)束
在實(shí)例銷毀之后調(diào)用奥秆,調(diào)用后逊彭,所以的事件監(jiān)聽器會(huì)被移出,所有的子實(shí)例也會(huì)被銷毀构订,該鉤子在服務(wù)器端渲染期間不被調(diào)用
destroyed(){
console.group("destroyed 銷毀狀態(tài),銷毀完成");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log(this.$el);
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:生命周期
},
activated 和 deactivated(組件激活時(shí)和停用時(shí)執(zhí)行)
這兩個(gè)鉤子需要配合配合<keep-alive><keep-alive/>
來使用
keep-alive
的作用會(huì)緩存不活動(dòng)的組件實(shí)例侮叮,而不是銷毀它們。當(dāng)組件在<keep-alive>
內(nèi)被切換悼瘾,activated
和deactivated
這兩個(gè)生命周期鉤子函數(shù)將會(huì)被對(duì)應(yīng)執(zhí)行囊榜。
在這里我搭建了一個(gè)腳手架,新建2個(gè)子組件亥宿,1個(gè)父組件
子組件A內(nèi)容
<template>
<div>
<div>componentA</div>
<button @click="show=!show" >componentA事件</button>
<div v-if='show'>componentA-2</div>
<div v-else>componentA-1</div>
</div>
</template>
<script>
export default {
name: 'componentA',
comments: {},
data() {
return {
show: true,
circle:'生命周期'
}
},
activated() {
console.group("activated 組件激活時(shí)執(zhí)行 ");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log(this.$el);//<div id="app" >...</div>
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:undefined
},
deactivated() {
console.group("deactivated 組件停用時(shí)執(zhí)行");
console.log("%c%s","color:pink",this);//this指向vue的實(shí)例
console.log(this.$el);//<div id="app" >...</div>
console.log("%c%s","color:skyblue","el:"+this.$el);//el:[object HTMLDivElement]
console.log("%c%s","color:green","data:"+this.$data);//data:[object Object]
console.log("%c%s","color:blue","message:"+this.circle);//message:undefined
}
}
</script>
<style>
</style>
子組件B內(nèi)容
<template>
<div>
<div>componentB</div>
</div>
</template>
<script>
export default {
name: 'componentB',
compnents: {},
data() {
return {}
}
}
</script>
<style>
</style>
父組件內(nèi)容
<template>
<div id="box">
<button @click="active='componentA'">componentA</button>
<button @click="active='componentB'">componentB</button>
<keep-alive>
<component :is='active' ></component>
</keep-alive>
</div>
</template>
<script>
import Vue from 'vue'
import componentA from '@/components/componentA'
import componentB from '@/components/componentB'
export default{
components:{
componentA,
componentB
},
data(){
return{
active:'componentB'
}
}
}
</script>
<style>
</style>
輸出
這里看到當(dāng)A組件被點(diǎn)擊激活時(shí)就觸發(fā)activated
鉤子卸勺,點(diǎn)擊B組件開啟A組件關(guān)閉時(shí)deactivated
鉤子就觸發(fā)執(zhí)行。
這里也能看出在keep-alive
里A組件的數(shù)據(jù)也被緩存起來烫扼,第二次觸發(fā)的時(shí)候組件狀態(tài)沒有被重新改變
errorCaptured -- 錯(cuò)誤處理機(jī)制
當(dāng)捕獲一個(gè)來自子孫組件的錯(cuò)誤時(shí)被調(diào)用曙求。此鉤子會(huì)收到三個(gè)參數(shù):錯(cuò)誤對(duì)象、發(fā)生錯(cuò)誤的組件實(shí)例以及一個(gè)包含錯(cuò)誤來源信息的字符串映企。此鉤子可以返回 false 以阻止該錯(cuò)誤繼續(xù)向上傳播
1.默認(rèn)情況下悟狱,如果全局的 config.errorHandler定義,所有的錯(cuò)誤仍會(huì)發(fā)送它堰氓,因此這些錯(cuò)誤仍然會(huì)向單一的分析服務(wù)的地方進(jìn)行匯報(bào)
如果一個(gè)組件的繼承或父級(jí)從屬鏈路中存在多個(gè) errorCaptured 鉤子挤渐,則它們將會(huì)被相同的錯(cuò)誤逐個(gè)喚起。
2.如果此 errorCaptured 鉤子自身拋出了一個(gè)錯(cuò)誤双絮,則這個(gè)新錯(cuò)誤和原本被捕獲的錯(cuò)誤都會(huì)發(fā)送給全局的 config.errorHandler浴麻,不能捕獲異步promise內(nèi)部拋出的錯(cuò)誤和自身的錯(cuò)誤
3.一個(gè) errorCaptured 鉤子能夠返回 false 以阻止錯(cuò)誤繼續(xù)向上傳播得问。本質(zhì)上是說“這個(gè)錯(cuò)誤已經(jīng)被搞定了且應(yīng)該被忽略”。它會(huì)阻止其它任何會(huì)被這個(gè)錯(cuò)誤喚起的 errorCaptured 鉤子和全局的 config.errorHandler
在全局組件main.js中使用
import Vue from 'vue'//引入Vue框架
import router from './router'//引入路由
Vue.config.errorHandler = function (err, vm, info) {
// #處理錯(cuò)誤信息, 進(jìn)行錯(cuò)誤上報(bào)
// #err錯(cuò)誤對(duì)象
// #vm Vue實(shí)例
// #`info` 是 Vue 特定的錯(cuò)誤信息白胀,比如錯(cuò)誤所在的生命周期鉤子
// #只在 2.2.0+ 可用
console.log("%c%s","color:red","#err錯(cuò)誤對(duì)象:",err)
console.log("%c%s","color:blue","#vm Vue實(shí)例:",vm)
console.log("%c%s","color:green","#`info` 是 Vue 特定的錯(cuò)誤信息椭赋,比如錯(cuò)誤所在的生命周期鉤子:",info)
}
然后在子組件中隨意寫入一個(gè)錯(cuò)誤的信息
mounted () {
a // 直接定義一個(gè)錯(cuò)誤的變量 a
},
輸出
當(dāng)這個(gè)鉤子檢測(cè)到組件中發(fā)生錯(cuò)誤時(shí)就被調(diào)用。通過err
, vm
, info
這3個(gè)參數(shù)輸出
#err錯(cuò)誤對(duì)象
#vm Vue實(shí)例
#info
是 Vue 特定的錯(cuò)誤信息或杠,比如錯(cuò)誤所在的生命周期鉤子
總結(jié)一下:
beforecreate:實(shí)例剛剛創(chuàng)建出來哪怔,data等屬性方法都不能獲取,loading事件可以放在這里向抢。
created:實(shí)例初始化完成认境,data等屬性方法也初始化完成,但還沒有開始編譯挟鸠,可以在這里結(jié)束loading叉信,可以發(fā)送請(qǐng)求,拿數(shù)據(jù)艘希。硼身!注意一下,因?yàn)樵谶@里還沒有渲染頁面覆享,如果獲取的數(shù)據(jù)過多佳遂,會(huì)造成有一段空白頁面的延遲。
beforemount :屬性方法等已經(jīng)編譯完成撒顿,但還沒掛載丑罪。
mounted:這里所有的屬性方法已經(jīng)完成掛載。
beforeUpdate:這個(gè)獲取的數(shù)據(jù)是最新的值凤壁,但dom還是舊值
updated:dom更新完成吩屹。
beforedestroy:消亡前,用來清除定時(shí)器
destroy:已消亡拧抖,也能用來清除定時(shí)器
destroyed:實(shí)例完全銷毀
activated:可以用來初始化數(shù)據(jù)
deactivated:在緩存里能用來代替beforedestroy
和destroy
errorCaptured :能快速找到報(bào)錯(cuò)的組件位置煤搜,還能解決滿屏紅等視覺沖擊
問題:
如果當(dāng)在子組件里寫了一個(gè)定時(shí)器,子組件被銷毀后唧席,定時(shí)器還是會(huì)繼續(xù)執(zhí)行擦盾,所以要使用beforedestroy
和destroyed
,組件銷毀后袱吆,清除定時(shí)器。
<keep-alive>
包裹動(dòng)態(tài)組件時(shí)距淫,會(huì)緩存不活動(dòng)的組件實(shí)例绞绒,而不是銷毀它們,所以在<keep-alive>
中的所有組件不會(huì)觸發(fā)beforedestroy
和 destroyed
這兩個(gè)鉤子函數(shù)
關(guān)于created
和 activated
的區(qū)別
created
是頁面初始化時(shí)才觸發(fā)的函數(shù)榕暇,vue的優(yōu)勢(shì)在于不需要刷新或重啟頁面蓬衡,所以created
只會(huì)觸發(fā)一次喻杈。而activated
是只要頁面組件被激活就會(huì)執(zhí)行