Vue生命周期,及父子組件生命周期順序


Vue生命周期,及父子組件生命周期順序

祭出官方圖: 

 

 

 Vue組件的生命周期主要為8個: beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed。

其實官方圖已經講明白很多了。包括各個階段之間做了些什么事情,但在掌握上終歸還是有一些模糊的地方。

下面做了一些梳理。

個人理解是主要分為三個階段:

  • 創建階段(注冊實例與掛載): beforeCreate、created、beforeMount、mounted
  • 運行階段:beforeUpdate、updated
  • 注銷階段:beforeDestroy、destroyed

以下代碼vue分別注冊了father和child組件,並在father中調用了child子組件來觀察他們的生命周期已經先后關系:

復制代碼
<!-- HTML部分 --> <!-- 父組件掛載 --> <div id="app"></div> <!-- child模板 --> <div class="child" @click="updateTest()"> i'm child <br /> data: {{data}} </div> <!-- father模板 --> <div class="father"> <button @click="changeDate()">{{tData}}</button> <button @click="destroyEl()">destroy</button> <child v-if="showChild"></child> I'm father </div>
復制代碼

 

 

復制代碼
/*JavaScript部分*/ /*child*/ var child = Vue.extend({ template: '#child', data(){   return {     data: 0   } }, methods:{ consoleinfo(){    console.log(this.data)}, updateTest(){     this.data += 1} }, beforeCreate(){ console.log('child-beforeCreate')}, created(){ console.log('child-created')}, beforeMount(){ console.log('child-beforeMount')}, mounted(){ console.log('child-mounted')}, beforeUpdate(){ console.log('child-beforeUpdate')}, updated(){ console.log('child-updated')}, beforeDestroy(){ console.log('child-beforeDestroy:') this.consoleinfo() }, destroyed(){ console.log('child-destroyed:') this.consoleinfo() } }) 
復制代碼

 

