在vue中,组件之间的通讯方式有很多种, 比如父组件向子组件传参使用props、子组件与父组件通信使用emit、兄弟组件通信使用eventBus/(provides/inject)。现在就一起来研究一下provide与inject的实现吧.
provide
在开发过程中, 我们经常会在父组件或更上级的组件中使用provide, 然后在子孙组件中使用inject来接受, vue中的provideAPI给我们的开发带来了很大的便利,而且在使用过程中, 父级组件不需要知道哪些子孙组件在调用当前的provide, 而子孙组件也不需要知道当前inject调用的函数来自哪里。 下面让我们一起来看一下vue3源码中关于provideAPI的实现吧。
function provide<T>(key: InjectionKey<T> | string | number, value: T) {
// 如果定义当前provide的组件不存在 在开发环境下发出警告⚠️
if (!currentInstance) {
if (__DEV__) {
warn(`provide() can only be used inside setup().`)
}
} else {
let provides = currentInstance.provides
const parentProvides =
currentInstance.parent && currentInstance.parent.provides
if (parentProvides === provides) {
provides = currentInstance.provides = Object.create(parentProvides)
}
// TS doesn't allow symbol as index type
// 相同key值的情况下 父级组件的provide会覆盖根组件的provide
provides[key as string] = value
}
}
可以看到,相对与watchAPI来说 provide的代码并不是很长, 让我带大家一起分析一下吧. 从代码中可以看到 provide函数其实只做了一件事情, 就是将当前传入的函数添加到了provides对象中, 在其中需要注意的一点是, 当你在根组件传入一个provide之后, 如果key值相同,在父组件中传入的provide会覆盖根组件中的provide, 这点在开发过程中还是需要注意的. 接下来一起在看一下inject的实现吧.
inject
上面说到provideAPI方法将接受的所有key、value全部放到了一个provides对象中, 那么有些小伙伴应该可以猜到, inject函数其实是对provides中的方法进行了调用, 接下来就一起来看一下尤大的代码吧
function inject(
key: InjectionKey<any> | string,
defaultValue?: unknown,
treatDefaultAsFactory = false
) {
// fallback to `currentRenderingInstance` so that this can be called in
// a functional component
const instance = currentInstance || currentRenderingInstance
if (instance) {
// #2400
// to support `app.use` plugins,
// fallback to appContext's `provides` if the intance is at root
const provides =
instance.parent == null
? instance.vnode.appContext && instance.vnode.appContext.provides
: instance.parent.provides
// 判断当前的函数是否存在于provides数组 如果存在调用当前函数, 如果不存在则判断第二个参数是否存在, 如果第二个参数存在 判断第二个参数是否为一个函数, 如果为函数则调用这个函数, 否则直接返回第二个参数 如果第二个参数不存在则返回一段警告
if (provides && (key as string | symbol) in provides) {
// TS doesn't allow symbol as index type
return provides[key as string]
} else if (arguments.length > 1) {
return treatDefaultAsFactory && isFunction(defaultValue)
? defaultValue()
: defaultValue
} else if (__DEV__) {
warn(`injection "${String(key)}" not found.`)
}
} else if (__DEV__) {
warn(`inject() can only be used inside setup() or functional components.`)
}
}
在inject函数中, 该函数接收三个参数, 第一个参数为你要调用的provide方法的key, 通过provides去调用当前的key值所对应的方法, 第二个参数为一个默认值, 第三个参数是一个选填的布尔值, 咱们接着往下分析,
- 代码中首先当前实例是否为根组件, 接着判断了provides中是否存在当前需要调用函数的key, 如果存在则返回这个函数的执行结果,
- 如果不存在则判断inject接收参数的数量, 这时候就要看第二个参数和第三个参数了, 第三个参数treatDefaultAsFactory更像是一个开关, 用来控制是否需要第二个参数,
- 如果treatDefaultAsFactory为true且第二个参数是个函数, 直接返回这个函数的默认结果, 否则会直接返回第二个参数.
- 如果不满足上述条件则会返回一段警告.
怎么样,看完之后是不是觉得provide很简单呢?。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!