>웹 프론트엔드 >JS 튜토리얼 >Vue.js 소스 코드 학습 제공 및 주입

Vue.js 소스 코드 학습 제공 및 주입

小云云
小云云원래의
2018-02-24 14:25:581649검색

Vue.js의 2.2.0+ 버전에 제공 및 주입 옵션이 추가되었습니다. 이들은 쌍으로 나타나며 상위 구성 요소에서 데이터를 아래로 전달하는 데 사용됩니다. 2.2.0+ 版本中添加加了 provide 和 inject 选项。他们成对出现,用于父级组件向下传递数据。 

源码位置

和之前一样,初始化的方法都是在 Vue 的 _init 方法中的。

  // src/core/instance/init.js
  Vue.prototype._init = function (options?: Object) {
    ……
    vm._self = vm
    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')
  }

这里找到 initInjectionsinitProvide 方法,这就是 provideinject 的初始化方法了。这两个方法都是在 src/core/instance/inject.js 中。

provide

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。

先看源码:

// src/core/instance/inject.jsexport function initProvide (vm: Component) {
  const provide = vm.$options.provide  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }
}

provide 是向下传递数据的选项。这里先拿到 provide 选项中的内容,如果有 provide 选项,将 provide 选项传递给 vm._provided 变为 Vue 实例全局数据。
这里看一下例子更清楚,下例中传入数据 foo,数据内容为 bar

var Provider = {
  provide: {
    foo: 'bar'
  },  // ...}

inject

inject 选项应该是一个字符串数组或一个对象,该对象的 key 代表了本地绑定的名称,value 为其 key (字符串或 Symbol) 以在可用的注入中搜索。

源码

// src/core/instance/inject.jsexport function initInjections (vm: Component) {
  const result = resolveInject(vm.$options.inject, vm)  if (result) {
    observerState.shouldConvert = false
    Object.keys(result).forEach(key => {
      defineReactive(vm, key, result[key])
    })
    observerState.shouldConvert = true
  }
}

简化后的源码可以看到,首先通过 resolveInject 方法获取 inject 选项搜索结果,如果有搜索结果,遍历搜索结果并为其中的数据添加 setter 和 getter。
接着来看下 resolveInject 方法:

export function resolveInject (inject: any, vm: Component): ?Object {
  if (inject) {    // inject 是 :any 类型因为流没有智能到能够指出缓存
    const result = Object.create(null)    // 获取 inject 选项的 key 数组
    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 && provideKey in source._provided) {
          result[key] = source._provided[provideKey]          break
        }
        source = source.$parent
      }      if (!source) {        if (&#39;default&#39; in inject[key]) {          const provideDefault = inject[key].default
          result[key] = typeof provideDefault === &#39;function&#39;
            ? provideDefault.call(vm)
            : provideDefault
        } else if (process.env.NODE_ENV !== &#39;production&#39;) {
          warn(`Injection "${key}" not found`, vm)
        }
      }
    }    return result
  }
}

获取 inject 选项的 key 数组,遍历 key 数组,通过向上冒泡来查找 provide 中是否有 key 与 inject 选项中 from 属性同名的,如果有,则将这个数据传递给 result;如果没有,检查 inject 是否有 default 选项设定默认值或者默认方法,如果有则将默认值返传给 result,最终返回 result 对象。
所以,inject 的写法应该是有 default 默认值的:

