拼搏30天VUE.js之Vue 實體的生命週期(Part3)
生命週期函式示意圖:
注,上图来自于@老马自嘲的《Vue入门系列之Vue实例详解与生命周期》一文。著作权归作者所有。
創建一個vue實例的四個過程:
注,上图来自于@Airen的博客的《Vue 2.0的学习笔记: Vue实例和生命周期》一文。著作权归作者所有。
注:上图来自@浅白的《Vue生命周期》一文。示例也参考此文。著作权归作者所有。
beforeCreate : 實例初始化立即叫用,這時還未創建實例,所以任何 Vue 實體中的設定(例如: data )都還未配置。
created : 完成創建實例,這時 Vue 實體中的配置除了 $el 外已全部配置,而 $el要在掛載模板後才會配置。
beforeMount : 在 Vue 實體中的定義被掛載到目標元素之前叫用,這時的 $el 會是還未被 Vue 實體中的定義渲染的初始設定模板。
mounted : Vue 實體上的設置已經安裝上模板,這時的 $el 是已經藉由實體中的定義渲染而成的真正的頁面。
beforeUpdate : 當實體中的 data 產生變化後或是執行 vm.$forceUpdate() 叫用,這時的頁面還未被重渲染為改變後的畫面。
updated : 在重新渲染頁面後叫用,這時的頁面已經被重渲染成改變後的畫面。
beforeDestroy : 在此實體被銷毀前時叫用,這時實體還是擁有完整的功能。
destroyed : 此實體被銷毀後叫用,這時實體中的任何定義( data 、 methods...等)都已被解除綁定,代表在此做的任何操作都會失效。
例子:
<div id="app">
{{a}}
</div>
var vm = new Vue({
el: '#app',
data: {
a: 1
}
});
下面將函數拆成四組來分析,分別是:
- beforeCreate 及 created : 創建實體。
- beforeMount 及 mounted : 掛載目標元素。
- beforeUpdate 及 updated : data 改變後的重渲染。
- beforeDestroy 及 destroyed : 銷毀實體。
1:beforeCreate 及 created
var vm = new Vue({
el: '#app',
data: {
a: 1
},
beforeCreate() {
console.log('Hook: beforeCreate');
console.log(` this.a: ${this.a}`);
console.log(` this.$el: ${this.$el}`);
console.log();
},
created() {
console.log('Hook: created');
console.log(` this.a: ${this.a}`);
console.log(` this.$el: ${this.$el}`);
console.log();
},
...
});
結果是:
Hook: beforeCreate
this.a: undefined
this.$el: undefined
Hook: created
this.a: 1
this.$el: undefined
解說:
beforeCreate : 在 beforeCreate 時因實體還沒創建,所以 a 跟 $el 都是 undefined 。
created : 到了 created 時已經創建實例,所以 a 已變為 1 ,但是 $el 因為還未掛載至目標元素,所以依然是 undefined 。
所以在 beforeCreate 是不能操作實體中的物件的。
2:beforeMount 及 mounted
var vm = new Vue({
el: '#app',
data: {
a: 1
},
...
beforeMount() {
console.log('Hook: beforeMount');
console.log(this.$el.outerHTML);
console.log();
},
mounted() {
console.log('Hook: mounted');
console.log(this.$el.outerHTML);
console.log();
},
...
});
結果如下:
Hook: beforeMount
<div id="app"> {{a}}
<button v-on:click="a++">add</button>
<button v-on:click="$destroy()">Destroy instance</button>
</div>
Hook: mounted
<div id="app"> 1
<button>add</button>
<button>Destroy instance</button>
</div>
解說:
beforeMount : 流程圖上有提到,在叫用 beforeMount 前 Vue 已經決定模板的樣式,所以在 beforeMount 中的 $el 已經有值了,只是它還未依照 Vue 實體上的定義所渲染,只是個初始設定的模板,因此可以看到 {{a}} 、 v-on 這些模板語法都還未被轉換。
mounted : 在 mounted 被叫用時已經把 Vue 實體上的定義綁定到元素上,所以這裡看到的是經由 Vue 渲染後的配置。
所以在 beforeMount 前不能操作 DOM 元素。
3:beforeUpdate 及 updated
var vm = new Vue({
el: '#app',
data: {
a: 1
},
...
beforeUpdate() {
console.log('Hook: beforeUpdate');
console.log(` this.a: ${this.a}`);
console.log(` this.$el: ${this.$el}`);
console.log(this.$el.outerHTML);
console.log();
},
updated() {
console.log('Hook: updated');
console.log(` this.a: ${this.a}`);
console.log(` this.$el: ${this.$el}`);
console.log(this.$el.outerHTML);
console.log();
},
...
});
html:
<div id="app">
{{a}}
<button v-on:click="a++">add</button>
</div>
Hook: beforeUpdate
this.a: 2
this.$el: [object HTMLDivElement]
<div id="app"> 1
<button>add</button>
<button>Destroy instance</button>
</div>
Hook: updated
this.a: 2
this.$el: [object HTMLDivElement]
<div id="app"> 2
<button>add</button>
<button>Destroy instance</button>
</div>
解說:
beforeUpdate : a 改變後觸發 beforeUpdate ,可以看到 a 已經變為 2 了,可是頁面上還是 1 ,表示這時雖然 data 已經改變,可是還沒有重新渲染畫面。
updated : 完成重新渲染的作業後觸發,這時可以看到畫面已經將 1 改為 2了。
updated 時盡量避免修改 data ,這樣有可能再次觸發 update 造成無限循環,如果 data 要連動變化可以使用後面的章節會介紹的 computed 屬性。
4:beforeDestroy 及 destroyed
var vm = new Vue({
el: '#app',
data: {
a: 1
},
...
beforeDestroy() {
console.log('Hook: beforeDestroy');
console.log();
},
destroyed() {
console.log('Hook: destroyed');
console.log();
}
});
HTML:
<div id="app">
{{a}}
<button v-on:click="a++">add</button>
<button v-on:click="$destroy()">Destroy instance</button>
</div>
結果如下:
Hook: beforeDestroy
Hook: destroyed
解說:
beforeDestroy : 叫用 beforeDestroy 表示即將執行銷毀動作,如果有些物件要釋放資源可以在這處理。
destroyed : 叫用 destroyed 時,實體已經銷毀。
由於 Vue 會將 Vue 實體綁定在 this 上,所以在 Vue 實例中只要有使用到 this 的函式都不能使用箭頭函數,因箭頭函數的 this 會綁定上層(父親)的內容,所以箭頭函數中的 this 不會是期望的 Vue 實體。