iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 5
1
自我挑戰組

每天來點 Vue.js 吧系列 第 5

Vue instance 生命週期 ✦

  • 分享至 

  • xImage
  •  
tags: Vuejs

Instance Lifecycle 生命週期 ✐

介紹完如何使用 new Vue({...}) 建構 Vue instance 後,接著來談論有關 Vue instance 的生命週期。何謂生命週期?生命週期指的便是一個 Vue instance 自 創建銷毀 的過程中需要歷經的系列步驟,包含設置 data observer、編譯 template、將 Vue instance 掛載到 DOM 上、data 更動 Virtual DOM 重新打補丁等。

Instance Lifecycle Hooks

而上述的過程 Vue 提供各個階段的 Lifecycle Hooks 使得開發者可以在 Vue instance Lifecycle 的各個階段執行特定的程式碼,相當於在每個階段可以寫入對應的 callback 執行其他動作,例如資料請求等。

自一個簡單的 Vue instance 初探 Lifecycle ☼ 範例

進入介紹 Lifecycle Hooks 各個階段前,先來一個簡易的 Vue instance 掛載過程,並在各個 Lifecycle Hooks 使用 alert (lifecycle Hook Name) 方便觀察:

HTML
<main>
    <h1>還沒掛載 vue instance 的原始頁面</h1>
</main>
Javascript
const vm = new Vue({
  el: 'main',
  template: `
    <main class="bg-green">
      <h1>已經掛載 vue instance 的頁面</h1>
    </main>
`,
  beforeCreate () {
    alert('beforeCreate')
  },
  created () {
    alert('created')
  },
  beforeMount () {
    alert('beforeMount')
  },
  mounted () {
    alert('mounted')
  },
  beforeUpdate () {
    alert('beforeUpdate')
  },
  updated () {
    alert('updated')
  },
  beforeDestroy () {
    alert('beforeDestroy')
  },
  destroyed () {
    alert('destroyed')
  },
})

在該範例中,我們創建了一個 root Vue instance 取代掛載的 el main,Vue instance 創建後,我們可以看到歷經以下步驟:

  1. 初始化 Vue instance。 -> 對應 beforeCreate Hook
  2. Vue instance 完成 data observer 等設置。 -> 對應 create Hook
  3. 調用 template 相關渲染函式 -> 對應 beforeMounted Hook
  4. vm.$el 替換 el 元素。 -> 對應 mounted Hook
    • 此時畫面由原先的 紫色 轉換成 綠色

在此簡單範例中,我們看到了 Vue instance 中 Lifecycle Hooks 何時被調用,下面詳細介紹各個階段 Lifecycle Hooks:

各階段 Lifecycle Hooks ☼ 範例

tags: 注:Vue2 版

beforeCreate

在 Vue instance 初始後,data observer 設置前。

透過設定 console.log() 我們可以來觀察 Vue instance 目前的狀態。

在 Option 物件中添加以下程式碼:

補充:由於會有多個生命週期 Hooks 的 console 結果,推薦使用 console.group 幫助檢視。

beforeCreate() {
    alert('beforeCreate')
    console.group('beforeCreate')
    console.log('this', this)
    console.log('this.$el', this.$el)
    console.log('this.$data', this.$data)
    console.groupEnd('beforeCreate')
},

由於此時 Vue instance 尚未完成 $data$el 綁定,所以此時兩者皆為 undefined

$data $el
undefined undefined

created

Vue instance 完成 data observe$data 可用,$el 尚未掛載,不可用。

在 Option 物件中添加以下程式碼:

created() {
    alert('created')
    console.group('created')
    console.log('this', this)
    console.log('this.$el', this.$el)
    console.log('this.$data', this.$data)
    console.groupEnd('created')
},
$data $el
可用 undefined

beforeMount

$el 掛載前被呼叫。

在 Option 物件中添加以下程式碼:

beforeMount() {
    alert('beforeMount')
    console.group('beforeMount')
    console.log('this', this)
    console.log('this.$el', this.$el)
    console.log('this.$data', this.$data)
    console.groupEnd('beforeMount')
},
$data $el
可用 有值

此部分的 $el 打印結果目前測試為尚未渲染的 el,正在研究中 ⚙︎,之後會補上理解


mounted

