vue api中提供了provide/inject,那么inject中是如何接收到provide的呢?
/* @flow */
import { hasOwn } from 'shared/util'
import { warn, hasSymbol } from '../util/index'
import { defineReactive, toggleObserving } from '../observer/index'
export function initProvide (vm: Component) {
// 取provide
const provide = vm.$options.provide
if (provide) {
// 如果是方法,执行注入this = vm
vm._provided = typeof provide === 'function'
? provide.call(vm)
: provide
}
}
export function initInjections (vm: Component) {
// 处理inject
const result = resolveInject(vm.$options.inject, vm)
if (result) {
// shouldObserve切换为false,在defineReactive中,调用observe()时跳过new Observe()
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)
}
}
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)
// Reflect.ownKeys(target)返回自身属性key,相当于Object.keys(),但不会受到enumerable影响
// 详细文档见
// [Reflect - JavaScript | MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
const keys = hasSymbol
? Reflect.ownKeys(inject)
: Object.keys(inject)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
// #6574 in case the inject object is observed...
if (key === '__ob__') continue
// TODO 在什么时候挂上的from
const provideKey = inject[key].from
// 查找provide过程
// 当前组件是否存在provideKey,如果有给到result,跳出
// 父级组件赋给source,继续上面的操作
// 直到无父级组件
let source = vm
while (source) {
if (source._provided && hasOwn(source._provided, provideKey)) {
result[key] = source._provided[provideKey]
break
}
source = source.$parent
}
if (!source) {
// inject如果存在default属性,即默认值
if ('default' in inject[key]) {
const provideDefault = inject[key].default
// 如果default是方法,注入vm执行
result[key] = typeof provideDefault === 'function'
? provideDefault.call(vm)
: provideDefault
} else if (process.env.NODE_ENV !== 'production') {
warn(`Injection "${key}" not found`, vm)
}
}
}
return result
}
}
总结
查找provide过程:
# 1. result存储查找到的provide设置
# 2. 循环当前组件inject的keys,当前inject key 为 provideKey
# 3. 当前组件是否存在provideKey,如果有给到result,跳出
# 4. 父级组件赋给source,继续上面的2,3操作
# 5. 直到无父级组件
#朝花夕拾/Front-end/综合应用/vue/源码