Vue.js 3.x 中跨层级组件如何传递数据?
provide/inject 基本用法
在 Vue.js 中,跨层级组件如果想要传递数据,我们可以直接使用 props 来将祖先组件的数据传递给子孙组件:

注:上图来自
Vue.js官网:Prop Drilling。
如上图所示,中间组件 <Footer> 可能根本不需要这部分 props,但为了 <DeepChiild> 能访问这些 props,<Footer> 还是需要定义这些 props,并将其传递下去。
有人说我们可以使用 $attrs/$listeners,但依然还要经过中间层级,而使用 Vuex 又过于麻烦,Event Bus 又很容易导致逻辑分散,出现问题后难以定位。
那么,有没有其他方法可以实现直接从祖先组件传递数据给子孙组件呢?答案就是 provide/inject。
祖先组件:
// Root.vue
<script setup>
import { provide } from 'vue'
provide('msg' /* 注入的键名 */ , 'Vue.js' /* 值 */)
</script>
子孙组件:
// DeepChild.vue
<script setup>
import { inject } from 'vue'
const msg = inject('msg' /* 注入的键名 */, 'World' /* 默认值 */)
</script>
具体用法详见:Provide / Inject。
现在,问题解决了:

注:上图来自
Vue.js官网:Prop Drilling。
provide 实现原理
这么神奇的东西,究竟是如何实现的呢?
export function provide<T>(key: InjectionKey<T> | string | number, value: T) {
let provides = currentInstance.provides
const parentProvides = currentInstance.parent && currentInstance.parent.provides
if (parentProvides === provides) {
provides = currentInstance.provides = Object.create(parentProvides)
}
provides[key as string] = value
}
在默认情况下,组件实例的 provides 继承自其父组件。但是当组件实例需要提供自己的值的时候,它使用父组件的 provides 对象作为原型,来创建自己的 provides 对象。这样一来,当使用 inject 时,我们就可以通过原型链来找到父组件提供的数据。
inject 实现原理
inject 的代码也很简单,简单到你看了之后会来一句:

export function inject(
key: InjectionKey<any> | string,
defaultValue?: unknown,
treatDefaultAsFactory = false
) {
const instance = currentInstance || currentRenderingInstance
if (instance) {
// #2400
// to support `app.use` plugins,
// fallback to appContext's `provides` if the instance is at root
const provides = instance.parent == null
? instance.vnode.appContext && instance.vnode.appContext.provides
: instance.parent.provides
if (provides && (key as string | symbol) in provides) {
return provides[key as string]
} else if (arguments.length > 1) {
return treatDefaultAsFactory && isFunction(defaultValue)
? defaultValue.call(instance.proxy)
: defaultValue
}
}
}
inject 的主要功能就两点:
- 通过
in操作获取父组件的数据,in操作会遍历原型链,这就是上面provide的实现中,为什么组件要使用父组件的 provides 对象作为原型来创建自己 provides 对象的原因 - 实现
inject的默认值功能,inject第二个参数为默认值
一句话总结:provide/inject 利用原型链来实现跨层级组件的数据传递。
Vue.js 3.x 中跨层级组件如何传递数据?的更多相关文章
- vue.js入门(3)——组件通信
5.2 组件通信 尽管子组件可以用this.$parent访问它的父组件及其父链上任意的实例,不过子组件应当避免直接依赖父组件的数据,尽量显式地使用 props 传递数据.另外,在子组件中修改父组件的 ...
- Vue.js 系列教程 2:组件,Props,Slots
原文:intro-to-vue-2-components-props-slots 译者:nzbin 这是关于 JavaScript 框架 Vue.js 五个教程的第二部分.在这一部分,我们将学习组件, ...
- 每天记录一点:NetCore获得配置文件 appsettings.json vue-router页面传值及接收值 详解webpack + vue + node 打造单页面(入门篇) 30分钟手把手教你学webpack实战 vue.js+webpack模块管理及组件开发
每天记录一点:NetCore获得配置文件 appsettings.json 用NetCore做项目如果用EF ORM在网上有很多的配置连接字符串,读取以及使用方法 由于很多朋友用的其他ORM如S ...
- Vue.js 父子组件相互传递数据
父传子 : 子组件接收变量名=父组件传递的数据 如::f-cmsg="fmsg" 注意驼峰问题 子传父:@子组件关联的方法名 = 父组件接受的方法名 如:@func=" ...
- vue.js 组件之间传递数据
前言 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.如何传递数据也成了组件的重要知识点之一. 组件 组件与组件之间,还存在着不同的关 ...
- Vue.js 桌面端自定义滚动条组件|vue美化滚动条VScroll
基于vue.js开发的小巧PC端自定义滚动条组件VScroll. 前段时间有给大家分享一个vue桌面端弹框组件,今天再分享最近开发的一个vue pc端自定义滚动条组件. vscroll 一款基于vue ...
- vue.js基础知识篇(6):组件详解
第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...
- Vue.js 2.x笔记:组件(5)
1. 组件简介 组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码. 组件:为了拆分Vue实例的代码量,以不同的组件来划分不同的功能模块,需要 ...
- vue.js 二维码生成组件
安装 通过NPM安装 npm install vue-qart --save 插件应用 将vue-qart引入你的应用 import VueQArt from 'vue-qart' new Vue({ ...
随机推荐
- Redis的持久化方案(三)
Redis的所有数据都是保存到内存中的. Rdb:快照形式,定期把内存中当前时刻的数据保存到磁盘.Redis默认支持的持久化方案. aof形式:append only file.把所有对redis数据 ...
- java-設計模式-生成器
生成器模式Bulider 使你能够分步骤创建复杂对象. 该模式允许你使用相同的创建代码生成不同类型和形式的对象. 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示. 将一个复杂的 ...
- MyBatis 实现一对一有几种方式?具体怎么操作的?
有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次, 通过在 resultMap 里面配置 association 节点配置一对一的类就可以完成: 嵌套查询是先查一个表,根据这个表里面的结果的 ...
- 什么是 bean 的自动装配?
Spring 容器能够自动装配相互合作的 bean,这意味着容器不需要和配置,能通 过 Bean 工厂自动处理 bean 之间的协作.
- JVM的基础知识
一.JVM的基础知识 1.JVM内存结构: 1.JVM堆内存结构: 2.JVM内存分配: 3.Java的堆机构和垃圾回收: 4.Jvm堆内存配置参数: 5.JVM新生代概念和配置: 6.JVM老生代概 ...
- USART_GetITStatus()和USART_GetFlagStatus()的区别
USART_GetITStatus()和USART_GetFlagStatus()的区别 都是访问串口的SR状态寄存器,唯一不同是,USART_GetITStatus()会判断中断是否开启,如果没开启 ...
- C++ | 简单工厂模式 | 复数计算器
简单工厂模式最直观的一个应用便是实现一个计算器的程序. 比如,公司让你给计算器添加一个幂运算的功能,你只需要设计一个幂运算的类,并实现幂运算的逻辑,然后让该类继承自运算类即可. 简单工厂模式: 简单工 ...
- char的越界赋值即其原理剖析
思考: int ch = 'A'; int ch1 = 65; int ch2 = 321; printf("%c %c %c\n", ch, ch1, ch2);的输出结果是什么 ...
- 顺利通过EMC实验(8)
- webpack系列——webpack3导入jQuery的新方案
本文的目的 拒绝全局导入jQuery!! 拒绝script导入jQuery!! 找到一种只在当前js组件中引入jQuery,并且使用webpack切割打包的方案! 测试环境 以下测试在webpack3 ...