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 中跨层级组件如何传递数据?的更多相关文章

  1. vue.js入门(3)——组件通信

    5.2 组件通信 尽管子组件可以用this.$parent访问它的父组件及其父链上任意的实例,不过子组件应当避免直接依赖父组件的数据,尽量显式地使用 props 传递数据.另外,在子组件中修改父组件的 ...

  2. Vue.js 系列教程 2:组件,Props,Slots

    原文:intro-to-vue-2-components-props-slots 译者:nzbin 这是关于 JavaScript 框架 Vue.js 五个教程的第二部分.在这一部分,我们将学习组件, ...

  3. 每天记录一点:NetCore获得配置文件 appsettings.json vue-router页面传值及接收值 详解webpack + vue + node 打造单页面(入门篇) 30分钟手把手教你学webpack实战 vue.js+webpack模块管理及组件开发

    每天记录一点:NetCore获得配置文件 appsettings.json   用NetCore做项目如果用EF  ORM在网上有很多的配置连接字符串,读取以及使用方法 由于很多朋友用的其他ORM如S ...

  4. Vue.js 父子组件相互传递数据

    父传子 : 子组件接收变量名=父组件传递的数据 如::f-cmsg="fmsg"  注意驼峰问题 子传父:@子组件关联的方法名 = 父组件接受的方法名 如:@func=" ...

  5. vue.js 组件之间传递数据

    前言 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.如何传递数据也成了组件的重要知识点之一. 组件 组件与组件之间,还存在着不同的关 ...

  6. Vue.js 桌面端自定义滚动条组件|vue美化滚动条VScroll

    基于vue.js开发的小巧PC端自定义滚动条组件VScroll. 前段时间有给大家分享一个vue桌面端弹框组件,今天再分享最近开发的一个vue pc端自定义滚动条组件. vscroll 一款基于vue ...

  7. vue.js基础知识篇(6):组件详解

    第11章:组件详解 组件是Vue.js最推崇也最强大的功能之一,核心目标是可重用性. 我们把组件代码按照template.style.script的拆分方式,放置到对应的.vue文件中. 1.注册 V ...

  8. Vue.js 2.x笔记:组件(5)

    1. 组件简介 组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重用的代码. 组件:为了拆分Vue实例的代码量,以不同的组件来划分不同的功能模块,需要 ...

  9. vue.js 二维码生成组件

    安装 通过NPM安装 npm install vue-qart --save 插件应用 将vue-qart引入你的应用 import VueQArt from 'vue-qart' new Vue({ ...

随机推荐

  1. Redis 如何设置密码及验证密码?

    设置密码:config set requirepass 123456 授权密码:auth 123456

  2. 什么是 Spring 的 MVC 框架?

    Spring 配备构建 Web 应用的全功能 MVC 框架.Spring 可以很便捷地和其他 MVC 框架集成,如 Struts,Spring 的 MVC 框架用控制反转把业务对象和控制逻 辑清晰地隔 ...

  3. Effective Java —— 优先考虑依赖注入来引用资源

    本文参考 本篇文章参考自<Effective Java>第三版第五条"Prefer dependency injection to hardwiring resources&qu ...

  4. Kali Linux 下安装配置MongoDB数据库 ubuntu 下安装配置MongoDB源码安装数据库

    Kali Linux 下安装配置MongoDB数据库   1.下载mongodb.tgz 压缩包: 2.解压到:tar -zxvf mongodb.tgz /usr/local/mongodb 3.创 ...

  5. springboot插件

    目前spring官网(http://spring.io/tools/sts/all)上可下载的spring插件只有:springsource-tool-suite-3.8.4(sts-3.8.4).但 ...

  6. 解决webpack项目中打包时候内存溢出的bug JavaScript heap out of memory

    vue 项目 npm run dev 的时候一直卡住不动:后来找到报错是 Ineffective mark-compacts near heap limit Allocation failed - J ...

  7. setTimeout中第一个参数

    永远不要传递字符串作为setTimeout的第一个参数!!!记住第一个参数只允许函数,或者匿名函数!因为传递字符串有陷阱啊!!它就是披着羊皮的eval啊!!而且上下文会变成全局啊!! 第一个参数为可执 ...

  8. ansible模块解析及使用

    模块一:setup(收集远程主机信息) [root@zabbix30 /]# ansible test -m setup 模块二:ping(测试主机是否在线) [root@zabbix30 /]# a ...

  9. Java学习day33

    线程池: 背景:经常创建和销毁.使用量特别大的资源,比如并发情况下的线程,对性能影响很大 思路:提前创建好多个线程.实现重复利用. 好处:提高响应速度,减少了创建新线程的时间:降低资源消耗,重复利用线 ...

  10. SSM整合_年轻人的第一个增删改查_新增

    写在前面 SSM整合_年轻人的第一个增删改查_基础环境搭建 SSM整合_年轻人的第一个增删改查_查找 SSM整合_年轻人的第一个增删改查_新增 SSM整合_年轻人的第一个增删改查_修改 SSM整合_年 ...