vue生命週期探究(一)

曾廣營發表於2017-03-29

vue官方文件---例項生命週期
vue-router2.3版文件---路由勾子
vue官方文件---指令及其繫結週期

前言

在使用vue開發的過程中,我們經常會接觸到生命週期的問題。那麼你知道,一個標準的工程專案中,會有多少個生命週期勾子嗎?讓我們來一起來盤點一下:

  1. 根元件例項:8個 (beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed)

  2. 元件例項:8個 (beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed)

  3. 全域性路由鉤子:2個 (beforeEach、afterEach)

  4. 元件路由鉤子:3個 (beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave)

  5. 指令的週期: 5個 (bind、inserted、update、componentUpdated、unbind)

  6. beforeRouteEnter的next所對應的週期

  7. nextTick所對應的週期

嚇到了嗎?合計竟然一共有28個週期,是否看得頭昏眼花了呢?接下來讓我們一起來介紹一下各個週期的通常用途與使用細節吧

元件例項週期

這一塊vue2的官方文件有一張圖示,我們簡要提一下用法和注意

beforeCreate

在例項初始化之後,資料觀測(data observer) 和 event/watcher 事件配置之前被呼叫。

tip:

此時元件的選項還未掛載,因此無法訪問methods,data,computed上的方法或資料

created

例項已經建立完成之後被呼叫。在這一步,例項已完成以下的配置:資料觀測(data observer),屬性和方法的運算, watch/event 事件回撥。然而,掛載階段還沒開始,$el 屬性目前不可見。

這是一個常用的生命週期,因為你可以呼叫methods中的方法、改變data中的資料,並且修改可以通過vue的響應式繫結體現在頁面上、獲取computed中的計算屬性等等。

tip:

通常我們可以在這裡對例項進行預處理。
也有一些童鞋喜歡在這裡發ajax請求,值得注意的是,這個週期中是沒有什麼方法來對例項化過程進行攔截的。
因此假如有某些資料必須獲取才允許進入頁面的話,並不適合在這個頁面發請求。
建議在元件路由勾子beforeRouteEnter中來完成。

beforeMonut

在掛載開始之前被呼叫:相關的 render 函式首次被呼叫。

mounted

el 被新建立的 vm.$el 替換,並掛載到例項上去之後呼叫該鉤子。如果 root 例項掛載了一個文件內元素,當 mounted 被呼叫時 vm.$el 也在文件內。

tip:

1.在這個週期內,對data的改變可以生效。但是要進下一輪的dom更新,dom上的資料才會更新。
2.這個週期可以獲取 dom。 之前的論斷有誤,感謝@馮銀超 和 @AnHour的提醒
3.beforeRouteEnter的next的勾子比mounted觸發還要靠後
4.指令的生效在mounted週期之前

beforeUpdate

資料更新時呼叫,發生在虛擬 DOM 重新渲染和打補丁之前。你可以在這個鉤子中進一步地更改狀態,這不會觸發附加的重渲染過程。

updated

由於資料更改導致的虛擬 DOM 重新渲染和打補丁,在這之後會呼叫該鉤子。當這個鉤子被呼叫時,元件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。然而在大多數情況下,你應該避免在此期間更改狀態,因為這可能會導致更新無限迴圈。

beforeDestroy

例項銷燬之前呼叫。在這一步,例項仍然完全可用。

tip:

1.這一步還可以用this來獲取例項。
2.一般在這一步做一些重置的操作。比如清除掉元件中的 定時器 和 監聽的dom事件

destroyed

Vue 例項銷燬後呼叫。呼叫後,Vue 例項指示的所有東西都會解繫結,所有的事件監聽器會被移除,所有的子例項也會被銷燬。

全域性路由鉤子

作用於所有路由切換,一般在main.js裡面定義

router.beforeEach

示例
router.beforeEach((to, from, next) => {
  console.log('路由全域性勾子:beforeEach -- 有next方法')
  next()
})

一般在這個勾子的回撥中,對路由進行攔截。
比如,未登入的使用者,直接進入了需要登入才可見的頁面,那麼可以用next(false)來攔截,使其跳回原頁面。
值得注意的是,如果沒有呼叫next方法,那麼頁面將卡在那。

