一看就会的provide/inject原理(Vue)

246 阅读2分钟
面试官:说一下组件通信的方式  
我:provide/inject , ... ...
面试官:简单说一下provide/inject原理
我:啊,卒......

1.provide/inject使用场景

injectprovide一般都是一起使用的,允许祖先组件向其所有子孙后代注入依赖,不论组件的层次有多深,依赖始终生效的。

  • inject:可以是字符串,对象,以及数组,用于可以在注入内容中搜索。
  • provide:可以为一个对象或者一个返回对象的函数,用于注入依赖。
const parent = {
    provide:{
        a:'aaa'
    }
}

const child = {
    inject:['a'],
    created(){
        console.log(this.a) // 'aaa'
    }
}

同时,我们也可以在data和props种访问注入的值

const child = {
    inject:['a','b'],
    props:{
        propA:{
            default(){
                return this.a
            }
        }
    },
    data(){
        return {
            dataB:this.b
        }
    }

}

我们还可以通过form来表示其源属性,default代表默认值:

const child = {
    inject:{
        aa:{
            from:"a",
            default:"bb"
        }
    }
}

2.inject内部原理

我们知道injectprovide是成对出现的,但是他们的内部实现却是分开的。从之前示例中我们就发现,injectdata/props之前初始化的,而providedata/props后面初始化的。目的是可以让data/props依赖于inject,所以inject的初始化要放在前面。provide在后面也很好理解,因为provide依赖这些值。

2.1 initInjections

很明显,初始化inject的值,就是读取配置的key值,读不到则先父级读下去。是一个自底向上获取的过程。最终找到的内容保存到实例上即可。因为这些值会保存到实例上,所以我们还需要对这些值进行响应式。

export function initInjections (vm) {
    const result = resolveInject(vm.$options.inject,vm)
    Object.keys(result).forEach((key)=>{
        defineReactive(vm,key,result[key])
    })
}

2.2 resolveInject

resolveInject这个函数主要就是从下向上进行查找的操作。

export function resolveInject(inject,vm){
    if(inject){
        const result = Object.create(null);
        const keys = 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.provide && provideKey in source.provide){
                    result[key] = source.provide[provideKey];
                    break;
                }
                source = source.$parent
            }
        }
    return result
    }
}

我们通过for循环拿到每个key值,通过from属性拿到provide源属性。通过while循环来搜索内容,如果找到源值就可以跳出循环。进行下一轮循环查找。

3总结:

  • injectdata/props之前进行初始化(方便data/props可以依赖inject
  • inject通过自下而上的方式拿到源值(provide提供的值)
  • 拿到所有源值后进行本实例的响应式绑定

往期vue源码文章精选: