Vue3组件通讯(父传子,子传父,跨组件通讯)

打印 上一主题 下一主题

主题 1056|帖子 1056|积分 3168

本文主要是讲述Vue3在setup语法糖下的组件间通讯
  Vue组件通讯是指在Vue.js中,差异组件之间进行信息交换和共享数据的过程。在前端开发中,组件通讯是非常重要的一部分,因为在一个复杂的应用中,差异的组件通常需要相互协作,共同完成一些功能。
一、父传子组件通讯

父组件通过props将数据传递给子组件,子组件可以通过调用父组件传递的函数来与父组件进行通讯。
下面通过几个实例来讲解:
实验一: 在父组件里,设置子组件的“字符串型”属性(进而用于父组件向子组件传递数据)
 在父组件里,设置子组件的“字符串型”属性(propName="王五" propAge="21"),这就是父组件向子组件传递的数据
  1. //父组件
  2. <script setup>
  3.    import Header from "./components/Header.vue";
  4. </script>
  5. <template>
  6.     <!-- 实验一: 在父组件里,设置子组件的“字符串型”属性(进而用于父组件向子组件传递数据) -->
  7.     <Header propName="王五" propAge="21"  />
  8. </template>
  9. <style scoped>
  10. </style>
复制代码
  1. //子组件
  2. <script setup>
  3.     // props是properties的缩写,意思为属性,
  4.     // defineProps定义的属性是提供给外部进行设置使用的
  5.     // 定义字符串类型的属性
  6.     const props = defineProps(
  7.         ["propName", "propAge"]
  8.     )
  9.     console.log(props);
  10. </script>
  11. <template>
  12.     <div>
  13.         <h3>我是页面头部(子组件)</h3>
  14.     </div>
  15. </template>
  16. <style scoped>
  17.     /* 设置子组件样式 */
  18.     div {
  19.         width:25%;
  20.         background-color: red;
  21.     }
  22. </style>
复制代码
以上例子中,子组件通过 defineProps 声明吸收props
 运行结果:


