组件通信——provide 和 inject 实现爷孙组件通信

news/2024/9/17 18:09:30/ 标签: javascript, vue.js, 前端

provide 和 inject 实现爷孙组件通信

介绍

provideinject 是 Vue.js 提供的一种在组件之间共享数据的机制,它允许在组件树中的任何地方注入依赖项。这对于跨越多个层级的组件间通信特别有用,因此无需手动将 prop 数据逐层传递下去。

  • provide

    • 在一个组件中使用 provide 方法来定义要提供的数据或方法。

    • provide 方法返回一个对象,该对象包含了要提供的数据或方法。

  • inject

    • 在另一个组件中使用 inject 方法来注入这些数据或方法。

    • inject 方法接收一个数组或对象,指明要注入的数据或方法名称。

实现原理

provide 方法

当你在组件中定义 provide 方法时,Vue.js 会执行以下步骤:

  • 创建 provide 对象:
javascript">provide() {return {sharedData: 'Hello from App component!',updateData: this.updateData};
}
  • 附加到组件实例:Vue.js 会在组件实例上附加一个 _provided 属性,存储 provide 方法返回的对象。

inject 方法

当你在组件中定义 inject 方法时,Vue.js 会执行以下步骤:

  • 查找 provide 对象:Vue.js 会从当前组件及其祖先组件中查找 _provided 属性。
    如果找到,则将相应的数据或方法注入到当前组件中。

  • 注入到组件实例:注入的数据或方法会作为属性添加到当前组件实例上,可以通过 this 访问。

优点
  • 简化多层级组件通信:不需要逐层传递 props,可以方便地在组件树中的任意位置提供和注入数据。

  • 灵活性高:可以动态地提供和注入数据或方法,适用于多种场景。

  • 减少代码冗余:减少了逐层传递 props 的代码量,提高了代码的可读性和可维护性。

缺点
  • 调试困难:由于数据传递路径不明确,调试时可能比较困难,尤其是在大型项目中。

  • 组件关系模糊:组件之间的依赖关系变得不清晰,可能导致代码难以理解和维护。

  • 性能开销:大量使用 provideinject 可能导致额外的性能开销,特别是在复杂的应用中。

  • 滥用问题:如果过度使用 provideinject,可能会导致组件之间的耦合度过高,降低代码的可维护性。

vue2.x 使用

grandpa.vue 组件(爷)

  • 使用 provide 方法提供了 message, message2 字符串和一个 sendGradpaMessage 方法。

  • sendGradpaMessage 方法用于接收子组件传递的消息。

javascript">// grandpa.vue<template><div class="grandpa"><h2>爷组件</h2><parent /></div>
</template><script>
import parent from './parent.vue';export default {name: 'grandpa',data() {return {}},provide() {return {message: 'This is some shared data1',message2: 'This is some shared data2',sendGradpaMessage: this.getSendMessage};},components: {parent},methods: {getSendMessage(message) {console.log('Message received:', message);}}
}
</script>

parent.vue 组件(父)

  • 使用 inject 方法注入了从爷组件提供的 message 参数。
javascript">// parent.vue<template><div class="parent"><h2>父组件</h2><span>{{ message }}</span><son /></div>
</template><script>
import son from './son.vue';export default {name: 'parent',data() {return {}},inject: ['message'],components: { son },methods: {}
}
</script>

son.vue 组件(子)

  • 使用 inject 方法注入了从爷组件提供的 message2 字符串和一个 sendGradpaMessage 方法。

  • 当点击按钮时,调用 sendGradpaMessage 方法将消息传递给祖先组件。

javascript">// son.vue<template><div class="son"><h2>孙组件</h2><span>{{ message2 }}</span><el-button type="primary" @click="sendMessage">发送消息</el-button></div>
</template><script>
export default {name: 'son',data() {return {}},inject: ['message2', 'sendGradpaMessage'],methods: {sendMessage() {const msg = 'Hello from son component!';this.sendGradpaMessage(msg);}}
}
</script>

上述示例中:

  • grandpa.vue 组件通过 provide 方法提供了 message, message2 两个参数和一个名为 sendGradpaMessage 的方法。

  • parent.vue 组件通过 inject 接收了 message 参数,并在模板中使用 message

  • son.vue 组件通过 inject 接收了 message2 参数,并在模板中使用 message,同时通过点击按钮触发 sendGradpaMessage 方法将参数 msg 传给了 grandpa.vue 组件。

