0


Vue3父子组件间传参通信

Vue3 父子组件间通信

前言

本文主要是记录Vue3在setup语法糖下的父子组件间传参的四种方式

Vue3+TypeScript

一、父传子 defineProps

父组件传值给子组件主要是由父组件为子组件通过v-bind绑定数值,而后传给子组件;子组件则通过defineProps接收使用。

如下为父组件

Father.vue
<template><div class="fa"><div style="margin: 10px;">我是父组件</div><Son :fatherMessage="fatherMessage"></Son></div></template><script setup lang="ts">import Son from'./Son.vue'import{ref}from"vue";const fatherMessage = ref<string>("我是父组件传过来的值")</script><style scoped>.fa{border: 3px solid cornflowerblue;width: 400px;
  text-align: center;}</style>

如下为子组件Son.vue

<template><div style="margin: 10px;border: 2px solid red">
    我是子组件
    <div style="margin: 5px;border: 2px solid gold">
      父组件传值接收区:{{fatherMessage}}</div></div></template><script setup lang="ts">interfaceProps{
  fatherMessage?: string,}
defineProps<Props>()</script>

父组件

Father.vue

中在调用

Son.vue

这个子组件时,使用

v-bind

绑定参数

fatherMessage

,并传给

Son.vue

子组件

Son.vue

使用

defineProps

接收

fatherMessage

这个参数,而后就可以正常使用该参数。

二、子传父 defineEmits

子组件传值给父组件主要是子组件通过

defineEmits

注册一个自定义事件,而后触发

emit

去调用该自定义事件,并传递参数给父组件。

在父组件中调用子组件时,通过

v-on

绑定一个函数,通过该函数获取传过来的值。

如下为子组件

Son.vue
<template><div style="margin: 10px;border: 2px solid red">
    我是子组件
    <button @click="transValue" style="margin: 5px">传值给父组件</button></div></template><script setup lang="ts">import{ref}from"vue";// 定义所要传给父组件的值const value = ref<String>("我是子组件传给父组件的值")// 使用defineEmits注册一个自定义事件const emit =defineEmits(["getValue"])// 点击事件触发emit,去调用我们注册的自定义事件getValue,并传递value参数至父组件consttransValue=()=>{emit("getValue", value.value)}</script>

如下为父组件

Father.vue
<template><div class="fa"><div style="margin: 10px;">我是父组件</div>
    父组件接收子组件传的值:{{sonMessage}}<Son @getValue="getSonValue"></Son></div></template><script setup lang="ts">import Son from'./Son.vue'import{ref}from"vue";const sonMessage = ref<string>("")constgetSonValue=(value: string)=>{
  sonMessage.value = value
}</script><style scoped>.fa{border: 3px solid cornflowerblue;width: 400px;
  text-align: center;}</style>

父组件

Father.vue

中在调用

Son.vue

这个子组件时,当子组件

Son.vue

需要传参给父组件

Father.vue

时,使用

defineEmits

注册一个事件

getValue

,而后设置点击事件

transValue

去触发

emit

,去调用我们注册的自定义事件

getValue

,并传递

value

参数至父组件。

父组件

Father.vue

在获取子组件

Son.vue

传过来的值时,通过在子组件上使用

v-on

设置响应函数

getValue

**(该函数与子组件中的注册自定义事件

getValue

名称需一致)**,并绑定一个函数

getSonValue

来获取传过来的值。

三、子组件暴露属性给父组件 defineExpose

当父组件想直接调用父组件的属性或者方法时,子组件可以使用

defineExpose

暴露自身的属性或者方法,父组件中使用

ref

调用子组件暴露的属性或方法。
如下为子组件

Son.vue
<template><div style="margin: 10px;border: 2px solid red">
    我是子组件

  </div></template><script setup lang="ts">import{ref, defineExpose}from"vue";// 暴露给父组件的值const toFatherValue = ref<string>("我是要暴露给父组件的值")// 暴露给父组件的方法consttoFatherMethod=()=>{
  console.log("我是要暴露给父组件的方法")}// 暴露方法和属性给父组件defineExpose({toFatherMethod, toFatherValue})</script>

如下为父组件

Father.vue
<template><div class="fa"><div style="margin: 10px;">我是父组件</div><button @click="getSonMethod">获取子组件的方法</button><Son ref="sonMethodRef"></Son></div></template><script setup lang="ts">import Son from'./Son.vue'import{ref}from"vue";const sonMethodRef =ref()constgetSonMethod=()=>{
  sonMethodRef.value.toFatherMethod()
  console.log(sonMethodRef.value.toFatherValue)}</script><style scoped>.fa{border: 3px solid cornflowerblue;width: 400px;
  text-align: center;}</style>

在子组件中定义属性

toFatherValue

和方法

toFatherMethod

,而后通过

defineExpose

暴露出来。
父组件调用时,为子组件绑定一个

ref

,并定义一个

ref

变量

sonMethodRef

,通过调用

sonMethodRef

,来获取子组件暴露出来的属性和方法。

四、依赖注入Provide / Inject

从上面的介绍里我们可以了解到父子组件之间的通信,但是却存在这样的情况:有一些多层级嵌套的组件,形成了一颗巨大的组件树,而某个深层的子组件需要一个较远的祖先组件中的部分数据。在这种情况下,如果仅使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦:
在这里插入图片描述

虽然这里的

Footer

组件可能根本不关心这些

props

,但为了使

DeepChild