实验二: 在父组件里,设置子组件的“对象型”属性(进而用于父组件向子组件传递数据) 
在父组件里,设置子组件的“对象型”属性
    const propStudent = {
        name: "李雷",
        age: 19, 
进而用于父组件向子组件传递数据;父组件在调用子组件时,利用 v-bind 绑定参数 propStudent ,并传给子组件
  1. //父组件
  2. <script setup>
  3.    import { reactive } from "vue";
  4.    import Nav from "./components/Nav.vue";
  5.    const propStudent = {
  6.         name: "李雷",
  7.         age: 19,   
  8.    }
  9. </script>
  10. <template>
  11.     <!-- 实验二: 在父组件里,设置子组件的“对象型”属性(进而用于父组件向子组件传递数据)-->
  12.     <Nav v-bind="propStudent"  />
  13. </template>
  14. <style scoped>
  15. </style>
复制代码
  1. //子组件
  2. <script setup>
  3.     // 定义对象类型的属性
  4.     const props = defineProps(
  5.         {
  6.             name:{
  7.                 type:String   // 类型为字符串
  8.             },
  9.             age:{
  10.                 type:Number,  // 类型为数字
  11.                 // 是否必需传值(若必须传值却没有传,则控制台会给出警告)
  12.                 required:true,  
  13.                 default:18    // 默认值
  14.             },        
  15.         }
  16.     )
  17.     console.log(props);
  18. </script>
  19. <template>
  20.     <div>
  21.         <h3>我是页面导航(子组件)</h3>
  22.     </div>
  23. </template>
  24. <style scoped>
  25.     div {
  26.         width:25%;
  27.         background-color: greenyellow;
  28.     }
  29. </style>
复制代码
以上例子中,子组件利用 defineProps 声明吸收props,并且界说对象类型的属性props ,而后就可以正常利用该参数
运行结果:

实验三: 在父组件里,设置子组件的“相应型”属性(进而用于父组件向子组件传递数据)
在父组件里,设置子组件的“相应型”属性( reactive ), 进而用于父组件向子组件传递数据
  1. //父组件
  2. <script setup>
  3.    import { reactive } from "vue";
  4.    import Footer from "./components/Footer.vue";
  5.    const propTeacher = reactive( {
  6.         name: "韩梅梅",
  7.         age: 25,   
  8.    })
  9.    const addTeacherAge = () => {
  10.         propTeacher.age ++
  11.         console.log(`教师年龄为${propTeacher.age}`);      
  12.    }
  13. </script>
  14. <template>
  15.     <!-- 实验三: 在父组件里,设置子组件的“响应型”属性(进而用于父组件向子组件传递数据) -->
  16.     <Footer v-bind="propTeacher"  />
  17.     <button v-on:click="addTeacherAge">在父组件中增加教师年龄</button>
  18. </template>
  19. <style scoped>
  20. </style>
复制代码
上述父组件中,界说了 一个相应式数据 propTeacher 和一个方法 addTeacherAge 。父组件在调用子组件时,利用 v-bind 绑定参数 propTeacher ,并传给子组件;利用方法来增加教师的年龄
  1. //子组件
  2. <script setup>
  3.     // 定义对象类型的属性
  4.     const props = defineProps(
  5.         {
  6.             name:{
  7.                 type:String   // 类型为字符串
  8.             },
  9.             age:{
  10.                 type:Number,  // 类型为数字
  11.                 required:true,  // 是否必需传值(若必须传值却没有传,则控制台会给出警告)
  12.                 default:28   // 默认值
  13.             },        
  14.         }
  15.     )
  16. </script>
  17. <template>
  18.     <div>
  19.         <h3>我是页面底部(子组件), 教师年龄为:  {{ props.age }}</h3>
  20.     </div>
  21. </template>
  22. <style scoped>
  23.     div {
  24.         width:25%;
  25.         background-color: rgb(154, 154, 228);
  26.     }
  27. </style>
复制代码
 子组件中,利用 defineProps 声明吸收props,并且界说对象类型的属性 props ,而后就可以正常利用该参数

二、子传父组件通讯

子组件可以通过调用父组件传递的函数或者触发父组件的变乱来与父组件进行通讯
子组件传值给父组件主要是子组件通过 defineEmits 注册一个自界说变乱,而后触发 emits 去调用该自界说变乱,并传递参数给父组件。
  1. //子组件
  2. <script setup>
  3.     /* defineEmits是Vue3的编译时宏函数,
  4.        用于子组件向父组件发送自定义事件 */
  5.     //1.用宏函数defineEmits定义一个名为 emits 的对象(名字可以随便取), 用于存储自定义事件
  6.     const emits = defineEmits(["getPerson", "addPerson"])
  7.     //2.向上级组件发射名为“getPerson”的自定义事件,并同时发射数据
  8.     emits("getPerson", { name:"李雷", age: 18 })
  9.     const addPerson = () => {
  10.         //3.向父组件发射名为“addPerson”的自定义事件,并同时发射数据
  11.         emits("addPerson", 1)
  12.     }  
  13. </script>
  14. <template>
  15.     <div>
  16.         <h3>我是下级组件</h3>
  17.         <button @click="addPerson">添加人数</button>
  18.     </div>
  19. </template>
  20. <style scoped>
  21.     div {
  22.         width: 25%;
  23.         background-color: gray;
  24.     }
  25. </style>
复制代码
上述子组件中, 通过 defineEmits 注册了一个名为 emits 的对象,包含两个自界说变乱 getPerson 和 addPerson ,通过两种方法向上级组件发射名为“getPerson”和“addPerson”的自界说变乱,并同时发射数据
在父组件中调用子组件时,通过 v-on 绑定一个函数,通过该函数获取传过来的值。
  1. //父组件
  2. <script setup>
  3.     import { ref } from 'vue';
  4.     import Header from './components/Header.vue';
  5.     const person_num = ref(1)
  6.     const emitPrintPerson = (data) => {
  7.         console.log(`下级组件发射过来的数据为:   ${data.name} , ${data.age}`);
  8.     }
  9.     const emitAddPersonNum = (data) => {
  10.         person_num.value += data
  11.     }
  12. </script>
  13. <template>
  14.     <div id="root_component">
  15.         <h3>我是上级组件</h3>
  16.         <h6>计算机学院总人数:{{ person_num }}</h6>
  17.         <!-- 监听两个子组件的事件 -->
  18.         <Header v-on:getPerson="emitPrintPerson" @addPerson="emitAddPersonNum" />  
  19.     </div>
  20. </template>
  21. <style scoped>
  22.     #root_component {
  23.         width: 50%;
  24.         background-color: antiquewhite;
  25.     }
  26. </style>
复制代码
上述父组件中,界说两个函数 emitPrintPerson 和 emitAddPersonNum ,调用子组件时通过 v-on 绑定这两个函数,通过该函数获取传过来的值 。
   (在父组件上利用 v-on 设置相应函数 getPerson 和 addPerson ,该函数与子组件中的注册自界说变乱 getPerson、addPerson名称需同等)
   运行结果:

三、跨组件通讯 (依赖注入 provide 和 inject)

在React中,当需要在不直接存在父子关系的组件之间进行通讯时,可以利用 provide 和 inject 来实现跨组件通讯。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。

