api文档

https://v3.cn.vuejs.org/guide/component-provide-inject.html#provide-inject

源码地址

https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiInject.ts

分析

import { instance } from './components'

export function provide(key, value) {
    // provide 必须要用在setup中 因为要拿实例
    if (!instance) return // 如果没有实例 则直接返回 说明这个方法没有在setup中使用
    let parentProvides = instance.parent && instance.parent.provide // 获取父亲的provide + 自己的provide

    // 第一次应该创建一个全新的provides,后续就用自己的
    let currentProvides = instance.provides // 自己的
    if (currentProvides === parentProvides) {
        // provides: parent ? parent.provides : Object.create(null), 默认是相同的
        //  说明是第一次
        currentProvides = instance.provides = Object.create(parentProvides) // 这样就可以让子不能修改父provide
    }
    // 下一个儿子会获取所有的provide

    currentProvides[key] = value
}

// 前置条件 组件的实例的provides 指向的是parent的provides
// 1) 我们先取出自己父亲身上的provides ,默认是父亲的provides,创建一个新的provides 重新给自己的provides赋值
// 2) 在上面添加属性
// 3) 再次provide的时候, 拿父亲的provides,再取出自己的provides,此时不想等了,直接用自己身上的添加属性

// provide('a', 1)
// provide('b', 1)
// provide('c', 1) // 不能覆盖

export function inject(key, defaultValue?) {
    // debugger
    if (!instance) return
    const provides = instance.parent && instance.parent.provides // 父组件的provides
    if (provides && key in provides) {
        return provides[key]
    } else {
        return defaultValue
    }
}

eavan2022-07-23_13-37-40.jpg

源码地址:https://github.com/vuejs/core/blob/main/packages/runtime-core/src/component.ts

首先vue创建组件实例的时候会在自己身上默认初始化一个provides对象,这样就可以用===去比较是否进行provide属性,没有则用父亲的provides属性当原型新建一个对象(这样能避免相同的值被覆盖)

总结

实际上vue用到了 原型式继承(Object.create) 的方法,让每一层能够去获取到上层提供的属性,并且让每一层都能隔离开,无法影响到上层的数据,这样就形成了一个单项数据流

Last modification:September 23, 2022
If you think my article is useful to you, please feel free to appreciate