vue 生命週期梳理

三隻萌新發表於2018-10-27

前言

在使用vue開發過程中經常會接觸到生命週期的問題,但對於每個鉤子函式都做了什麼,應用場景比較模糊,希望通過這次梳理讓自己清楚一些。初次寫文章,有不對的地方還望各位多多指正!

1. vue例項化過程

從vue例項化開始分析,我們通過new Vue來例項化來檢視一下原始碼 在 src/core/instance/init.js 中定義 使用vscode的小夥伴推薦使用Search node_modules外掛查詢node_modules中的外掛方便多了,媽媽再也不用擔心我迷路了

Vue.prototype._init = function (options?: Object) {
  // ... 省略程式碼
  initLifecycle(vm)
  initEvents(vm)
  initRender(vm)
  callHook(vm, 'beforeCreate')
  initInjections(vm) // resolve injections before data/props
  initState(vm)
  initProvide(vm) // resolve provide after data/props
  callHook(vm, 'created')

  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    vm._name = formatComponentName(vm, false)
    mark(endTag)
    measure(`vue ${vm._name} init`, startTag, endTag)
  }

  if (vm.$options.el) {
    vm.$mount(vm.$options.el)
  }
}
複製程式碼

Vue 初始化主要就幹了幾件事情,合併配置,初始化生命週期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等,vue 把不同的功能邏輯拆成一些單獨的函式執行。

我們關注到,在這個過程中插入鉤子函式,提供給開發者呼叫的機會。在初始化的最後,檢測到如果有 el 屬性,則呼叫 vm.$mount 方法掛載 vm,掛載的目標就是把模板渲染成最終的 DOM。

2.生命週期鉤子

  1. 生命週期鉤子自動繫結this到例項上,因此你可以通過this.操作訪問到資料和方法。注意不能使用箭頭函式例如下方程式碼,因為箭頭函式繫結外層的this會一直往上找。
created:()=>{// ...程式碼}
複製程式碼
  1. 下面用在各個生命週期中列印下el,data,dom節點
export default {
  name: 'App',
  data() {
    return {
      title: '標題'
    }
  },
   methods: {
    onDestoryClick() {
      this.$destroy()
    }
  },
  beforeCreate() {
    console.log(
      `\n\nbeforeCreate打頭\n$el    :${this.$el}\n$data     :${JSON.stringify(
        this.$data
      )}\n$refs.head   :${JSON.stringify(
        this.$refs.head
      )}\nbeforeCreate結尾\n\n`
    )
    console.log(this.$vnode)
  },
  created() {
    console.log(
      `\n\ncreated打頭\n$el    :${this.$el}\n$data     :${JSON.stringify(
        this.$data
      )}\n$refs.head   :${JSON.stringify(this.$refs.head)}\ncreated結尾\n\n`
    )
    console.log(this.$vnode)
  },
  beforeMount() {
    console.log(
      `\n\nbeforeMount打頭\n$el    :${this.$el}\n$data     :${JSON.stringify(
        this.$data
      )}\n$refs.head   :${JSON.stringify(this.$refs.head)}\nbeforeMount結尾\n\n`
    )
    console.log(this.$vnode)
  },
  mounted() {
    console.log(
      `\n\nmounted打頭\n$el    :${this.$el}\n$data     :${JSON.stringify(
        this.$data
      )}\n$refs.head   :${JSON.stringify(this.$refs.head)}\nmounted結尾\n\n`
    )
    console.log(this.$vnode)
  }
}
複製程式碼

結果圖
可以發現

  1. beforeCreate中拿不到任何資料,它在例項初始化之後,資料觀測 (data observer) 和 event/watcher 事件配置之前被呼叫。

  2. created中已經可以拿到data中的資料了,但是dom還沒有掛載。會判斷有無el,如果沒有el則停止後面的模板掛載。

    在例項建立完成後被立即呼叫。在這一步,例項已完成以下的配置:資料觀測 (data observer),屬性和方法的運算,watch/event 事件回撥。

    使用場景:ajax請求和頁面初始化

  3. beforeMount 和 created 拿到的資料相同 在掛載開始之前被呼叫:相關的 render 函式首次被呼叫。

  4. mounted中el被建立dom已經更新,vue例項物件中有template引數選項,則將其作為模板編譯成render函式,編譯優先順序render函式選項 > template選項

    使用場景:常用於獲取VNode資訊和操作,ajax請求

    注意 mounted 不會承諾所有的子元件也都一起被掛載。如果你希望等到整個檢視都渲染完畢,可以用 vm.$nextTick 替換掉 mounted

  5. 由於beforeUpdate和updated使用的比較少,一般用計算屬性和watch代替所以在此不在說明

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

客戶端渲染過程

  1. 處理 HTML 標記並構建 DOM 樹。
  2. 處理 CSS 標記並構建 CSSOM 樹。
  3. 將 DOM 與 CSSOM 合併成一個渲染樹。
  4. 根據渲染樹來佈局,以計算每個節點的幾何資訊。
  5. 將各個節點繪製到螢幕上。

參考資料

  1. vue.js
  2. 瀏覽器渲染過程

程式碼

github 地址

相關文章