Vue instance 掛載取代 el 後呼叫,此時原先的 el 已經被 $el 取代。

在 Option 物件中添加以下程式碼:

mounted() {
    alert('mounted')
    console.group('mounted')
    console.log('this', this)
    console.log('this.$el', this.$el)
    console.log('this.$data', this.$data)
    console.groupEnd('mounted')
},
$data $el
可用 可用

beforeUpdate

資料更新時調用,發生在 Virtual DOM 打補丁前。

在 Option 物件中添加以下程式碼:

beforeUpdate() {
    alert('beforeUpdate')
    console.group('beforeUpdate')
    console.log('this', this)
    console.log('this.$el', this.$el)
    console.log('this.$data', this.$data)
    console.groupEnd('beforeUpdate')
},

接著要先更改 data,並且我們添加 {{ 要更改的資料 }}template 中,滿足資料更新及會觸發 Virtual DOM 打補丁的條件,才會觸發該 Lifecycle Hook 調用。

添加以下程式碼:

...
  template: `
<main class="bg-green">
  <h1>已經掛載 vue instance 的頁面</h1>
  <p>{{ word }}</p>
</main>
`,
    data: {
    word: 'init',
    },
...

接著透過 Vue devtool 修改資料、或是在 console 輸入以下修改資料 vm.$data.word = 'change'

便可以看到該 Hook 調用。


updated

更改 data 導致 Virtaul DOM 重新渲染後調用。


beforeDestroy

Vue instance 銷毀前調用。

使用 vm.$destory 觸發 Vue instance 銷毀。

vm.$destroy()

destroyed

Vue instance 銷毀後調用,此時會移除 Vue instance 內的事件監聽器。


最後,我們來了解使用 Lifecycle Hook 要注意的細節。

Lifecycle Hooks 注意事項 ✐

Lifecycle Hooks 會自動綁定 this contextVue instance,因此可以透過 this 訪問該 Vue instance。

由於上述原因,不可以使用 arrow function 定義 Hook,arrow function 沒有自己的 this,其 this 值為所屬 lexical contextthis 值,若是使用 arrow function 定義 Hook,Vue 將無法綁定 Vue instance 作為 Hook 的 this 值。

更多關於 this,推薦可以閱讀這篇 淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂

以下使用 arrow function this 值將不會是 vue instance 而為 window,請不要如此:

const vm = new Vue({
  el: 'main',
  template: `
<main class="bg-green">
  <h1>lifecycle hook and This</h1>
</main>
`,
  // (X) 錯誤寫法
  beforeCreate: () => {
    console.log(this)
  },
})

請使用以下寫法:

const vm = new Vue({
  el: 'main',
  template: `
<main class="bg-green">
  <h1>lifecycle hook and This</h1>
</main>
`,
  beforeCreate () {
    console.log(this)
  },
})

結語

以上為此次內容,說明了有關 Instance Lifecycle,以及各個 instance Lifecycle Hook 調用的時機,感謝看到這裡的你,我們明天見。


若是文中有任何錯誤、錯字、想討論的內容,歡迎各位大大不吝鞭笞指正、交流分享,筆者不慎感激 ✦ ✦ ✦

▶︎ 筆者 github:https://github.com/YUN-RU-TSENG
▶︎ 老王賣瓜之筆者另一篇鐵人:每天來點 CSS Specification

▶︎ 倘若不斷向深處扎根,似乎就能茁壯成長 - RM


參考資料:

  1. Vuejs.org 2.x
  2. Component Lifecycle Methods Explained
  3. Vue Instance
  4. Vue github issue
  5. Introduction to Vue lifecycle hooks
  6. 淺談 JavaScript 頭號難題 this:絕對不完整,但保證好懂
  7. MDN this
  8. 等待學習:What Hooks Mean for Vue

上一篇
一切的基礎:Vue instance
下一篇
Vue template 模板語法
系列文
每天來點 Vue.js 吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
Chris
iT邦新手 3 級 ‧ 2020-09-20 22:37:50

還有隱藏版的 lifecycle
active
deactive
nextTick

原本打算放在後面元件的部分介紹 activeddeactived,方法 $nextTick 就要來研究一下了 XD

Chris iT邦新手 3 級 ‧ 2020-09-22 11:07:17 檢舉

我劇透了?!XD

我要留言

立即登入留言