类型检查

inject 的配置项可以是一个数组或者一个对象。当使用对象形式时,可以指定更多的配置选项,比如类型检查、默认值等。

配置选项详解

  • from:指定 inject 要注入的数据的键名。如果没有指定,则默认为 inject 的键名。

  • default:如果没有从祖先组件中找到对应的数据,则使用这个默认值。这对于确保组件即使在缺少某些数据的情况下也能正常工作是非常有用的。

  • fromdefault 的组合:你可以同时指定 from 和 default,在这种情况下,如果 from 指定的数据不存在,则使用 default 中定义的值。

例如,你可以指定默认值和别名:

javascript">inject: {// 定义别名为 message2 的数据,其来源为 message2message2: {   from: 'message2',// 如果没有提供则使用默认值default: 'Default value if not provided'},// 定义别名为 sendGradpaMessage 的方法sendGradpaMessage: {from: 'sendGradpaMessage',// 如果没有提供则使用一个空函数作为默认值default: () => {}}
}

vue3.x 使用

在 Vue 3.x 中,provideinject 的使用方式有所变化,主要是因为引入了 Composition API。在 Composition API 中,provideinject 的使用更加灵活,并且通常在 setup 函数中进行操作。

注意事项:

1. Composition API 中的使用:

  • 在 Vue 3.x 中,provide 和 inject 必须在 setup 函数中使用。

  • provide 通常用来向子组件提供数据或方法。

  • inject 用来从父组件或其他祖先组件获取数据或方法。

2. 响应式处理:

  • 当使用 provide 提供一个响应式对象时,Vue 3.x 会自动处理它的响应性。然而,如果提供的数据不是响应式的,那么注入的数据也不会是响应式的。

3. 类型安全:

  • 在 TypeScript 项目中,可以使用类型注解来确保 provide 和 inject 的类型安全。

4. 默认值:

  • 在 Vue 3.x 中,inject 可以接受一个默认值作为第二个参数,如果找不到对应的 provide 数据,则使用默认值。

5. 调试:

  • 使用 provide 和 inject 时,确保在开发过程中使用 Vue Devtools 来帮助跟踪数据流。
示例

grandpa.vue 组件(爷)

  • 使用 provide 方法提供了 message, message2 字符串和一个 sendGradpaMessage 方法。

  • sendGradpaMessage 方法用于接收子组件传递的消息。

javascript">// grandpa.vue<template><div class="grandpa"><h2>爷组件</h2><div>{{ num1 }}</div><parent /></div>
</template><script setup lang="ts" name="grandpa">
import { provide, ref } from 'vue';import parent from './parent.vue';// 定义一个可变的值
const message = ref('Hello from grandpa');
const message2 = ref('Hello from Parent');let num1 = ref(0);
// 使用 provide 将这个值暴露给子组件
provide('message', message);
provide('message2', message2);
provide('sendGradpaMessage', getSendMessage);// 接受 son 组件传递的参数
function getSendMessage(num: number) {console.log('msg::: ', num);num1.value = num
}
</script>

parent.vue 组件(父)

  • 使用 inject 方法注入了从爷组件提供的 message2 参数。
javascript">// parent.vue<template><div class="parent"><h2>父组件</h2><span>{{ message2 }}</span><son /></div>
</template><script setup lang="ts" name="parent">
import son from './son.vue';
import { inject, onMounted } from 'vue';// 使用 inject 获取父组件提供的值
const message2 = inject('message2');
</script>

son.vue 组件(子)

  • 使用 inject 方法注入了从爷组件提供的 message2 字符串和一个 sendGradpaMessage 方法。

  • 当点击按钮时,调用 sendGradpaMessage 方法将消息传递给祖先组件。

javascript">// son.vue<template><div class="son"><h2>孙组件</h2><div>{{ message }}</div><el-button type="primary" @click="sendMessage(111)">发送消息</el-button></div>
</template><script setup lang="ts" name="son">import { inject, onMounted } from 'vue';// 使用 inject 获取父组件提供的值
const message = inject('message', '默认值');const sendMessage = inject('sendGradpaMessage', (params: number) => { });</script>

上述示例中:

  • grandpa.vue 组件通过 provide 方法提供了 message, message2 两个参数和一个名为 sendGradpaMessage 的方法。

  • parent.vue 组件通过 inject 接收了 message 参数,并在模板中使用 message

  • son.vue 组件通过 inject 接收了 message2 参数,并在模板中使用 message,同时通过点击按钮触发 sendGradpaMessage 方法将参数 msg 传给了 grandpa.vue 组件。

总结

provideinject 是 Vue.js 中一种用于跨越多个层级组件间通信的机制,通过在组件中定义 provide 方法提供数据或方法,并在其他组件中使用 inject 方法注入这些数据或方法,从而简化了多层级组件间的通信。这种方式不仅减少了逐层传递 props 的代码量,提高了代码的可读性和可维护性,还支持动态提供和注入数据,适用于多种场景。然而,过度使用 provideinject可能会导致组件之间的耦合度增加,影响代码的调试和维护。


http://www.ppmy.cn/news/1525075.html

相关文章

使用Selenium WebDriver捕获网络请求

在进行Web自动化测试时,捕获网络请求是十分重要的。通过这种方式,我们可以了解到页面加载过程中发生的网络活动,这对于调试、性能分析以及确保应用程序按预期工作都非常有用。本文将详细介绍如何使用Selenium WebDriver和Python来实现捕获网络请求的功能。 前置要求 在开始…

启动ros2_control与gazebo仿真

目录 问题&#xff1a;启动my_world.world文件时&#xff0c;报错&#xff1a; 原因&#xff1a; 解决方法&#xff1a; 1. 确保 robot_state_publisher 节点正在运行 2. 检查配置文件 总结&#xff1a; 问题&#xff1a;启动my_world.world文件时&#xff0c;报错&#x…

分支管理

目录 创建分支 切换分支 合并分支 删除分支 合并冲突 创建分支 git branch [分支]指令 创建新的分⽀后&#xff0c;Git 新建了⼀个指针叫dev&#xff0c; * 表⽰当前 HEAD 指向的分⽀是 master 分⽀。另外&#xff0c;可以通过⽬录结构发现&#xff0c;新的 dev 分⽀…

【CSS】尺寸单位

在 CSS 中&#xff0c;常见的尺寸单位有以下几种&#xff1a; 像素&#xff08;px&#xff09;&#xff1a; 这是最常用的绝对单位。例如 width: 200px; 表示宽度为 200 像素。像素是固定的尺寸&#xff0c;不会随着屏幕分辨率或设备的不同而变化。 备注&#xff1a; 在不同的…

Harmony Next 文件命令操作(发送、读取、媒体文件查询)

查询文件位置 hdc shell mediatool query IMG_20240902_204224.jpg 输出示例 拉取文件 hdc file recv /storage/cloud/100/files/Photo/4/IMG_1725281044_036.jpg aa.jpg 发送文件 hdc file send aa.jpg /storage/media/100/local/files/Docs/Download/ab.jpg 下载目录位置…

兼容pc端和移动端的滑块校验

组件 <template><canvas :class"cvsClass" :width"props.width" :height"props.height" ref"cvs"></canvas> </template><script setup> import { ref, reactive, watch, nextTick } from "vue&q…

【C++开发中XML 文件的妙用】

在C中&#xff0c;XML&#xff08;可扩展标记语言&#xff09;文件通常用于存储配置数据、应用程序设置、数据交换格式等。由于其结构化和可读性强的特点&#xff0c;XML文件在配置管理、序列化、跨平台数据交换以及软件国际化等方面有着广泛的应用。 XML 文件的妙用 配置管理…

Go语言结构体和元组全面解析

Go语言中的复合类型与其应用 在编程中&#xff0c;标准类型虽然方便&#xff0c;但无法满足所有需求。Go通过支持结构体和元组类型&#xff0c;为开发者提供了自定义数据类型的能力。本文将介绍如何定义结构体、如何使用指针操作结构体、如何通过元组返回多个值等内容&#xf…

技术速递|VS Code Java 8月更新 - 重要 Gradle 更新!用户体验与入门向导增强

作者&#xff1a;Nick Zhu 排版&#xff1a;Alan Wang 大家好&#xff0c;欢迎来到 Visual Studio Code for Java 八月更新&#xff01;在这篇博客中&#xff0c;我们将涵盖重要 Gradle 更新、更多用户体验改进以及更好的入门体验&#xff0c;马上开始吧&#xff01; Gradle 更…

【开源免费】基于SpringBoot+Vue.JS图书个性化推荐系统(JAVA毕业设计)

本文项目编号 T 015 &#xff0c;文末自助获取源码 \color{red}{T015&#xff0c;文末自助获取源码} T015&#xff0c;文末自助获取源码 目录 一、系统介绍1.1 业务分析1.2 用例设计1.3 时序设计 二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究…

Rust 函数

文章目录 发现宝藏1. 函数的基本定义2. 函数调用3. 函数参数4. 语句与表达式5. 返回值总结 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 函数是 Rust 编程中的核心组成部分&…

【Go】Golang连接数据库使用HTTP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么 &#x1f3b5; 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time&q…

从100G到400G:利用多模光纤升级数据中心网络

数据中心网络的持续发展 数据中心网络的持续发展涵盖了两个关键方面。首先&#xff0c;必须应对由机器学习和物联网等数据密集型应用所带来的带宽和流量需求的增长挑战&#xff0c;这些应用正在推动现有10G和40G链路的升级&#xff1b;其次&#xff0c;为了满足日益提升的可持…

Leetcode 三数之和

解题思路&#xff1a; 排序数组&#xff1a;首先对数组进行排序&#xff0c;以便使用双指针技术来查找三元组。双指针法&#xff1a;在遍历数组时&#xff0c;遍历固定三元组的第一个元素&#xff0c;然后使用双指针&#xff08;分别指向剩下数组的头和尾并相向而行&#xff0…

基于图谱的记忆存储 - mem0 graph memory + neo4j

log 日志版 【LLM最强大脑】基于图谱的记忆存储 - mem0 graph memory neo4j_哔哩哔哩_bilibili 获取API Key 谷歌邮箱注册&#xff0c;需科学上网&#xff0c;你知道的┗|&#xff40;O′|┛ 嗷~~ 获取 mem0ai key Dashboard | Mem0.ai 获取 neo4j key Neo4j Graph Databa…

WebLogic 笔记汇总

WebLogic 笔记汇总 一、weblogic安装 1、创建用户和用户组 groupadd weblogicuseradd -g weblogic weblogic # 添加用户,并用-g参数来制定 web用户组passwd weblogic # passwd命令修改密码# 在文件末尾增加以下内容 cat >>/etc/security/limits.conf<<EOF web…

SpringMVC基于注解使用

01-拦截器介绍 首先在pom.xml里面加入springmvc的依赖 创建拦截类 在spring-mvc.xml配置拦截器配置 创建控制类测试 拦截器中处理方法之前的方法介绍 拦截器中处理方法之后&#xff0c;渲染之前的方法介绍 拦截器中处理方法之后&#xff0c;渲染之后的方法介绍 判断拦截器和过…

element form rules 验证数组对象属性时如何写判断规则

需求&#xff1a;一个el-form-item里放了2个下拉选择框&#xff0c;规定是最少选择一个&#xff0c;最多这俩都选择值&#xff1b;下拉框的值设置为对象了&#xff0c;所以这俩select的值组成了一个数组里的两个对象 逻辑&#xff1a;感觉只需要把第一个下拉框值&#xff08;即…

默认端口被占用后,如何修改Apache2 端口

你可以通过以下步骤修改 Apache2 的默认端口&#xff08;80 端口&#xff09;&#xff1a; 1. 修改 Apache2 配置文件 首先&#xff0c;你需要编辑 Apache2 的端口配置文件&#xff1a; sudo nano /etc/apache2/ports.conf在文件中&#xff0c;你会看到类似以下的内容&#…

【PostgreSQL里的restartpoint重启点】

不知道大家有没有关注过&#xff0c;配置文件里archive_cleanup_command参数的注释部分有着这么一句"command to execute at every restartpoint",意思是在每个restartpoint时执行的命令。 提起checkpoint大家可能比较熟悉&#xff0c;对于这个restartpoint&#xff…