vue provide和inject原理(源码)
2021-07-26 本文已影响0人
vivianXIa
使用
provide和inject主要用于开发高阶插件和组件时使用。并不推荐应用于程序代码中
父组件提供foo 子组件注入
var Provider = {
provide:{
foo:'bar'
},
//....
}
//子
var Child = {
inject:['foo'],
created(){
console.log(this.foo);
}
}
缺点
数据来源不明确
重名问题
源码:
1入口位置:src/core/instance/init.js 50行左右
initInjections(vm)//子组件将数据注入到自己身上
initProvide(vm);//父组件在初始化的时候提供好数据
2:provide源码
- 位置:src/core/inject.js:第8行
- 说明:其实就是在vm上增加_provide vm._provide.foo = 'bar'
export function initProvide(vm:component){
const provide = vm.$options.provide
if(provide){
vm._provide = typeof provide === 'function' ?provide.call(vm):provide
}
}
export default initInjection(vm:Component){
//拿到inject属性 进行解析
const result = resolveInject(vm.$options.inject,vm)
}
3.inject
- 不停的去从实例上查找source._provided属性,一层层向上查找,找到为止
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)
: 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
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
}
}
总结
在全局vm上添加一个属性provide存我们定义的变量,inject一层层向上查找目标属性,找到为止!