vue[原始碼]生命週期鉤子的實現

小為子發表於2019-04-01

先看下這5個函式呼叫:

callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')複製程式碼

先看看callHook函式作用:呼叫生命週期鉤子函式

下面是callHook函式原始碼

export function callHook (vm: Component, hook: string) {
  // #7573 disable dep collection when invoking lifecycle hooks
  pushTarget() //為了避免在某些生命週期鉤子中使用 props 資料導致收集冗餘的依賴
  const handlers = vm.$options[hook] //獲取生命週期鉤子 vue選項合併會把生命週期鉤子選項合併成一個陣列
  if (handlers) {
    for (let i = 0, j = handlers.length; i < j; i++) {
      try {
        handlers[i].call(vm)//為了保證生命週期鉤子函式內可以通過 this 訪問例項物件,所以使用 .call(vm) 執行這些函式
      } catch (e) { //為了捕捉可能出現的錯誤
        handleError(e, vm, `${hook} hook`)
      }
    }
  }
  if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook)
  }
  popTarget() //為了避免在某些生命週期鉤子中使用 props 資料導致收集冗餘的依賴

}複製程式碼

接收兩個引數:例項物件和要呼叫的生命週期鉤子的名稱

現在大家應該知道,beforeCreate 以及 created 這兩個生命週期鉤子的呼叫時機了。

其中 initState 包括了:initPropsinitMethodsinitDatainitComputed 以及 initWatch

所以當 beforeCreate 鉤子被呼叫時,所有與 propsmethodsdatacomputed 以及 watch 相關的內容都不能使用,當然了 inject/provide 也是不可用的。

created 生命週期鉤子

initInjectionsinitState 以及 initProvide 執行完畢之後才被呼叫,

所以在 created 鉤子中,是完全能夠使用以上提到的內容的。但由於此時還沒有任何掛載的操作,但是在 created 中是不能訪問DOM的,即不能訪問 $el

callHook 函式最後一段程式碼

if (vm._hasHookEvent) {
  vm.$emit('hook:' + hook)
}複製程式碼

vm._hasHookEvent 是在 initEvents 函式中定義的,它的作用是判斷是否存在生命週期鉤子的事件偵聽器,初始化值為 false 代表沒有,當元件檢測到存在生命週期鉤子的事件偵聽器時,會將 vm._hasHookEvent 設定為 true

介紹下生命週期鉤子事件幀聽器:

<child
  @hook:beforeCreate="handleChildBeforeCreate"
  @hook:created="handleChildCreated"
  @hook:mounted="handleChildMounted"
  @hook:生命週期鉤子
 />複製程式碼

使用hook:加上生命週期鉤子名稱來監聽元件內對應的生命週期事件


接下來繼續講那幾個呼叫函式:initState

initState執行前先執行了initInjections函式,也就是說inject選項更早被初始化,由於初始化inject設計到比較多 先跳過講initstate

export function initState (vm: Component) {
  vm._watchers = [] //在vue例項物件上新增一個屬性(陣列)
  const opts = vm.$options //定義一個常量作為vm.$options引用
  if (opts.props) initProps(vm, opts.props) //判斷選項中是否有props 有則呼叫initprops
//判斷是否有methods,有則呼叫initmethodds初始化methods選項  if (opts.methods) initMethods(vm, opts.methods) 
  if (opts.data) {//判斷data是否存在 //呼叫initdata初始化data選項
    initData(vm)
  } else {//如果不存在則呼叫observe函式觀察一個空物件
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed) //判斷computed是否存在,然後初始化
  if (opts.watch && opts.watch !== nativeWatch) { //判斷是否存在和是否是原生物件...
    initWatch(vm, opts.watch)
  }
}複製程式碼

整理完initstate函式發現都是一些初始化選項彙總:



相關文章