能访问到它们,仍然需要定义并向下传递。如果组件链路非常长,可能会影响到更多这条路上的组件。这一问题被称为“prop 逐级透传”,显然是我们希望尽量避免的情况。

provide

inject

可以帮助我们解决这一问题。 一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
在这里插入图片描述
如下为父组件

Root.vue
<template><div>
    我是root组件
    <Footer></Footer></div></template><script setup lang="ts">import{ provide, ref }from'vue'import Footer from'./Footer.vue'const toChildValue= ref<string>("我是给所有子组件的值")// 将toChildValue注入到所有子组件中provide(/* 注入名 */'toChildValue',/* 值 */ toChildValue)</script>

如下为子组件

Footer.vue
<template><div>
    我是footer组件
    <div>
      接收父组件的值:{{getFatherValue}}</div><DeepChild></DeepChild></div></template><script setup lang="ts">import DeepChild from"./DeepChild.vue"import{ref,inject,Ref}from"vue";// 获取父组件提供的值// 如果没有祖先组件提供 "toChildValue"// ref("") 会是 "这是默认值"const getFatherValue = inject<Ref<string>>(/* 注入名 */"toChildValue",/* 默认值 */ref(""))</script>

如下为孙子组件

DeepChild.vue
<template><div>
    我是deepChild组件
    <div>
      接收爷爷组件的值:{{getGrandFatherValue}}
    </div></div></template><scriptsetuplang="ts">import{inject, ref, Ref}from"vue";// 获取爷爷组件提供的值// 如果没有爷爷组件提供 "toChildValue"// value 会是 ""const getGrandFatherValue = inject<Ref<string>>(/* 注入名 */"toChildValue",/* 默认值 */ref(""))</script>

当最顶层的组件

Root.vue

传值给所有子组件时,使用

provide

进行注入

provide(/* 注入名 */'toChildValue',/* 值 */ toChildValue)

而后无论哪个子组件想要获取

toChildValue

的值,只需使用

inject

即可

inject<Ref<string>>(/* 注入名 */"toChildValue",/* 默认值 */ref(""))

当提供 / 注入响应式的数据时,如果想改变数据时,建议尽可能将任何对响应式状态的变更都保持在供给方组件中,即根组件

Root.vue

。这样可以确保所提供状态的声明和变更操作都内聚在同一个组件内,使其更容易维护。

有的时候,我们可能需要在注入方组件中更改数据。在这种情况下,我们推荐在供给方组件内声明并提供一个更改数据的方法函数:
如下为父组件

Root.vue
<template><div>
    我是root组件
    <Footer></Footer></div></template><script setup lang="ts">import{InjectionKey, provide, Ref, ref}from'vue'import Footer from'./Footer.vue'const toChildValue= ref<string>("我是给所有子组件的值")/**
 * 修改父组件值的方法
 */constchangeValue=()=>{
  toChildValue.value ="我是父组件修改的值"}// 定义一个注入key的类型(建议将注入 key 的类型放在一个单独的文件中,这样它就可以被多个组件导入)interfaceProvideType{toChildValue: Ref<string>;changeValue:()=>void;}// 为注入值标记类型const toValue =Symbol()as InjectionKey<ProvideType>// 将toChildValue和changeValue注入到所有子组件中provide(/* 注入名 */'toValue',/* 值 */{
  toChildValue,
  changeValue
})</script>
provide

inject

通常会在不同的组件中运行。要正确地为注入的值标记类型,Vue 提供了一个

InjectionKey

接口,它是一个继承自

Symbol

的泛型类型,可以用来在提供者和消费者之间同步注入值的类型。
建议将注入

key

的类型放在一个单独的文件中,这样它就可以被多个组件导入。

// 定义一个注入key的类型//(建议将注入 key 的类型放在一个单独的文件中,这样它就可以被多个组件导入)interfaceProvideType{toChildValue: Ref<string>;changeValue:()=>void;}// 为注入值标记类型const toValue =Symbol()as InjectionKey<ProvideType>

如下为孙子组件

DeepChild.vue
<template><div>
    我是deepChild组件
    <div><button @click="changeValue">改变祖先组件的值</button>{{toChildValue}}</div></div></template><script setup lang="ts">import{inject, ref, Ref}from"vue";// 定义注入值的类型interfaceProvideType{toChildValue: Ref<string>;changeValue:()=>void;}// 解构获取父组件传的值,需要进行强制类型转换const{toChildValue, changeValue}=inject(/* 注入名 */"toValue")as ProvideType
// 不解构时,只需指定类型即可// const value = inject<ProvideType>(/* 注入名 */"toValue")</script>

当祖先组件提供参数与方法时,子组件在解构时需要强制转换该值的类型

// 解构获取父组件传的值const{toChildValue, changeValue}=inject(/* 注入名 */"toValue")as ProvideType

如果子组件在使用时不进行解构,则直接指明类型即可

// 不解构时,直接指定类型即可const value = inject<ProvideType>(/* 注入名 */"toValue")

参考

1、小满ZS 学习Vue3 第二十三章(依赖注入Provide / Inject) https://blog.csdn.net/qq1195566313/article/details/123143981?spm=1001.2014.3001.5501
2、Vue3官网 依赖注入
https://cn.vuejs.org/guide/components/provide-inject.html


本文转载自: https://blog.csdn.net/qq_45397526/article/details/126281133
版权归原作者 不会写代码的小周 所有, 如有侵权,请联系我们删除。

“Vue3父子组件间传参通信”的评论:

还没有评论