首页IT科技vue父子组件间的参数传递是如何做到的(Vue3父子组件间传参通信)

vue父子组件间的参数传递是如何做到的(Vue3父子组件间传参通信)

时间2025-05-04 17:37:14分类IT科技浏览4606
导读:前言 本文主要是记录Vue3在setup语法糖下的父子组件间传参的四种方式...

前言

本文主要是记录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"> interface Props { 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参数至父组件 const transValue = () => { 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>("") const getSonValue = (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>("我是要暴露给父组件的值") // 暴露给父组件的方法 const toFatherMethod = () => { 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() const getSonMethod = () => { 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> <script setup lang="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>("我是给所有子组件的值") /** * 修改父组件值的方法 */ const changeValue = () => { toChildValue.value = "我是父组件修改的值" } // 定义一个注入key的类型(建议将注入 key 的类型放在一个单独的文件中            ,这样它就可以被多个组件导入) interface ProvideType { 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 的类型放在一个单独的文件中             ,这样它就可以被多个组件导入) interface ProvideType { 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"; // 定义注入值的类型 interface ProvideType { 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
声明:本站所有文章      ,如无特殊说明或标注       ,均为本站原创发布      。任何个人或组织                  ,在未征得本站同意时         ,禁止复制    、盗用                 、采集            、发布本站内容到任何网站  、书籍等各类媒体平台                。如若本站内容侵犯了原著者的合法权益    ,可联系我们进行处理           。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
python3列表删除元素(python删除元素的使用条件) python 函数与方法(python函数式编程如何理解)