比方就是这样一个组件树,APP组件跨过Header组件与Nav组件通讯; 不外provide是向所有下层组件广播平常数据,父组件APP也可以传给子组件Header,用法是与传给孙组件一样的,这里就不逐一赘述了。
   provide 用于某个上层组件将数据广播给所有下层组件。若利用了 provide 和 inject 来进行数据传递,则一般不需要再利用 defineProps
  下面通过几个实验来明白:
【实验1】某个上层组件向所有下层组件广播平常数据,下层组件通过inject注入上层App组件广播的平常数据
在父组件界说一个属性 web ,当父组件传值给所有子组件时,利用provide 将其进行注入 
  1. //父组件
  2. <script setup>
  3.   import { provide, ref } from 'vue'
  4.   import Header from "./components/Header.vue"
  5.   //【实验1】某个上层组件向所有下层组件广播普通数据
  6.   const web =  {name:"百度一下", url:"www.baidu.com"}
  7.   provide("provideWeb", web) //注入名,值
  8. </script>
  9. <template>
  10.   <h3>我是上层的App组件</h3>
  11.   <Header/>
  12. </template>
  13. <style scoped></style>
复制代码
孙组件想要获取 provideWeb 的值,只需利用inject 即可 
  1. //孙组件
  2. <script setup>
  3.     import { inject } from 'vue'
  4.     //【实验1】下层组件通过inject注入上层App组件广播的普通数据
  5.     const web = inject("provideWeb")  //注入名,默认值
  6.     console.log("provideWeb:", web)
  7. </script>
  8. <template>
  9.     <h3>我是底层的Nav组件</h3>
  10. </template>
  11. <style scoped></style>
复制代码
 运行结果:

 【实验2】某个上层组件向所有下层组件广播相应式数据,下层组件通过inject注入上层App组件广播的函数
 在父组件界说一个相应式数据 user ,当父组件传值给所有子组件时,利用provide 将其进行注入 
  1. //父组件
  2. <script setup>
  3.   import { provide, ref } from 'vue'
  4.   import Header from "./components/Header.vue"
  5.   //【实验2】某个上层组件向所有下层组件广播响应式数据
  6.   const user = ref(0)
  7.   provide("provideUser",user)  //注入名,值
  8. </script>
  9. <template>
  10.   <h3>我是上层的App组件, 用户数为: {{ user }}</h3>
  11.   <Header/>
  12. </template>
  13. <style scoped></style>
复制代码
孙组件想要获取 provideUser 的值,只需利用inject 即可 ,利用 .value 来获取其值
  1. //孙组件
  2. <script setup>
  3.     import { inject } from 'vue'
  4.     //【实验2】下层组件通过inject注入上层App组件广播的响应式数据
  5.     const user = inject("provideUser")  //注入名,默认值
  6.     console.log("provideUser:", user.value)
  7. </script>
  8. <template>
  9.     <h3>我是底层的Nav组件</h3>
  10. </template>
  11. <style scoped></style>
复制代码
 运行结果:

【实验3】某个上层组件向所有下层组件广播函数,下层组件通过inject注入上层App组件广播的平常数据
 在父组件界说一个方法 userAdd ,当父组件传值给所有子组件时,利用provide 将其进行注入 
  1. //父组件
  2. <script setup>
  3.   import { provide, ref } from 'vue'
  4.   import Header from "./components/Header.vue"
  5.   //【实验3】某个上层组件向所有下层组件广播函数
  6.   const user = ref(0)
  7.   const userAdd = () => {
  8.     user.value++
  9.   }
  10.   provide("provideFuncUserAdd",userAdd)  //注入名,值
  11. </script>
  12. <template>
  13.   <h3>我是上层的App组件, 用户数为: {{ user }}</h3>
  14.   <Header/>
  15. </template>
  16. <style scoped></style>
复制代码
孙组件想要获取 provideFuncUserAdd 的值,只需利用inject 即可 ,下面组件并在按钮上绑定了 click 变乱以实验由上层App组件注入的函数
  1. //孙组件
  2. <script setup>
  3.     import { inject } from 'vue'
  4.     //【实验3】下层组件通过inject注入上层App组件广播的函数
  5.     const funcUserAdd = inject("provideFuncUserAdd")  //注入名,默认值
  6.     console.log("provideFuncUserAdd:", funcUserAdd)
  7. </script>
  8. <template>
  9.     <h3>我是底层的Nav组件</h3>
  10.     <button @click="funcUserAdd">添加用户</button>
  11. </template>
  12. <style scoped></style>
复制代码
 运行结果:
 


​想要学习更多Java知识:点击Java专栏


​想要学习更多前端知识:点击Web前端专栏



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表