0%

VueJs Instance Lifecycle Hooks 生命週期鉤子

在 Vue 所使用到的整個生命週期方法,可以想像成是一齣戲要上演,哪一個主角需要在哪個時候上場、哪個配角需要在哪個時刻退場,都需要有邏輯才可以讓故事產生連貫性與流暢。

Vue 的生命週期方法雖然共有八個,但並不是每個都需要用到,就像在戲裡,有些橋段不出現、配角不出現也不會影響整齣性的故事性。

把 Vue 的生命週期分為三個大階段會比較容易理解:第一階段的「初始化顯示」、第二階段「更新狀態顯示」、第三階段「死亡、銷毀 Vue 實例」,每個階段都有對應的生命週期 callback 方法,這些生命週期的方法也稱為「生命週期鉤子」掛載在不同時期。 Vue 的生命週期比 React 還要複雜一些。

為了避免 this 的混淆,這些生命週期的方法都是回調方法(callback),所以最好一律都寫成箭頭函式,讓 this 直接指向父級,也就是 vue 實例本身。

Vue 的生命週期各階段都做了什麼?

0. 創建 Vue 的實例

當我們創建好一個 Vue 的實例,就會馬上進入下一個階段beforeCreate()

1. 初始化顯示階段

  • beforeCreate() 實例創建前

    • 準備工作:觀察初始化(Observe Data)、初始化事件(Init Events)
    • 這個階段實例的 data、methods 是讀不到的
  • created() 實例創建後

    • 這個階段已經完成了資料觀察初始化(data observer),屬性和方法的運算, watch/event 事件回調。mount 掛載階段還沒開始,$el 屬性目前不可見,資料並沒有在 DOM 元素上進行渲染。
  • beforeMount() 在掛載開始之前被調用

  • 相關的 render 函數首次被調用。

  • mounted()

  • 初始化顯示之後。立即調用。是最常用的 callback,用來「掛載」到頁面上。

  • el選項的 DOM 節點 被新創建的 vm.$el 替換,並掛載到實例上去之後調用此生命週期方法。此時實例的資料在 DOM 節點上進行渲染。

2. 更新狀態顯示階段

this.xxx = value

  • beforeUpdate() 資料更新時調用

    • 但不進行 DOM 重新渲染,在資料更新時 DOM 沒渲染前可以在這個生命方法裡進行狀態處理。
  • updated() 資料更新並且 DOM 重新渲染

    • 這個狀態下資料更新並且 DOM 重新渲染,當這個生命週期方法被調用時,組件 DOM 已經更新,所以這時可以執行依賴於 DOM 的操作。當實例每次進行資料更新時 updated 都會執行。

當我們調用 vm.$destroy()時,就會進入下一個銷毀 Vue 實例的階段

3.死亡、銷毀 Vue 實例階段

也稱死亡,也就是沒有互動的功能。

  • beforeDestory() 實例銷毀之前調用

  • destoryed() 實例銷毀後調用

    • Vue 實例銷毀後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷毀。

查看生命週期方法的順序範例

範例:一行字,每隔一秒會切換成隱藏。

在初始化之後,把初始化的值以v-show的方式讓<p>依定時器的規則顯示。
再設定一個按鈕,綁定可以銷毀 vm 的函式,當點擊按鈕時這個 vm 會銷毀而停止顯示或隱藏切換,這個定時器掛載到mounted()之後,點擊按鈕雖然會停止文字顯示的切換,卻不會停止我們在定時器裡放的console.log('++++++'),也表示「定時器」並沒有被銷毀。

要把整個定時器銷毀(進入銷毀 Vue 實例)階段,需要在beforeDestroy()這個階段清除定時器,我們可使用clearInterval()來清除定時器,但是如何找到我們要銷毀的定時器?可以在mounted()階段的定時器,指向我們設定的變數this.intervalId = setInterval()來讓清除定時器的函式找到。

在實例裡加入每個時期的生命週期方法,並用console.log印出來,執行一下頁面就可看到其順序。

各生命週期執行次數

階段 生命週期 Hook 執行次數

| 初始化顯示階段
||beforeCreate() 實例創建前 | 1 次
| |created() 實例創建後 | 1 次 |
| | beforeMount() 在掛載開始之前 | 1 次
|| mounted() 掛載 | 1 次
| 更新狀態顯示階段
| | beforeUpdate() 資料更新時 | 不限次數 |
| | updated() 資料更新並 DOM 重新渲染 | 不限次數 |
| 死亡、銷毀 Vue 實例階段| | |
| | beforeDestory() 實例銷毀之前 | 1 次 |
| | destoryed() 實例銷毀後 | 1 次 |

常用的生命週期方法?

  • mounted():主要用來發送ajax請求,啟動定時器等非同步的任務。
  • beforeDestory():做收尾的工作,例如清除定時器,否則定時器會一直執行下去(如範例)
  • created():進行 ajax 請求異步數據的獲取、初始化數據
  • mounted():掛載元素內 dom 節點的獲取
  • nextTick():針對單一事件更新數據後立即操作 dom
  • updated():任何數據的更新,如果要做統一的業務邏輯處理
  • watch():監聽具體數據變化,並做相應的處理

實際操作

來 codepen 看看:VueJs Instance Lifecycle Hooks 生命週期鉤子,別忘了觀察 console 的變化。
HTML 部分:

1
2
<button @click="destroyVm">Destroy vm</button>
<p v-show="isShow">Hello Paris</p>

Vue 實例的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const vm = new Vue({
el: '#app',
data: {
isShow: true,
},
// 1.初始化顯示階段
beforeCreate() {
console.log('1. beforeCreate');
},
created() {
console.log('2. created');
},
beforeMount() {
console.log('3. beforeMount');
},
// 初始化後的顯示,所以放在mounted(只用一次)
mounted() {
console.log('4. mounted');
// 定時器,每一秒改變一次
this.intervalId = setInterval(() => {
console.log('+++++++++');
this.isShow = !this.isShow;
}, 1000);
},
// 2.更新狀態顯示階段
beforeUpdate() {
console.log('5. beforeUpdate');
},
updated() {
console.log('6. updated');
},
// 3.死亡、銷毀 Vue 實例階段 / 銷毀之前調用(只用一次)
beforeDestroy() {
// 清除定時器
clearInterval(this.intervalId);
console.log('7. beforeDestroy');
},
destroyed() {
console.log('8. destroyed');
},
methods: {
// 毀掉vm
destroyVm() {
this.$destroy();
},
},
});