Vue 生命週期與鉤子函式

YXi發表於2019-08-03

如果想要了解對於實現頁面邏輯互動等效果,我們必須知道 Vue 的生命週期,知道我們寫的東西應該掛載到哪裡?而且說到生命週期,必定少不了鉤子函式。。

Vue官方給出的api講解:

所有的生命週期鉤子自動繫結this上下文到例項中,因此你可以訪問資料,對屬性和方法進行運算。這意味著你不能使用箭頭函式來定義一個生命週期方法(例如created: () => this.fetchTodos())。這是因為箭頭函式繫結了父上下文,因此this與你期待的 Vue 例項不同,this.fetchTodos的行為未定義。

圖片載入失敗!

好像聽不太懂?看下面

生命週期

生命週期函式就是 Vue 例項在某一個時間點會自動執行的函式。

簡單來說就是好像把人的出生到死亡分成一個個階段,你取名字肯定是在你出生階段,而不是在成年階段;你結婚肯定是在成年階段,而不是在出生階段;如果說你在出生階段想去階段,那肯定是不行的。 元件也是一樣,在例項化的時特定階段呼叫特定方法,呼叫的這個方法就是鉤子函式

鉤子函式

鉤子函式和回撥函式有什麼區別嗎?

區別:

js派函式監聽事件 => 監聽函式就是所謂的鉤子函式 => 函式鉤取事件:函式主動找事件 => 鉤子函式

js預留函式給dom事件,dom事件呼叫js預留的函式 => 事件派發給函式:事件呼叫函式 => 回撥函式

可以簡單的理解為:

鉤子函式是事件被動的監聽,一旦條件觸發就執行

回撥函式是主動事件,執行函式體內容

敲黑板

重點圖來了,不說廢話,附上:

圖片載入失敗!

是不是有那麼一丁點了解了

上猛料:

Vue中有8中生命週期函式:

圖片載入失敗!

就這八種

不多說了,來一組測試程式碼

注:此處省略部分程式碼

<template>
    <div>{{msg}}</div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'hello world',
      msg1: ''
    }
  },
  beforeCreate () {
    console.groupCollapsed('beforeCreate 建立前狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  created () {
    console.groupCollapsed('created 建立前狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  beforeMount () {
    console.groupCollapsed('beforeMount 掛載前狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  mounted () {
    console.groupCollapsed('mounted 掛載後狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
    setTimeout(() => {
      this.$data.msg = '123'
    }, 5000)
  },
  activated () {
    console.groupCollapsed('activated 掛載後狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(this.$data.msg)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
    setTimeout(() => {
      this.$data.msg = 'hello tiantian'
    }, 10000)
  },
  beforeUpdate () {
    console.groupCollapsed('beforeUpdate 更新前狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  updated () {
    console.groupCollapsed('updated 更新後狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
    setTimeout(() => {
      this.$destroy()
    }, 5000)
  },
  beforeDestroy () {
    console.groupCollapsed('beforeDestroy 例項銷燬前狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  },
  destroyed () {
    console.groupCollapsed('destroyed 例項銷燬後狀態')
    console.log('%c%s', 'color:MediumVioletRed', 'el     : ' + this.$el)
    console.log(this.$el)
    console.log('%c%s', 'color:MediumVioletRed', 'data   : ' + this.$data)
    console.log(document.getElementById('app').innerHTML)
    console.log('%c%s', 'color:MediumVioletRed', 'msg: ' + this.msg)
    console.groupEnd()
  }
}
</script>
複製程式碼

這一大坨,肯定沒有心情看。。實在不行,可以實踐一下。。。

詳細說一下步驟

beforeCreatecreated

beforeCreate:在例項初始化完成時,被執行。
一般不會使用這個鉤子函式

created:在初始化結束之後會再初始化一些外部注入和一些雙向繫結相關的事情時,被執行。
當前元件已構造完成,已經完成了資料劫持,把方法和計算屬性都已經掛載到了當前的元件上,但是並不能獲取到真實的DOM,所以不能操作DOM,通常會完成Ajax請求

這兩個鉤子函式執行完之後,初始化基本完成了。

在 beforeCreate 階段,el 和 data 都沒有被掛載;而在 created 階段,el 還沒被掛在,但 data 已經被掛載了,如下圖所示:

圖片載入失敗!

疑問?這裡el為啥沒有被掛載呢?

圖片載入失敗!

看上圖,在 created 執行完畢後,它會詢問一個條件:你這個Vue例項裡是否有 el 這個選項。

如果有就又會詢問是否有 template 這個選項:

  • 如果沒有 template 就會走右側的分支,

    • 如果這個例項沒有 template,就會將 el 這個根節點當做模版,來進行渲染
  • 如果有 template 就會走左側的分支

    • 把 template 作為模版去渲染

beforeMountmounted

beforeMount:執行時,頁面還沒有被渲染。

mounted:執行時,頁面已經被渲染了。
真實DOM已完成,掛載到了頁面上,也可以發起Ajax請求

從圖中也可以看出,在 beforeMount 執行時,el 還沒有被掛在;當 mounted 執行時,el 被掛載到頁面了。

圖片載入失敗!

beforeUpdateupdated

beforeUpdate:資料被改變,還沒渲染之前會被執行。

updated:資料被改變,渲染完成後會被執行。
不能修改data中的資料,可能會造成死迴圈

圖片載入失敗!

這張圖中有個奇怪的現象,為什麼在 beforeUpdate 和 updated 兩個鉤子函式中,el 和 msg 都是一樣呢?beforeUpdate 執行是不應該是老資料嘛,怎麼這裡也是最新的資料了?

因為這裡的 el 是虛擬 dom,不是真實的 dom,和 data 都是物件,在加上 console.log 這裡是個非同步操作,當你點開 console.log 時,其實程式碼早就跑完了,資料已經是最新的了,所以就會看到在這兩個函式中輸出結果是一樣的了。

可以用 document.getElementById('app').innerHTML獲取真實的Dom結構,這時我們就可以看到這兩處不一樣的地方了。

beforeDestroydestroyed

呼叫vm.$destroy()方法可對例項銷燬

beforeDestroy:例項被銷燬前被執行。

destroyed:例項被銷燬後被執行。

activateddeactivated

對了,也有人說這兩個也是生命週期函式,那就來看看

使用keep-alive標籤後,會有兩個生命週期函式分別是:activated、deactivated
具體keep-alive的使用方法,請參考我的文章《Vue中keepalive的深入理解和使用》

activated:頁面渲染的時候被執行。

deactivated:頁面被隱藏或者頁面即將被替換成新的頁面時被執行。

當引入keep-alive的時候,頁面第一次進入,鉤子的觸發順序 created-> mounted-> activated,退出時觸發deactivated。當再次進入(前進或者後退)時,只觸發activated。

事件掛載的方法等,只執行一次的放在 mounted 中;元件每次進去都執行的方法放在 activated 中, activated 中的方法不管是否需要快取都會執行。


簡單說一下:

  • beforecreate : 可以在這加個loading事件,在載入例項時觸發
  • created : 初始化完成時的事件寫在這裡,如在這結束loading事件,非同步請求也適宜在這裡呼叫
  • mounted : 掛載元素,獲取到DOM節點
  • updated : 如果對資料統一處理,在這裡寫上相應函式
  • beforeDestroy : 可以做一個確認停止事件的確認框
  • nextTick : 更新資料後立即操作dom

就這樣吧。。。。。。。。。。


^_<

相關文章