Vue的生命週期
Vue的生命週期是每個使用Vue框架的前端人員都需要掌握的知識,以此作為記錄。
Vue的生命週期就是vue例項從建立到銷燬的全過程,也就是new Vue() 開始就是vue生命週期的開始。Vue 例項有⼀個完整的⽣命週期,也就是從開始建立、初始化資料、編譯模版、掛載Dom -> 渲染、更新 -> 渲染、解除安裝 等⼀系列過程,稱這是Vue的⽣命週期。鉤子函式是Vue生命週期中每個階段對外開放讓程式設計師操作Vue的介面。Vue有8個鉤子函式。
beforeCreate( 建立前 )
這個時候,在例項被完成建立出來,el和data都沒有初始化,不能訪問data、method,一般在這個階段不進行操作。
beforeCreate() {
console.log('----beforeCreate----')
console.log(this.msg) //undefined
console.log(this.$el) //undefined
},
created( 建立後 )
這個時候,vue例項中的data、method已被初始化,屬性也被繫結,但是此時還是虛擬dom,真是dom還沒生成,$el 還不可用。這個時候可以呼叫data和method的資料及方法,created鉤子函式是最早可以呼叫data和method的,故一般在此對資料進行初始化。
created() {
console.log('----created----')
console.log(this.msg) //msg
console.log(this.$el) //undefined
},
beforeMount( 掛載前)
此時模板已經編譯完成,但還沒有被渲染至頁面中(即為虛擬dom載入為真實dom),此時el存在則會顯示el。在這裡可以在渲染前最後一次更改資料的機會,不會觸發其他的鉤子函式,一般可以在這裡做初始資料的獲取。
當vue例項中,el為掛載目標,未對el進行定義,則this.el顯示undefined,但頁面中存在template也能識別掛載目標,因為template可以被看成佔位符。如果對其進行定義則顯示<div id="app"></div>,故所以,beforeMount讀取不了真實的el,在mounted才能讀取到真實的el,因為el只有渲染完成後才會存在。這裡講的el是真實的el。在真實的el之前存在前,在beforeMount中的其實是頁面中的#app,是掛載的目標。
beforeMount() {
console.log('----beforeMount----')
console.log(this.msg) //msg
console.log(this.$el) //undefined
},
Mounted( 掛載後)
此時模板已經被渲染成真實DOM,使用者已經可以看到渲染完成的頁面,頁面的資料也是透過雙向繫結顯示data中的資料。 這例項建立期間的最後一個生命週期函式,當執行完 mounted 就表示,例項已經被完全建立好了,此時,如果沒有其它操作的話,這個例項,就靜靜的躺在我們的記憶體中,一動不動。
mounted() {
console.log('----mounted----')
console.log(this.msg) //msg
console.log(this.$el) //<div id="app"><span model="msg"></span></div>
},
建立Vue例項的示例
<template>
<div id="app">
<span :model="msg"></span>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
msg: 'msg',
}
},
beforeCreate() {
console.log('----beforeCreate----')
console.log(this.msg) //msg
console.log(this.$el) //undefined
},
created() {
console.log('----created----')
console.log(this.msg)
console.log(this.$el)
},
beforeMount() {
console.log('----beforeMount----')
console.log(this.msg)
console.log(this.$el)
},
mounted() {
console.log('----mounted----')
console.log(this.msg)
console.log(this.$el)
},
}
</script>
beforeUpdate(更新前)
更新前狀態(view層的資料變化前,不是data中的資料改變前),重新渲染之前觸發,然後vue的虛擬dom機制會重新構建虛擬dom與上一次的虛擬dom樹利用diff演算法進行對比之後重新渲染。只有view上面的資料變化才會觸發beforeUpdate和updated,僅屬於data中的資料改變是並不能觸發。
updated(更新後)
資料已經更改完成,dom也重新render完成。
更新例項
<template>
<div id="app">
<div style="height:50px"
ref="spanRef">{{msg}}</div>
<button @click="clickBtn"></button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
msg: 'msg',
}
},
methods: {
clickBtn() {
this.msg = 'newMsg'
},
},
beforeUpdate() {
console.log('----beforeUpdate----')
console.log(this.$refs.$el)
console.log(this.msg) //msg
},
updated() {
console.log('----updated----')
console.log(this.$refs.$el)
console.log(this.msg) //msg
},
}
</script>
新增一個按鈕,給按鈕繫結點選事件,點選後更新資料。
在這裡跟vue圖示有出入,vue圖示中說明在beforeUpdate階段,只有data中的資料改變,而試圖的還未更新,檢視中還是舊的資料,但在示例中,beforeUpdate鉤子函式列印el可看出試圖中的資料已更新。查閱資料後發現,檢視層的資料更新才會觸發beforeUpdate以及updated。如果data中的某資料更新,但這個資料並沒有繫結在檢視層,這個時候就不會觸發鉤子函式。但在思考後發現還是不對,上文所解釋的是,當檢視層所應用的data更新時,觸發鉤子函式。
這個時候壓力就來到了我這邊,百思不得其姐之後,我突然想到 console.log(this.$refs.$el)這個輸出程式碼,在給beforeUpdate中新增延時程式碼後我頓悟了,console.log(this.$refs.$el)輸出的是資料完成更新時候的el。
this.$el會等到資料更新完成才對el進行輸出。
beforeDestroy(銷燬前)
銷燬前執行($destroy方法被呼叫的時候就會執行),一般在這裡善後:清除計時器、清除非指令繫結的事件等等…’)
destroyed(銷燬後)
銷燬後 (Dom元素存在,只是不再受vue控制),解除安裝watcher,事件監聽,子元件。