当前位置:首页 > 技术文章 > 正文内容

Vue3开发极简入门(16):祖孙组件间通信之provide&inject

前文说了Vue的组件间关系,有父子、爷孙、其他关系。例如之前的Father、Son是父子关系,App与Son就是爷孙关系。而props的Son,与emits的Son,就是其他关系。

前文的props是父传子,emits是子传父。靠这俩,如果想实现爷孙组件间通信,比较麻烦,爷通过props到父,父通过props到子;子通过emits到父,父通过emits到爷。如果最外到最里面的组件,中间隔的N个组件,都这么过桥一下,就比较恶心了。

这种情况下,可以用provide&inject。

爷组件,Grandpa.vue:

<template>
    <div class="grandpa">
        <h1>爷组件</h1>
        司机:{{ driverName }}<br />
        发车时间:{{ departTime }}
        <Father />
    </div>
</template>
<script lang='ts' setup name='grandpa'>
import Father from './Father.vue';
import {  provide, ref, type Ref } from 'vue';

const departTime = ref('待定')
const driverName = ref('无')

function setDriver(val: string) {
    driverName.value = val
}

provide<Ref<string>>('departTime',departTime)
provide<Function>('setDriver',setDriver)

</script>
<style scoped>
.grandpa {
    background-color: aquamarine;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    height: 100%;
}
</style>

父组件,就是导入了Son.vue,其他什么代码都没有:

<template>
    <div class="father">
        <h1>父组件</h1>
        <h2>整件事情,雨我无瓜~~</h2>
        <Son />
    </div>
</template>
<script lang='ts' setup name='Father'>
import Son from './Son.vue';
</script>
<style scoped>
.father {
    background-color: darkseagreen;
    padding: 10px;
    margin-top: 10px;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    width: 90%;
    margin: auto;
}
</style>

孙组件:

<template>
    <div class="son">
        <h1>孙组件</h1>
        发车时间:{{ departTime }} <br>
        <button @click="letsGo">发车上报</button>
    </div>
</template>
<script lang='ts' setup name='Son'>
import { inject, type Ref, ref } from 'vue';

const departTime = inject<Ref<string>>('departTime', ref(""))
const setDriver = inject<Function>('setDriver', (params: string) => { })

function letsGo() {
    departTime.value = "2024-01-01 11:11:11." + Math.random()
    setDriver('司机A')
}
</script>
<style scoped>
.son {
    background-color: silver;
    padding: 10px;
    margin-top: 10px;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    width: 80%;
    margin: auto;
}
</style>

代码都很好理解,祖代组件定义的属性、Function,用

provide('key名',属性或方法)

提供出去。

后代组件用

inject('key名')

注入接收。

这里有几个要注意的:

  • 祖代提供的属性如果不是响应式数据,在后代这里被视为常数,无法修改。使用响应式数据,后代修改了,祖代也会同步变化。
  • 网上很多资料这么写:
const test=inject('test');
const testFn=inject('testFn')

但是在使用时,IDE会报类型为未知。解决方法有:

  1. 注入时给默认值:
const test=inject('test',ref('默认值'));
const testFn1=inject('testFn1',() => {});
const testFn2=inject('testFn2',(param:type) => {}
  1. 类型断言:
const test=inject('test') as Ref<string>;
const testFn=inject('testFn') as Function

这种写法就是开发人员非常确定传入的类型一定是as的这个,让TypeScript放心大胆的去用。

  • 显示指定类型信息,并加上默认值,就是本文代码的写法,这样能保持代码的类型安全性和可维护性。其实provide不用显示指定类型信息也可以,但是带上了,代码的可读性可维护性就更好了。

相关文章

中信泰富&amp;明源云——搭建营销费用管理系统,实现3个在线化

3月23日,中信泰富地产与明源云合作的营销费用管理系统业务解决方案汇报在中信泰富大厦顺利结束。 (会议现场)这是自双方合作以来,继今年1月底项目启动会后的又一重要推进动作,本次汇报得到了双方领导的高度...

费用报销单填写及粘贴全攻略:避免常见错误!附费用报销管理系统

费用报销单是企业日常财务管理中的重要工具,用于记录和核销员工在工作中产生的各类费用。填写准确的费用报销单不仅能够保证财务报销流程的顺利进行,还能提高工作效率,确保公司资金的合理使用。在填写报销单时,员...

适合在任何地方使用的 Linux:15 个小型 Linux 发行版

如果你有一台老旧的 PC 或超小型设备,这些 Linux 发行版中的一个应该适合你。来源:https://linux.cn/article-12281-1.html作者:David Gewirtz译者...

7 款最佳 Linux 桌面发行版,颜值天花板

一、elementary OS二、Deepin三、Pop!_OS四、Manjaro Linux五、KDE Neon六、Zorin OS七、Nitrux OS想必大家都知道三大常用操作系统:Linux、...

2023 年 10 个最佳 Linux 桌面发行版

Linux 操作系统在桌面领域的发展已经不再被忽视,越来越多的用户正在考虑切换到 Linux 上。在 2023 年,我们可以期待更多的 Linux 桌面发行版的推出和发展。这里列举了 10 个最佳的...

Vue3 中,父子组件如何传递参数?(vue父子组件传递数据方法)

在 Vue3 中,组件化开发是非常重要的特征,那么组件之间传值就是开发中常见的需求了。组件之间的传值三种方式:父传子、子传父、非父子组件传值。一、父传子( defineProps )父组件主要通过使用...