vue源碼學習-initInjections與initProvide

接下來看看initInjections與initProvide方法,這兩個方法是一對couple,你中有我,我中有你,缺一不可。git

initInjections

// src/core/instance/inject.js
export function initInjections (vm: Component) {
  const result = resolveInject(vm.$options.inject, vm)
  if (result) {
    toggleObserving(false)
    Object.keys(result).forEach(key => {
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production') {
        defineReactive(vm, key, result[key], () => {
          warn(
            `Avoid mutating an injected value directly since the changes will be ` +
            `overwritten whenever the provided component re-renders. ` +
            `injection being mutated: "${key}"`,
            vm
          )
        })
      } else {
        defineReactive(vm, key, result[key])
      }
    })
    toggleObserving(true)
  }
}
複製代碼
// src/core/instance/inject.js
export function resolveInject (inject: any, vm: Component): ?Object {
  if (inject) {
    // inject is :any because flow is not smart enough to figure out cached
    const result = Object.create(null)
    const keys = hasSymbol
      ? Reflect.ownKeys(inject).filter(key => {
        /* istanbul ignore next */
        return Object.getOwnPropertyDescriptor(inject, key).enumerable
      })
      : Object.keys(inject)

    for (let i = 0; i < keys.length; i++) {
      const key = keys[i]
      const provideKey = inject[key].from
      let source = vm
      while (source) {
        if (source._provided && hasOwn(source._provided, provideKey)) {
          result[key] = source._provided[provideKey]
          break
        }
        source = source.$parent
      }
      if (!source) {
        if ('default' in inject[key]) {
          const provideDefault = inject[key].default
          result[key] = typeof provideDefault === 'function'
            ? provideDefault.call(vm)
            : provideDefault
        } else if (process.env.NODE_ENV !== 'production') {
          warn(`Injection "${key}" not found`, vm)
        }
      }
    }
    return result
  }
}
複製代碼

initInjections方法主要是獲取全部的inject對象,其中inject的from做爲注入到組件實例對象中的key值,而default做爲默認值。先獲取_provided的值,若值不存在,則設爲default值。default能夠爲基本類型,也能夠爲function。initInjections方法會在data和props屬性以前被執行。github

在initInjections方法中,開頭有一句toggleObserving(false),主要的做用是不爲provide值添加響應式監聽。在最後再調用toggleObserving(true),使得其餘屬性能夠監聽。toggleObserving的做用仍是在於開啓或關閉響應式監聽。ide

initProvide

// src/core/instance/inject.js
export function initProvide (vm: Component) {
  const provide = vm.$options.provide
  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }
}
複製代碼

initProvide方法則是初始化provide的值,並賦值給_provided屬性。provide屬性能夠是一個基本類型,也能夠是一個function。ui

總結

簡而言之,這兩個方法的主要做用就像一個供應商和一個採購商。一個提供商品,一個購買商品。可是呢,不管採購銷售仍是購買,均可以支持多種方式。如一等公民(function)或二等公民(基本類型),他們提供給使用者實現高階組件的一種方式。spa

博客地址 gitbook小冊code

相關文章
相關標籤/搜索