Vue實例有一個完整的生命周期,即開始創建---》初始化數據---》編譯模板---》掛載DOM---》渲染---》更新---》渲染---》銷毀等一系列過程,這一系列過程我們稱之為Vue實例的生命周期,鈎子就是在某個階段給你一個做某些處理的機會。
先上一張圖來只管的感受一下Vue的生命周期:
Vue生命周期主要以下幾個鈎子函數:
1、beforeCreate():
我們在實例化Vue的時候(new Vue),會首先初始化事件和生命周期,然后會調用這個鈎子函數,這個鈎子函數我們一般不會使用它去做太多功能。
這個時候,數據data和el還沒有掛載到Vue實例上,只是一個空殼,是無法訪問到數據data和真實的dom掛載元素el的。
2、created():
在實例創建后,會掛載數據data和綁定事件。然后會調用created鈎子函數,所以此時,實例已經完成了基本配置。
這里可以使用數據data,也可以修改數據data,且這里的修改數據是不會觸發updated鈎子函數的。
一般可以在這里做數據初始化的操作,不過如果請求過多且全部都是同步請求的話,可能會導致界面出現短暫的空白阻塞,所以是否在這里初始化請求數據,看個人需求。
但是dom還是沒有掛載到界面,所以$el依舊是不可見的。
3、beforeMount():
實例基本配置完成后,會去判斷實例是否有掛載el對象,如果有的話,就繼續向下編譯,如果沒有的話,就停止編譯,即意味着停止了生命周期,直到我們在該實例上手動掛載el,即調用vm.$mount("#app")
這個鈎子函數,我們基本上也是不會去使用它的。
它的作用主要是用來檢查,Vue實例中有沒有自定義template參數選項,如果有的話,會將其作為模板template編譯成虛擬dom放到render函數中准備渲染;但是如果我們已經自定義了render函數,會使用我們定義的render函數的返回值渲染到界面;如果都沒有,就將掛載元素el的html作為模板template編譯。
可以看到自定義render函數優先級 > 自定義template參數選項 > 掛載元素el的outer HTML
此時,我們就可以理解,為啥要先去判斷是否有掛載el對象了,因為我們需要通過el找到對應的out template
找到實例或組件對應的模板,編譯成虛擬dom放入到render函數中,准備渲染,然后會執行beforeMount鈎子函數,這個函數中,虛擬dom已經創建完成,即將渲染。這里我們還可以修改data且不觸發updated鈎子函數,這將是我們不觸發updated鈎子函數去修改data的最后一次機會了,后面所有的修改都將觸發updated鈎子函數。
<div id='app'>{{a}}</div> new Vue({ data(){ return { a:100, } }, template:"<h1>{{a}}</h1>", render(createElement){ return createElement("h2",{ attrs:{ id:"aaa" }, style:{ border:"1px solid red" }, on:{ click(){ alert(1) } } },'this is a render fn') }, beforeMount(){ // 這里會去檢查我們是否有自定義render(),有的話,會將render函數的返回值渲染到app中,如果沒有render函數,會去查找是否有自定義template,有的話將template值渲染到app中 } })
4、mounted():
接下來render后,渲染出真實dom,然后執行mounted()鈎子函數。
此時,組件已經出現在頁面中,數據,真實dom都已經處理好了,事件也已經掛載好了,可以操作真實dom對象了。
這里修改數據data,會觸發updated鈎子,需要注意的是,vue中所有的數據渲染都是異步的,這里我們通過 this.$el.innerHTML 是拿不到更新后的內容的,需要通過vue.$nextTick 去獲取
<div id='app'>{{a}}</div> new Vue({ el:"#app", data(){ return { a:"hello" } }, mounted(){ this.a = 100; console.log(this.$el.innerHTML); this.$nextTick(()=>{
// 會在updated鈎子函數之后執行 console.log("nextTick->",this.$el.innerHTML) }) } });
5、beforeUpdate() 和 updated():
當組件和實例中的數據發生變化后,會立即執行beforeUpdate鈎子,然后vue的虛擬dom機制會重新創建新的虛擬dom,與上一次的虛擬dom樹利用diff算法進行對比后,重新渲染組件。
更新完成后,會執行updated鈎子,數據和組件都已經更新完成,這是可以操作更新后的dom
注意:updated()鈎子函數中不能再修改數據,否則會造成死循環
7、beforeDestroy():
當經過某種途徑調用$destroy()后(如組件銷毀,路由切換或者手動調用vm.$destroy()),在實例銷毀之前,會立即觸發beforeDestroy鈎子。
此時實例還是完全可用的。
一般在這里做一些清掃工作,如清除定時器,清除非指令綁定事件等等。
<div id="app"> <self-comp></self-comp> <div> <template> <div id="selfComp"> <button @click="destroy">銷毀</button> <h1>{{count}}</h1> </div> </template> Vue.component("selfComp",{ template:"#selfComp", data(){ return { count:1, } }, timer:null, methods:{ destroy(){ this.$destroy(); } }, mounted(){ this.$options.timer = setInterval(function(){ this.count+=1; }.bind(this),1000); }, beforeDestroy(){ clearInterval(this.$options.timer); } }) new Vue({}).$mount("#app")