前言
雖然現在網上有一大堆關於vue生命周期的文章,但我總覺得還是自己再來一遍理解更深,當然,我也看了很多關於vue生命周期的文章才寫出我自己的理解,不妥之處,不吝賜教!
官方圖解
首先,走流程,上官方圖解,注意,是官方圖解!
生命鈎子函數
什么叫鈎子函數?我認為,鈎子就是隨時可能或者有需要時掛到什么東西上,從而引發一些流血事件的發生。顯而易見,vue中的生命鈎子函數,就是隨時或者說在達到某一階段或條件時去觸發的函數,目的就是為了完成一些動作或者事件。需要注意的是,所有的生命周期鈎子自動綁定 this 上下文到實例中,因此你可以訪問數據,對屬性和方法進行運算。
通常我們所說的生命周期分為8個:分別為在初始化實例時,默認調用的beforeCreate、created、beforeMount、mounted這四個鈎子函數,還有當更新數據時,更新之前會觸發beforeUpdate這個鈎子函數,更新完成之后,會觸發updated這個鈎子函數;當vue的實例銷毀時,會調用beforeDestroy和destroyed這兩個鈎子函數。除此之外還有不常用的activated、deactivated、errorCaptured這三個鈎子函數,下面我會結合官方圖解逐一說一下。(我是不是很啰嗦啊)
過程
首先我們需要創建一個實例new Vue()
,也就是在這個過程當中,首先執行了init(init是vue組件里面默認去執行的),init Events & Lifecycle
后先調用了beforeCreate,所以此時事件已經好了,也能開始使用生命周期函數了,然后繼續init injections(注射) & reactivity(反應性)
,在實例創建完成后它會立即調用created。在這一步,實例已完成以下的配置:數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。所以在init的時候,事件已經調用了,我們在beforeCreate的時候千萬不要去修改data里面賦值的數據,最早也要放在created里面去做(添加一些行為)。
當created完成之后,它會去判斷instance(實例)里面是否含有“el”option(選項),如果沒有的話,它會等待我們調用vm.$mount(el)這個方法,然后執行下一步;如果有的話,直接執行下一步。緊接着會判斷是否含有“template”這個選項,如果有,把 template 解析成一個 render function。render 函數會用 template 中的 html 去覆蓋 html 中的 div 標簽。在使用 .vue 文件進行開發的過程中,是沒有 template 的,我們在 .vue 文件中寫的 template 都經過了 vue-loader 處理,直接變成了 render 函數,放在vue-loader 解析過的文件中;這樣做的好處,把 template 解析成 render 函數,比較耗時,vue-loader處理后,我們在頁面上執行代碼時,效率會變高。如果沒有,Compile el's outerHTML as template。
beforeMount在有了render函數的時候才會執行,此時vue實例的$el
和data都初始化了,但還是掛載之前為虛擬的dom節點。然后繼續執行render函數。當執行完render函數之后,也就是el被新創建的vm.$el
替換,並掛載到實例上去之后就會調用mounted這個鈎子,在mounted掛載完畢之后,這個實例就算是走完流程了,此時el也被掛載到了真實DOM上。但是它不會承諾所有的子組件也都一起被掛載。如果你希望等到整個視圖都渲染完畢,可以用vm.$nextTick()
。后續幾個鈎子函數,都是通過外部觸發進行的。
當數據更新變化時,beforeUpdate 執行,然后Virtual DOM re-render and patch
最后updated 執行。
當組件銷毀時,beforeDestroy 執行,然后Teardown watchers,child comonents and event listeners
,最后destroyed 執行。
然后說一下另外三個不常用的鈎子,首先activated、deactivated是和vue中一個原生的組件keep-alive有關系,當keep-alive組件激活時調用activated鈎子。keep-alive 組件停用時調用deactivated鈎子。鈎子errorCaptured是當捕獲一個來自子孫組件的錯誤時被調用。此鈎子會收到三個參數:錯誤對象、發生錯誤的組件實例以及一個包含錯誤來源信息的字符串。此鈎子可以返回 false 以阻止該錯誤繼續向上傳播。
現在大家可以用代碼測試一下鈎子函數的觸發順序,還有data數據和el渲染完畢的時間。
<div id="app">
<input type="text" v-model="msg">//測試數據更新時的鈎子
{{msg}}
</div>
let vm = new Vue({
el:"#app",
data: {
msg:"data數據",
},
methods:{
fn(){
this.msg="改變data數據"
}
},
beforeCreate(){
// 創建之前;無法獲取響應數據
console.log("beforeCreate","data:"+this.msg,"el:"+this.$el);
},
created(){
// 創建之后
console.log("created","data:"+this.msg,"el:"+this.$el);
},
beforeMount(){
// 掛載前
console.log("beforeMount","data:"+this.msg,"el:"+this.$el);
},
mounted(){
// 掛載后
console.log("mounted","data:"+this.msg,"el:"+this.$el);
},
beforeUpdate(){
// 數據更新之前
console.log("beforeUpdate","data:"+this.msg,"el:"+this.$el);
},
updated(){
// 數據更新完成之后;
console.log("updated","data:"+this.msg,"el:"+this.$el);
},
beforeDestroy(){
// 銷毀之前
console.log("beforeDestroy","data:"+this.msg,"el:"+this.$el);
},
destroyed(){
// 銷毀之后
console.log("destroyed","data:"+this.msg,"el:"+this.$el);
}
});
// vm.$destroy();//測試銷毀組件調用的鈎子
//測試結果
//初始化過程
beforeCreate data:undefined el:undefined
created data:data數據 el:undefined
beforeMount data:data數據 el:[object HTMLDivElement]
mounted data:data數據 el:[object HTMLDivElement]
//數據更新后
beforeUpdate data:data數據更新 el:[object HTMLDivElement]
updated data:data數據更新 el:[object HTMLDivElement]
//數據銷毀后
beforeDestroy data:data數據 el:[object HTMLDivElement]
destroyed data:data數據 el:[object HTMLDivElement]
其他一些總結
- beforecreate : 可以在這加個loading事件
- created :在這結束loading,還做一些初始數據的獲取,實現函數自執行
- mounted : 在這發起后端請求,拿回數據,配合路由鈎子做一些事情
- beforeDestroy: 你確認刪除XX嗎?
- destroyed :當前組件已被刪除,清空相關內容
如果有不當之處,請指出來哈!!!還有啊,內容可能有點啰嗦,有點亂,勿噴!!!謝謝