復制代碼
/*father*/ new Vue({ el: '#app', template:'#father', components:{child}, data(){ return { tData: 0, tCom: 'computed', showChild: true } }, computed:{ tComputed(){ return this.tCom} }, methods:{ consoleinfo(){ console.log('data: ' + this.tData) console.log('computed: ' + this.tComputed) console.log('el: ' + this.$el.outerHTML) }, changeDate(){ this.tData += 1 this.tCom = 'changeComputed' }, destroyEl(){         //this.showChild = false this.$destroy() } }, /** 創建階段 */ beforeCreate(){ console.log('beforeCreate:') this.consoleinfo() }, created(){ console.log('created:') this.consoleinfo() }, beforeMount(){ console.log('beforeMount:') this.consoleinfo() }, mounted(){ console.log('mounted:') this.consoleinfo() }, /** 運行階段 */ beforeUpdate(){ console.log('beforeUpdate:') this.consoleinfo() }, updated(){ console.log('updated:') this.consoleinfo() }, /** 注銷階段 */ beforeDestroy(){ console.log('beforeDestroy:') this.consoleinfo() }, destroyed(){ console.log('destroyed:') this.consoleinfo() } }) 
復制代碼

 

 

接下來看下各個生命周期控制台的輸出:

創建階段

beforeCreate:

在beforeCreate階段之前,vue做了init初始化的操作。操作包括:

—— 注冊一些vue默認的屬性方法事件(例如初始化vue的生命周期 —— 鈎子beforeCreate()等)

因此,在beforeCreate鈎子調用時,這些默認屬性方法事件已經注冊完成,但是vue實例中的data、computed、methods等都未定義:

—— 圖中函數consoleinfo(),報錯“not a function”’

Created:

beforeCreate與Created之間,實例將定義的data、methods等初始化並進行注入。

因此在Created階段,控制台已經能夠輸出data、computed值,包括控制台輸出的方法methods,這些值都已在當前father組件實例中定義生成了。

—— 此時只是在js操作了vue實例,dom中的元素還並未掛載,因此實例的$el並不能夠調用outerHTML,因此報錯。

——(雖然father組件調用了child組件,但是此時子組件child生命周期還未開始!這里要注意,只是father組件做初始化。子組件實例的生命周期什么時候開始,接下來的father生命周期里會涉及)

—— 由於data數據、methods方法等在created中已被定義,此時已經可以去做一些ajax請求后台數據

beforeMount

created與beforeMount之間,主要做了兩步工作:

1、判斷實例在dom中有沒有掛載的元素(el:‘#app’),只有掛載了才能夠繼續。掛載好后,實例即與掛載dom元素進行了綁定(占坑),實例中也可以進行引用;

2、渲染dom模板。渲染dom模板只是在內存中,並非是在HTML中的DOM結構中渲染,所以前台在這個階段時,組件對應的元素是沒有顯示的。(在調用 this.$el.outerHTML 后,控制台輸出 <div id="app"></div>)

—— 可以看到fathe組件的beforeMount時,child子組件的vue創建生命周期已經完成到mounted階段。說明father在執行dom模板渲染的時候,會監測模板中是否有自定義的vue子組件。如果有,就進入子組件的生命周期的創建階段,等到所有子組件的完成創建並掛載(mounted)到父組件的模板當中后。才能表明父組件在內存中的模板渲染完成。

—— 子組件的mounted階段雖然完成,但父組件仍在beforeMounte階段時。前台也看不見子組件渲染的效果,子組件只是完成了掛載到父組件的模板中了(控制台可以看到dom樹中的元素並未變化)。因此此刻在子組件的mounted階段直接調用一些方法(dom操作方法)可能會造成異常錯誤。為保險起見可在子組件中通過 $nextTick() 回調,等下一次DOM更新后再進行dom的操作。

—— 以上內存中渲染DOM可以了解一下Virtual DOM技術。

mounted

mounted階段表示,當前實例在內存中渲染的組件模板,已成功掛在到父組件orDOM樹中。

控制台可以看出DOM樹中元素已經發生變化。

—— 這個階段可以引用到元素,上面子組件提到過,一些情況下可以通過 $nextTick() 回調,避免一些意外錯誤。

運行階段

beforeUpdate

通過點擊左上角的button來改變father實例中的值

控制台

首先:只有實例中定義的變量綁定在了dom樹中,例如 <div>{{data}}<div>,當data發生改變,才會進入beforeUpdate階段。若dom樹中未綁定某變量,該變量只在實例中發生變化,那么就不會進入beforeUpdate階段!

我在代碼中綁定了tData變量,從beforeUpdate階段中可以看到,內部變量tData已經變化。頁面中DOM的 tData綁定值還未變化。

子組件的數據更新,不會引起父組件的beforeUpdate和updated生命周期鈎子

update

 

beforeUpdate和updated階段直接,vue根據變量更新后的數據在虛擬DOM中進行渲染(圖中re-render)。

而后進行頁面相應組件的更新。

控制台組件中值為1

注銷階段

若一個組件被判斷為銷毀,則進入相應的銷毀階段。一般情況下銷毀階段的調用有:

  • v-if = ‘false’ 
  • v-for 列表發生了變化(列表中部分item不再使用)
  • 實例調用 $destroy() 方法

beforeDestroy

進入該階段,表明實例已經接收到了被銷毀的指令。

在該階段,實例的屬性、方法、事件等仍然可以調用。

destroyed

在beforeDestroy與destroyed之間,組件開始注銷自己的屬性、方法、事件以及自己的子組件。只有等到所有都已注銷完成(子組件達到destroyed階段),父組件才能夠進入destroyed階段。看控制台。

以上注銷方法,是通過 $destroy() 來進行的,可以看到調用該方法后,頁面上的元素並未隨vue實例注銷。但是通過點擊button已經無法改變其button數組,說明實例已經不存在。

—— $destroy只是完全銷毀一個實例。清理它與其它實例的連接,解綁它的全部指令及事件監聽器。

—— 官方建議,$destroy 在多數情況下,還是用 v-if 和 v-for 來替代


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM