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

Vue3中的常见组件通信之`provide`、`inject`

Vue3中的常见组件通信之provideinject

概述

​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refsparent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。

组件关系传递方式
父传子1. props
2. v-model
3. $refs
4. 默认插槽、具名插槽
子传父1. props
2. 自定义事件
3. v-model
4. $parent
5. 作用域插槽
祖传孙、孙传祖1. $attrs
2. provide、inject
兄弟间、任意组件间1. mitt
2. pinia

props和自定义事件详见:
Vue3中的常见组件通信之props和自定义事件

mitt用法详见:
Vue3中的常见组件通信之mitt

v-model用法详见:
Vue3中的常见组件通信之v-model

$attrs用法详见:
Vue3中的常见组件通信之$attrs

$refs$parent详见:
Vue3中的常见组件通信之$refs$parent

接下来是provide和inject。

7.provide和inject

provideinject用于当前组件向其后代组件直接通信,需要先在祖先组件中通过provide配置向后代组件提供数据,然后在后代组件中通过inject配置声明接收数据。

7.1准备三个组件

先准备三个组件,分别为父组件、子组件和孙组件,具体代码如下:

父组件代码:

<template><div class="father"><h3>父组件</h3><h4>用户订单详情</h4><ul><li>订单编号:{{ oderDetail.id }}</li><li>订单用户:{{ oderDetail.username }}</li><li>订单商品:{{ oderDetail.goods }}</li><li>订单价格:{{ oderDetail.price }}</li></ul><Child/></div>
</template><script lang="ts" setup name="Father">
import Child from './Child.vue'
import {reactive} from 'vue'let oderDetail = reactive({id:"abc01",username:'xiaopeng',goods:"神仙水",price:998
})
</script><style scoped>.father{background-color: rgb(112, 150, 66);margin: 10px;padding: 10px;border-radius: 5px;}
</style>

子组件代码:

<template><div class="child"><h3>子组件</h3><GrandChild/></div>
</template><script lang="ts" setup name="Child">import GrandChild from './GrandChild.vue'</script><style scoped>.child{background-color: burlywood;margin: 10px;padding: 10px;border-radius: 10px;}
</style>

孙组件代码:

<template><div class="grandChild"><h3>这是孙组件</h3></div>
</template><script lang="ts" setup name="GrandChild"></script><style scoped>.grandChild{background-color: aqua;margin: 10px;padding:10px;border-radius: 5px;}
</style>

运行效果如下:

image-20240609172455063

7.2 祖传孙通信的实现

在父组件中引入provide,并提供数据

import {reactive,provide} from 'vue'
//提供数据
provide('oderDetail',oderDetail)

注意此处第一个参数的名字可以是任意的,第二个参数为数据,如果是多个数据,可以为对象格式的数据。

在后代组件中(以孙组件为例)引入inject,并注入数据:

import { inject } from 'vue';//注入数据
let oderDetail = inject('oderDetail')

注意inject中的第一个参数必须与祖组件中provide中第一个参数相同,第二个参数为默认值,即当父组件中没有传递'oderDetail',那么孙组件中的oderDetail的值就是procide中的第二个参数。

孙组件中在页面中呈现:

<h4>父组件传递过来的用户订单详情</h4><ul><li>订单编号:{{ oderDetail.id }}</li><li>订单用户:{{ oderDetail.username }}</li><li>订单商品:{{ oderDetail.goods }}</li><li>订单价格:{{ oderDetail.price }}</li></ul>

注意上面代码中VS Code进行TS检查,会提示oderDetail有错误,但是实际不影响页面呈现,运行结果如下:

image-20240609233257739

接下来需要处理ts的问题,ts显示oderDetail类型为未知,那么可以在定义oderDetail的时候给个默认值,如下代码:

let oderDetail = inject('oderDetail',{id:'',username:'',goods:'',price:0})

此时VS Code就不再报错,并且运行结果一样。

7.3 孙传祖通信的实现

provide和inject也可以实现孙传祖通信,需要在父组件中定义一个函数,并传递给后代:

//方法
function discount(value:number){oderDetail.price = oderDetail.price * value/10
}
//提供方法
provide('discount',discount)

孙组件中接收方法:

let discount = inject('discount',(value:number)=>{})

孙组件中添加按钮并绑定单击事件触发接收的方法,并传递参数:

<button @click="discount(7)">父组件中的订单价格打7折</button>

运行后单击按钮可以实现更改父组件中的价格,由于孙组件中接收的数据为相应式的,因此更改父组件中的价格,孙组件中的订单价格也会相应变化,如下图所示:

至此以及实现了孙传祖通信。

不过上面代码还可以简化,之前提到过provide第二个参数如果是多个数据,可以为对象格式的数据,这样就可以把数据和对象同时传递和接收,如下代码所示:

//提供数据和方法
provide('oderContent',{oderDetail,discount})
let {oderDetail,discount} = inject('oderContent',{oderDetail:{id:'',username:'',goods:'',price:0},discount:(value:number)=>{}})

这样运行的结果是完全一样的。

7.4 小结

provideinject用于当前组件向其后代组件直接通信,需要先在祖先组件中通过provide配置向后代组件提供数据,然后在后代组件中通过inject配置声明接收数据。这个过程是完全不打扰中间的子组件,实现的是祖孙间的直接通信。

下面是完整代码:

父组件:

<template><div class="father"><h3>父组件</h3><h4>用户订单详情</h4><ul><li>订单编号:{{ oderDetail.id }}</li><li>订单用户:{{ oderDetail.username }}</li><li>订单商品:{{ oderDetail.goods }}</li><li>订单价格:{{ oderDetail.price }}</li></ul><Child/></div>
</template><script lang="ts" setup name="Father">
import Child from './Child.vue'
import {reactive,provide} from 'vue'//数据
let oderDetail = reactive({id:"abc01",username:'xiaopeng',goods:"神仙水",price:998
})//方法
function discount(value:number){oderDetail.price = oderDetail.price * value/10
}
// //提供数据
// provide('oderDetail',oderDetail)
// 提供方法
// provide('discount',discount)//提供数据和方法
provide('oderContent',{oderDetail,discount})</script><style scoped>.father{background-color: rgb(112, 150, 66);margin: 10px;padding: 10px;border-radius: 5px;}
</style>

子组件:

<template><div class="child"><h3>子组件</h3><GrandChild/></div>
</template><script lang="ts" setup name="Child">import GrandChild from './GrandChild.vue'</script><style scoped>.child{background-color: burlywood;margin: 10px;padding: 10px;border-radius: 10px;}
</style>

孙组件:

<template><div class="grandChild"><h3>这是孙组件</h3><h4>父组件传递过来的用户订单详情</h4><ul><li>订单编号:{{ oderDetail.id }}</li><li>订单用户:{{ oderDetail.username }}</li><li>订单商品:{{ oderDetail.goods }}</li><li>订单价格:{{ oderDetail.price }}</li></ul><button @click="discount(7)">父组件中的订单价格打7折</button></div>
</template><script lang="ts" setup name="GrandChild">
import { inject } from 'vue';// // 注入数据
// let oderDetail = inject('oderDetail',{id:'',username:'',goods:'',price:0})
// let discount = inject('discount',(value:number)=>{})let {oderDetail,discount} = inject('oderContent',{oderDetail:{id:'',username:'',goods:'',price:0},discount:(value:number)=>{}})</script><style scoped>.grandChild{background-color: aqua;margin: 10px;padding:10px;border-radius: 5px;}
</style>

相关文章:

  • webkit 的介绍
  • 大模型网信办备案全网最详细说明(付附件)
  • Docker部署Nginx1.21.5(保姆级图文教程)
  • Mybatis框架的缓存
  • Excel导出实例
  • rust内存分配,内存回收,内存泄露
  • 联华集团:IT团队如何实现从成本中心提升至价值中心|OceanBase 《DB大咖说》(十)
  • (三十)Flask之wtforms库【剖析源码上篇】
  • 动态规划02(Leetcode62、63、343、96)
  • C语言——文件
  • Elastic字段映射(_source,doc_value,fileddata,index,store)
  • 【C语言】解决C语言报错:Array Index Out of Bounds
  • EasyExcel自定义处理器扩展指定行修改样式包括字体颜色
  • 没等来百度惊艳的All in AI,却等来了国产之光的盘古大模型 5.0
  • java-正则表达式 1
  • .pyc 想到的一些问题
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 30天自制操作系统-2
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • Angular Elements 及其运作原理
  • CentOS从零开始部署Nodejs项目
  • C学习-枚举(九)
  • exif信息对照
  • flask接收请求并推入栈
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • If…else
  • Laravel5.4 Queues队列学习
  • Object.assign方法不能实现深复制
  • RxJS: 简单入门
  • Vue2.x学习三:事件处理生命周期钩子
  • vue-cli3搭建项目
  • 创建一个Struts2项目maven 方式
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 蓝海存储开关机注意事项总结
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 前嗅ForeSpider中数据浏览界面介绍
  • 前言-如何学习区块链
  • 浅谈Golang中select的用法
  • 微信小程序实战练习(仿五洲到家微信版)
  • ​Java基础复习笔记 第16章:网络编程
  • #{}和${}的区别?
  • (阿里云在线播放)基于SpringBoot+Vue前后端分离的在线教育平台项目
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (一)SpringBoot3---尚硅谷总结
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .net项目IIS、VS 附加进程调试
  • .NET中GET与SET的用法
  • .stream().map与.stream().flatMap的使用
  • @DataRedisTest测试redis从未如此丝滑
  • [ Python ]使用Charles对Python程序发出的Get与Post请求抓包-解决Python程序报错问题
  • [ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)