当前位置: 首页 > news >正文

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

provide 和 inject 实现爷孙组件通信

介绍

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

  • provide

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

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

  • inject

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

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

实现原理

provide 方法

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

  • 创建 provide 对象:
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 方法用于接收子组件传递的消息。

// 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 参数。
// 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 方法将消息传递给祖先组件。

// 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 中定义的值。

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

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 方法用于接收子组件传递的消息。

// 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 参数。
// 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 方法将消息传递给祖先组件。

// 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可能会导致组件之间的耦合度增加,影响代码的调试和维护。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 机器学习和深度学习的区别是什么?
  • 【WPF】Border的使用
  • 【Java数据结构】泛型的进阶部分(泛型通配符)
  • 数据挖掘顶会ICDM 2024论文分享┆MetaSTC:一种基于聚类和元学习的时空预测框架
  • JS获取页面中video标签视频的封面和时长
  • ctfshow-命令执行
  • nacos 安装 centos7 docker
  • Pytorch深度学习快速入门笔记【小土堆】
  • Linux基础环境搭建(CentOS7)- 虚拟机准备_搭建hadoop能使用桥接模式吗
  • HTML5中`<area>`标签深入全面解析
  • HS光流法原理与实现
  • 在职研生活学习--20240907
  • Verilog FPGA 仿真 控制任务
  • 开发中ostringstream,格式化输出的问题
  • 7.测试用例设计方法 + Bug
  • “大数据应用场景”之隔壁老王(连载四)
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Apache Spark Streaming 使用实例
  • conda常用的命令
  • Docker容器管理
  • ES10 特性的完整指南
  • Javascript弹出层-初探
  • JS字符串转数字方法总结
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • 阿里云应用高可用服务公测发布
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 回顾 Swift 多平台移植进度 #2
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 那些年我们用过的显示性能指标
  • 前端_面试
  • 前嗅ForeSpider采集配置界面介绍
  • 写代码的正确姿势
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 京东物流联手山西图灵打造智能供应链,让阅读更有趣 ...
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​马来语翻译中文去哪比较好?
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • (1)STL算法之遍历容器
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (Java入门)抽象类,接口,内部类
  • (k8s中)docker netty OOM问题记录
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (十一)手动添加用户和文件的特殊权限
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (一)80c52学习之旅-起始篇
  • *** 2003
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET/C#⾯试题汇总系列:⾯向对象
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @vue/cli 3.x+引入jQuery
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt