Vue源码学习之initInjections和initProvide

Vue源码学习之initInjections和initProvide

在进行源码阅读之前先让我们了解一个概念:provide/inject,这个是Vue在2.2.0版本新增的一个属性,按照Vue官网的说法,它的作用是:

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。

简而言之就是由祖先组件提供了一个provide,provide里的属性可供所有的后代组件通过inject注入并调用,官网实例如下:

// 父级组件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 子组件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}
initInjections

该方法在初始化data/props之前被调用,主要作用是初始化vue实例的inject,让我们一行一行地看代码吧!

const result = resolveInject(vm.$options.inject, vm)

首先就是一个对inject进行处理的方法resolveInejct,让我们看下这个方法的实现。

const result = Object.create(null)
// 对Symbol进行不同的处理
const keys = hasSymbol ? Reflect.ownKeys(inject).filter(key => {
        /* istanbul ignore next */
    return Object.getOwnPropertyDescriptor(inject, key).enumerable
}) : Object.keys(inject)

先建立一个存放结果的空对象,由于provide支持Symbols作为key,所以要对symbol和普通的对象进行不同的处理。

for (let i = 0; i < keys.length; i++) {
      const key = keys[i]
      const provideKey = inject[key].from
      let source = vm
      while (source) {
        // 验证父组件链逐层向上查找provide,直到找到为止
        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

这段代码主要就是对inject属性中的各个key进行遍历,然后沿着父组件链一直向上查找provide中和inject对应的属性,直到查找到根组件或者找到为止,然后返回结果。

让我们接着回到initInjections方法:

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)
  }

可以看到从provide中找到了inject的值之后,接下来就是对result的一些处理,比如在非生产环境会将result里的值定义成相应式的。

initProvide
function initProvide (vm: Component) {
  const provide = vm.$options.provide
  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }
}

initProvide基本没有什么内容,就是将$options里的provide赋值到当前实例上

猜你喜欢

转载自blog.csdn.net/qq_34179086/article/details/88081602