拼搏30天VUE.js之Vue 實體的生命週期(Part3)

生命週期函式示意圖:

拼搏30天VUE.js之Vue 實體的生命週期(Part3)

注,上图来自于@老马自嘲的《Vue入门系列之Vue实例详解与生命周期》一文。著作权归作者所有。

創建一個vue實例的四個過程:

拼搏30天VUE.js之Vue 實體的生命週期(Part3)

注,上图来自于@Airen的博客的《Vue 2.0的学习笔记: Vue实例和生命周期》一文。著作权归作者所有。

拼搏30天VUE.js之Vue 實體的生命週期(Part3)

注:上图来自@浅白的《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
  }
});

下面將函數拆成四組來分析,分別是:

  1. beforeCreate 及 created : 創建實體。
  2. beforeMount 及 mounted : 掛載目標元素。
  3. beforeUpdate 及 updated : data 改變後的重渲染。
  4. 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 實體。