const Child = {
  inject: {
    foo: { default: &#39;foo&#39; }
  }
}

或者是有 from 查找键和 default 默认值的:

const Child = {
  inject: {
    foo: {
      from: &#39;bar&#39;,      default: &#39;foo&#39;
    }
  }
}

或者为 default 默认值设定一个工厂方法:

const Child = {
  inject: {
    foo: {
      from: &#39;bar&#39;,      default: () => [1, 2, 3]
    }
  }
}

好吧,我承认这就是引用的官网的三个例子~ 不过意思到就好啦。
这里我有个疑问,既然在源码中主动去识别了 from 和 default,官网上说是

2.5.0+ 的注入可以通过设置默认值使其变成可选项:

那么如下写法还可用吗?

var Child = {
  inject: [&#39;foo&#39;],
  created () {
    console.log(this.foo) // => "bar"
  }  // ...}

为此,我们去查查 2.2.0 版本的Vue是怎么写的?

export function initInjections (vm: Component) {
  const provide = vm.$options.provide  const inject: any = vm.$options.inject  if (provide) {
    vm._provided = typeof provide === &#39;function&#39;
      ? provide.call(vm)
      : provide
  }  if (inject) {    // inject is :any because flow is not smart enough to figure out cached
    // isArray here
    const isArray = Array.isArray(inject)    const keys = isArray
      ? inject
      : hasSymbol
        ? Reflect.ownKeys(inject)
        : Object.keys(inject)    for (let i = 0; i < keys.length; i++) {      const key = keys[i]      const provideKey = isArray ? key : inject[key]      let source = vm      while (source) {        if (source._provided && source._provided[provideKey]) {
          vm[key] = source._provided[provideKey]          break
        }
        source = source.$parent
      }
    }
  }
}

从中可以看到,在这个版本 provide 和 inject 是一起初始化的。之后,将 provide 传给 vm._provide ,在获取 inject 选项的时候代码判断了 inject 是否为数组,如果是数组直接遍历数组,之后查找 provide 的代码差不多。
所以我推测: 2.5.0+

소스 코드 위치

전과 마찬가지로 초기화 방법은 Vue의 _init 방법에 있습니다.
rrreee

여기에서 initInjectionsinitProvide 메소드를 찾으세요. 이것이 provideinject의 초기화 메소드입니다. 두 방법 모두 src/core/instance/inject.js에 있습니다. 🎜

provide

🎜provide 옵션은 객체이거나 객체를 반환하는 함수여야 합니다. 이 개체에는 하위 항목에 삽입할 수 있는 속성이 포함되어 있습니다. ES2015 기호를 이 객체의 키로 사용할 수 있지만 이는 Symbol 및 Reflect.ownKeys를 기본적으로 지원하는 환경에서만 작동합니다. 🎜
🎜먼저 소스 코드를 살펴보세요. 🎜rrreee🎜provide는 데이터를 아래쪽으로 전달하는 옵션입니다. 여기서는 먼저 제공 옵션의 콘텐츠를 가져옵니다. 제공 옵션이 있는 경우 제공 옵션을 vm._provided에 전달하여 Vue 인스턴스 전역 데이터가 됩니다. 🎜더 명확하게 설명하려면 여기 예시를 보세요. 다음 예시에서는 foo 데이터가 전달되고 데이터 콘텐츠는 bar입니다. 🎜rrreee

inject

🎜inject 옵션은 문자열 배열 또는 객체여야 하며, 객체의 키는 로컬 바인딩의 이름을 나타내고, 값은 해당 키(문자열 또는 기호)입니다. 사용 가능한 주사제 중에서 검색하세요. 🎜
🎜소스코드🎜rrreee🎜간단한 소스코드를 보실 수 있습니다. 먼저 resolveInject 메소드를 통해 인젝션 옵션 검색 결과를 얻으시고, 검색 결과가 있으면 순회하세요. 데이터와 게터에 세터를 추가합니다. 🎜그런 다음 resolveInject 메서드를 살펴보겠습니다. 🎜rrreee🎜주입 옵션의 키 배열을 가져오고 키 배열을 순회한 후 버블링하여 동일한 이름을 가진 키가 있는지 확인합니다. 주입 옵션의 from 속성으로 해당 데이터를 결과에 전달하고, 그렇지 않은 경우 주입에 기본값 또는 기본 방법을 설정하는 기본 옵션이 있는지 확인하고 마지막으로 기본값을 반환합니다. 결과 객체를 반환합니다. 🎜그래서 inject는 기본값으로 작성해야 합니다: 🎜rrreee🎜 또는 검색 키와 기본값을 사용하여: 🎜rrreee🎜 또는 기본값에 대한 팩토리 메소드 설정: 🎜rrreee🎜좋아요, 저는 이것이 다음과 같다는 것을 인정합니다. 공식 홈페이지에서 인용한 세 가지 예시~ 하지만 그냥 말이 되는 내용입니다. 🎜여기서 궁금한 점이 있습니다. 소스 코드에서 from과 default가 적극적으로 식별되기 때문에 공식 홈페이지에는 🎜
🎜2.5.0+의 주입은 기본값을 설정하여 변경할 수 있습니다. .이 선택 사항이 됩니다: 🎜
🎜그렇다면 다음과 같은 작성 방법이 여전히 사용 가능합니까? 🎜rrreee🎜이런 이유로 Vue의 2.2.0 버전은 어떻게 작성되었는지 확인해볼까요? 🎜rrreee🎜보시다시피 이번 버전에서는 Provide와 Inject가 함께 초기화됩니다. 그 후 vm._provide에 vm._provide가 전달되는데, inject 옵션을 가져올 때 코드는 inject가 배열인지 여부를 확인하고, 배열인 경우 배열을 직접 순회한 다음, 제공을 찾는 코드는 거의 동일합니다. . 🎜그래서 저는 추측합니다: 2.5.0+ 이후에는 더 이상 제공 검색에 배열 형식 삽입을 사용할 수 없습니다. 🎜🎜🎜

위 내용은 Vue.js 소스 코드 학습 제공 및 주입의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.