认识
2024年03月18日
一、认识
provide
用于提供可以被后代组件注入的值。请注意,注入绑定并非响应式的。这是有意为之的一个设计。如果要注入的值是一个响应式对象,那么这个对象上的属性将会保留响应性。inject()
注入一个由祖先组件或整个应用 (通过 app.provide()
) 提供的值。与注册生命周期钩子的 API
类似,inject()
必须在组件的 setup()
阶段同步调用。
二、provide 工作
provide
工作流如下: 获取当前组件的实例对象, 将传进来的数据存储在当前的组件实例对象上的 provides
上, 并且通过Object.create
把父组件的provides
属性设置到当前的组件实例对象的provides
属性的原型对象上。
export function provide(key, value) {
// 获取当前组件实例
const currentInstance: any = getCurrentInstance()
if(currentInstance) {
// 获取当前组件实例上provides属性
let { provides } = currentInstance
// 获取当前父级组件的provides属性
const parentProvides = currentInstance.parent.provides
// 如果当前的provides和父级的provides相同则说明还没赋值
if(provides === parentProvides) {
// Object.create() es6创建对象的另一种方式,可以理解为继承一个对象, 添加的属性是在原型下。
provides = currentInstance.provides = Object.create(parentProvides)
}
provides[key] = value
}
}
三、inject 工作
inject
工作流如下: 首先获取当前组件的实例对象,然后判断是否根组件,如果是根组件则返回到appContext
的provides
,否则就返回父组件的provides
。如果当前获取的key
在provides
上有值,那么就返回该值,如果没有则判断是否存在默认内容,默认内容如果是个函数,就执行并且通过call
方法把组件实例的代理对象绑定到该函数的this
上,否则就直接返回默认内容。
export function inject(
key,
defaultValue,
treatDefaultAsFactory = false
) {
// 获取当前组件实例对象
const instance = currentInstance || currentRenderingInstance
if (instance) {
// 如果instance位于根目录下,则返回到appContext的provides,否则就返回父组件的provides
const provides =
instance.parent == null
? instance.vnode.appContext && instance.vnode.appContext.provides
: instance.parent.provides
if (provides && key in provides) {
return provides[key]
} else if (arguments.length > 1) {
// 如果存在1个参数以上
return treatDefaultAsFactory && isFunction(defaultValue)
// 如果默认内容是个函数的,就执行并且通过call方法把组件实例的代理对象绑定到该函数的this上
? defaultValue.call(instance.proxy)
: defaultValue
}
}
}