next的四種用法
1.next() 跳入下一個頁面
2.next('/path') 改變路由的跳轉方向,使其跳到另一個路由
3.next(false)  返回原來的頁面
4.next((vm)=>{})  僅在beforeRouteEnter中可用,vm是元件例項。

router.afterEach

示例
router.afterEach((to, from) => {
  console.log('路由全域性勾子:afterEach --- 沒有next方法')
})

在所有路由跳轉結束的時候呼叫,和beforeEach是類似的,但是它沒有next方法

元件路由勾子

和全域性勾子不同的是,它僅僅作用於某個元件,一般在.vue檔案中去定義。

beforeRouteEnter

示例
  beforeRouteEnter (to, from, next) {
    console.log(this)  //undefined,不能用this來獲取vue例項
    console.log('元件路由勾子:beforeRouteEnter')
    next(vm => {
      console.log(vm)  //vm為vue的例項
      console.log('元件路由勾子beforeRouteEnter的next')
    })
  }

這個是一個很不同的勾子。因為beforeRouterEnter在元件建立之前呼叫,所以它無法直接用this來訪問元件例項。
為了彌補這一點,vue-router開發人員,給他的next方法加了特技,可以傳一個回撥,回撥的第一個引數即是元件例項。
一般我們可以利用這點,對例項上的資料進行修改,呼叫例項上的方法。

我們可以在這個方法去請求資料,在資料獲取到之後,再呼叫next就能保證你進頁面的時候,資料已經獲取到了。沒錯,這裡next有阻塞的效果。你沒呼叫的話,就會一直卡在那

tip:

next(vm=>{console.log('next')  })
這個裡面的程式碼是很晚執行的,在元件mounted週期之後。沒錯,這是一個坑。你要注意。
beforeRouteEnter的程式碼時很早執行的,在元件beforeCreate之前;
但是next裡面回撥的執行,很晚,在mounted之後,可以說是目前我找到的,離dom渲染最近的一個週期。

beforeRouteLeave

  beforeRouteLeave (to, from, next) {
    console.log(this)    //可以訪問vue例項
    console.log('元件路由勾子:beforeRouteLeave')
    next()
  },

在離開路由時呼叫。可以用this來訪問元件例項。但是next中不能傳回撥。

beforeRouteUpdate

這個方法是vue-router2.2版本加上的。因為原來的版本中,如果一個在兩個子路由之間跳轉,是不觸發beforeRouteLeave的。這會導致某些重置操作,沒地方觸發。在之前,我們都是用watch $route來hack的。但是通過這個勾子,我們有了更好的方式。

老實講,我沒用過這個勾子,所以各位可以檢視一下文章之前的文件,去嘗試一下,再和我交流交流。

指令週期

繫結自定義指令的時候也會有對應的週期。
這幾個週期,我比較常用的,一般是隻有bind。

bind

只呼叫一次,指令第一次繫結到元素時呼叫,用這個鉤子函式可以定義一個在繫結時執行一次的初始化動作。

inserted

被繫結元素插入父節點時呼叫(父節點存在即可呼叫,不必存在於 document 中)。
實際上是插入vnode的時候呼叫。

update

被繫結元素所在的模板更新時呼叫,而不論繫結值是否變化。通過比較更新前後的繫結值,可以忽略不必要的模板更新。
慎用,如果在指令裡繫結事件,並且用這個週期的,記得把事件登出

componentUpdated

被繫結元素所在模板完成一次更新週期時呼叫。

unbind

只呼叫一次, 指令與元素解綁時呼叫。

Vue.nextTick、vm.$nextTick

示例:
  created () {
    this.$nextTick(() => {
      console.log('nextTick')  //回撥裡的函式一直到真實的dom渲染結束後,才執行
    })
    console.log('元件:created')
  },

nextTick方法的回撥會在dom更新後再執行,因此可以和一些dom操作搭配一起用,如 ref。
非常好用,可以解決很多疑難雜症。

場景:
你用ref獲得一個輸入框,用v-model繫結。
在某個方法裡改變繫結的值,在這個方法裡用ref去獲取dom並取值,你會發現dom的值並沒有改變。
因為此時vue的方法,還沒去觸發dom的改變。
因此你可以把獲取dom值的操作放在vm.$nextTick的回撥裡,就可以了。

vue生命週期探究(二)

相關文章