6、组件通信详解(父子、兄弟、祖孙)

2024-06-09 20:52

本文主要是介绍6、组件通信详解(父子、兄弟、祖孙),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、父传子

1、props

  • 用法:

(1)父组件用 props绑定数据,表示为 v-bind:props="数据" (v-bind:简写为 : ,props可以任意命名)

(2)子组件用 defineProps(['props',....])接收

  • 注意:

(1)v-bind:c="数据" 表示父组件给数据绑定了一个名为c的prop属性。这样当父组件的数据发生改变,子组件也能接收到,使双方数据同步;

(2)父传子prop是非函数;

(3)props绑定的数据是只读属性,不能进行修改

父组件Father.vue

<template><div class="father"><h3>父组件</h3><h4>汽车:{{ car }}</h4><Child v-bind:c="car"/></div>
</template><script setup lang="ts" name="Father">
// @ts-nocheckimport Child from './Child.vue'import {ref} from 'vue'// 数据let car = ref('奔驰')
</script>

子组件 Child.vue

<template><div class="child"><h3>子组件</h3><h4>父给的车:{{ c }}</h4></div>
</template><script setup lang="ts" name="Child">
// @ts-nocheckimport {ref} from 'vue'// 声明接收propsdefineProps(['c'])
</script>

2、v-model

 用法:

(1)父组件 使用v-model给数据绑定

(2)子组件 利用了props和自定义事件的组合使用

 父组件

<Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
//父亲的数据
let pageNo = ref(1)
let pageSize = ref(3)

子组件

<template><div class="child2"><h1>同时绑定多个v-model</h1><button @click="handler">pageNo{{ pageNo }}</button><button @click="$emit('update:pageSize', pageSize + 4)">pageSize{{ pageSize }}</button></div>
</template><script setup lang="ts">
let props = defineProps(["pageNo", "pageSize"]);
let $emit = defineEmits(["update:pageNo", "update:pageSize"]);
//第一个按钮的事件回调
const handler = () => {$emit("update:pageNo", props.pageNo + 3);
};
</script>

3、$refs

用法:

ref

 (1)父组件 给所有子组件用ref打标识,定义点击事件以及回调。

(2)子组件 defineExpose暴露自己的数据,父亲可以拿到

$refs

父亲想修改所有儿子的数据。

(1)父组件定义一个修改全部儿子的方法传入参数$refs。$refs可以获取所有儿子实例

(2)子组件都使用defineExpose向外暴露自己的数据

父组件:

<template><div class="father"><h3>父组件</h3><h4>房产:{{ house }}</h4><button @click="changeToy">修改Child1的玩具</button><button @click="changeComputer">修改Child2的电脑</button><button @click="getAllChild($refs)">让所有孩子的书变多</button><Child1 ref="c1"/><Child2 ref="c2"/></div>
</template><script setup lang="ts" name="Father">import Child1 from './Child1.vue'import Child2 from './Child2.vue'import { ref,reactive } from "vue";let c1 = ref()let c2 = ref()// 注意点:当访问obj.c的时候,底层会自动读取value属性,因为c是在obj这个响应式对象中的/* let obj = reactive({a:1,b:2,c:ref(3)})let x = ref(4)console.log(obj.a)console.log(obj.b)console.log(obj.c)console.log(x) */// 数据let house = ref(4)// 方法function changeToy(){c1.value.toy = '小猪佩奇'}function changeComputer(){c2.value.computer = '华为'}function getAllChild(refs:{[key:string]:any}){console.log(refs)for (let key in refs){refs[key].book += 3}}// 向外部提供数据defineExpose({house})
</script>

子组件1:

<template><div class="child1"><h3>子组件1</h3><h4>玩具:{{ toy }}</h4><h4>书籍:{{ book }} 本</h4><button @click="minusHouse($parent)">干掉父亲的一套房产</button></div>
</template><script setup lang="ts" name="Child1">import { ref } from "vue";// 数据let toy = ref('奥特曼')let book = ref(3)// 方法function minusHouse(parent:any){parent.house -= 1}// 把数据交给外部defineExpose({toy,book})</script>

 子组件2:

<template><div class="child2"><h3>子组件2</h3><h4>电脑:{{ computer }}</h4><h4>书籍:{{ book }} 本</h4></div>
</template><script setup lang="ts" name="Child2">import { ref } from "vue";// 数据let computer = ref('联想')let book = ref(6)// 把数据交给外部defineExpose({computer,book})
</script>

4、默认插槽

用法:

(1)父组件  使用category子组件的起始终止标签,里面夹带要展示的内容

(2)子组件 使用slot默认插槽,父组件的每一个category标签中间的内容都会插入到slot里面

这样就能把父亲里面的数据显示到子组件里面。

父组件

<template><div class="father"><h3>父组件</h3><div class="content"><Category title="热门游戏列表"><ul><li v-for="g in games" :key="g.id">{{ g.name }}</li></ul></Category><Category title="今日美食城市"><img :src="imgUrl" alt=""></Category><Category title="今日影视推荐"><video :src="videoUrl" controls></video></Category></div></div>
</template><script setup lang="ts" name="Father">import Category from './Category.vue'import { ref,reactive } from "vue";let games = reactive([{id:'asgytdfats01',name:'英雄联盟'},{id:'asgytdfats02',name:'王者农药'},{id:'asgytdfats03',name:'红色警戒'},{id:'asgytdfats04',name:'斗罗大陆'}])let imgUrl = ref('https://z1.ax1x.com/2023/11/19/piNxLo4.jpg')let videoUrl = ref('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4')</script>

子组件

<template><div class="category"><h2>{{title}}</h2><slot>默认内容</slot></div>
</template><script setup lang="ts" name="Category">defineProps(['title'])
</script>

5、具名插槽 

用法:

(1)父组件 用template v-slot:s1或者#s2来命名

(2)子组件 用slot name=xxx来决定存放位置

这样父组件里面的数据就能决定放在子组件的哪个位置了,不受顺序影响

父组件中:<Category title="今日热门游戏"><template v-slot:s1><ul><li v-for="g in games" :key="g.id">{{ g.name }}</li></ul></template><template #s2><a href="">更多</a></template></Category>
子组件中:<template><div class="item"><h3>{{ title }}</h3><slot name="s1"></slot><slot name="s2"></slot></div></template>

 

二、子传父

1、props

  • 用法:

(1)先在父组件内部定义一个关于获取数据的方法getToy,为这个方法getToy绑定prop属性为函数sendToy。表示为  :sendToy="getToy"

(2)子组件definprops(['prop',....])接收,并绑定点击事件@click="sendToy(toy)"把要传的数据发送过去。

  • 注意:

(1)子传父prop是函数

(2)props绑定的数据是只读属性,不能进行修改

父组件Father.vue

<template><div class="father"><h3>父组件</h3><h4 v-show="toy">子给的玩具:{{ toy }}</h4><Child :sendToy="getToy"/></div>
</template><script setup lang="ts" name="Father">
// @ts-nocheckimport Child from './Child.vue'import {ref} from 'vue'// 数据let toy = ref('')// 方法function getToy(value:string){toy.value = value}
</script>

子组件Child.vue 

<template><div class="child"><h3>子组件</h3><button @click="sendToy(toy)">把玩具给父亲</button></div>
</template><script setup lang="ts" name="Child">
// @ts-nocheckimport {ref} from 'vue'// 数据let toy = ref('奥特曼')// 声明接收propsdefineProps(['sendToy'])
</script>

2、emit自定义事件通信

用法:

(1) 先在父组件内部的子组件绑定自定义事件@xxx,即为 @send-toy="saveToy",再定义自定义事件的回调saveToy

(2)子组件声明事件,用definEmits(['send-toy'])

(3)子组件绑定事件传递参数,@click="emit('send-toy',toy)"

Father.vue

<template><div class="father"><h3>父组件</h3><h4 v-show="toy">子给的玩具:{{ toy }}</h4><!-- 给子组件Child绑定事件 --><Child @send-toy="saveToy"/></div>
</template><script setup lang="ts" name="Father">
// @ts-nocheckimport Child from './Child.vue'import { ref } from "vue";// 数据let toy = ref('')// 用于保存传递过来的玩具function saveToy(value:string){console.log('saveToy',value)toy.value = value}
</script>

Child.vue 

<template><div class="child"><h3>子组件</h3><h4>玩具:{{ toy }}</h4><button @click="emit('send-toy',toy)">测试</button></div>
</template><script setup lang="ts" name="Child">
// @ts-nocheckimport { ref } from "vue";// 数据let toy = ref('奥特曼')// 声明事件const emit =  defineEmits(['send-toy'])
</script>

3、v-model 

4、$parent

用法:

(1)父组件,用definExpose向外暴露自己的数据

(2)子组件,通过$parent获取父组件实例,定义点击事件传入$parent 修改父组件的数据

父组件:

<template><div class="father"><h3>父组件</h3><h4>房产:{{ house }}</h4><button @click="changeToy">修改Child1的玩具</button><button @click="changeComputer">修改Child2的电脑</button><button @click="getAllChild($refs)">让所有孩子的书变多</button><Child1 ref="c1"/><Child2 ref="c2"/></div>
</template><script setup lang="ts" name="Father">import Child1 from './Child1.vue'import Child2 from './Child2.vue'import { ref,reactive } from "vue";let c1 = ref()let c2 = ref()// 注意点:当访问obj.c的时候,底层会自动读取value属性,因为c是在obj这个响应式对象中的/* let obj = reactive({a:1,b:2,c:ref(3)})let x = ref(4)console.log(obj.a)console.log(obj.b)console.log(obj.c)console.log(x) */// 数据let house = ref(4)// 方法function changeToy(){c1.value.toy = '小猪佩奇'}function changeComputer(){c2.value.computer = '华为'}function getAllChild(refs:{[key:string]:any}){console.log(refs)for (let key in refs){refs[key].book += 3}}// 向外部提供数据defineExpose({house})
</script>

子组件1:

<template><div class="child1"><h3>子组件1</h3><h4>玩具:{{ toy }}</h4><h4>书籍:{{ book }} 本</h4><button @click="minusHouse($parent)">干掉父亲的一套房产</button></div>
</template><script setup lang="ts" name="Child1">import { ref } from "vue";// 数据let toy = ref('奥特曼')let book = ref(3)// 方法function minusHouse(parent:any){parent.house -= 1}// 把数据交给外部defineExpose({toy,book})</script>

5、作用域插槽 

比如你要在父组件显示子组件的不同形式(有序,无序,标题),但是当你在父组件遍历子组件的数据时候,你是拿不到的。这时候就用到了作用域插槽。数据在子组件,数据的展示解构由父组件决定。

用法:

(1)父组件  使用template v-slot="params" params就是子组件传递过来的所有对象

(2)子组件 用props绑定数据,传给了内置组件slot,slot又把数据传给了他的使用者,父组件。

 父组件

<template><div class="father"><h3>父组件</h3><div class="content"><Game><template v-slot="params"><ul><li v-for="y in params.youxi" :key="y.id">{{ y.name }}</li></ul></template></Game><Game><template v-slot="params"><ol><li v-for="item in params.youxi" :key="item.id">{{ item.name }}</li></ol></template></Game><Game><template #default="{youxi}"><h3 v-for="g in youxi" :key="g.id">{{ g.name }}</h3></template></Game></div></div>
</template><script setup lang="ts" name="Father">import Game from './Game.vue'
</script>

子组件

<template><div class="game"><h2>游戏列表</h2><slot :youxi="games" x="哈哈" y="你好"></slot></div>
</template><script setup lang="ts" name="Game">import {reactive} from 'vue'let games = reactive([{id:'asgytdfats01',name:'英雄联盟'},{id:'asgytdfats02',name:'王者农药'},{id:'asgytdfats03',name:'红色警戒'},{id:'asgytdfats04',name:'斗罗大陆'}])
</script>

三、祖传孙

1、$attrs

用法:

(1)父组件 使用v-bind给数据绑定props

(2)子组件 不接收,使用v-bind="$attrs"存给孙组件

(3)孙组件 使用defineprops接收

父组件:

<template><div class="father"><h3>父组件</h3><h4>a:{{a}}</h4><h4>b:{{b}}</h4><h4>c:{{c}}</h4><h4>d:{{d}}</h4><Child :a="a" :b="b" :c="c" :d="d" /></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref} from 'vue'let a = ref(1)let b = ref(2)let c = ref(3)let d = ref(4)</script>

子组件:

<template><div class="child"><h3>子组件</h3><GrandChild v-bind="$attrs"/></div>
</template><script setup lang="ts" name="Child">import GrandChild from './GrandChild.vue'
</script>

孙组件: 

<template><div class="grand-child"><h3>孙组件</h3><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>c:{{ c }}</h4><h4>d:{{ d }}</h4></div>
</template><script setup lang="ts" name="GrandChild">defineProps(['a','b','c','d'])
</script>

2、provide inject

用法:

 (1)父组件,先从vue中import引入provide ,而后使用provide向后代提供数据

provide('名字',值)  

(2)后代组件,先import引入inject,而后使用inject接收数据,inject('名字','默认值')

 父组件:

<template><div class="father"><h3>父组件</h3><h4>银子:{{ money }}万元</h4><h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4><Child/></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref,reactive,provide} from 'vue'let money = ref(100)let car = reactive({brand:'奔驰',price:100})function updateMoney(value:number){money.value -= value}// 向后代提供数据provide('moneyContext',{money,updateMoney})provide('car',car)

孙组件:

<template><div class="grand-child"><h3>我是孙组件</h3><h4>银子:{{ money }}</h4><h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4><button @click="updateMoney(6)">花爷爷的钱</button></div>
</template><script setup lang="ts" name="GrandChild">import { inject } from "vue";let {money,updateMoney} = inject('moneyContext',{money:0,updateMoney:(param:number)=>{}})let car = inject('car',{brand:'未知',price:0})
</script>

四、孙传祖

1、$attrs

(1)父组件 绑定方法

(2)子组件 不接收使用$attrs传给孙组件

(3)孙组件 使用defineprops接收,并绑定点击事件

 父组件:

<template><div class="father"><h3>父组件</h3><h4>a:{{a}}</h4><h4>b:{{b}}</h4><h4>c:{{c}}</h4><h4>d:{{d}}</h4><Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"/></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref} from 'vue'let a = ref(1)let b = ref(2)let c = ref(3)let d = ref(4)function updateA(value:number){a.value += value}
</script>

子组件:

<template><div class="child"><h3>子组件</h3><GrandChild v-bind="$attrs"/></div>
</template><script setup lang="ts" name="Child">import GrandChild from './GrandChild.vue'
</script>

 孙组件:

<template><div class="grand-child"><h3>孙组件</h3><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>c:{{ c }}</h4><h4>d:{{ d }}</h4><h4>x:{{ x }}</h4><h4>y:{{ y }}</h4><button @click="updateA(6)">点我将爷爷那的a更新</button></div>
</template><script setup lang="ts" name="GrandChild">defineProps(['a','b','c','d','x','y','updateA'])
</script>

2、provide inject

用法:

(1) 父组件,里面定义一个方法,在provide里面传的是money的值和这个方法给孙组件

(2)孙组件,可以把传过来的值和方法 利用解构赋值和inject接收,然后再添加一个按钮绑定这个方法,并传数据。就实现了孙传祖。

父组件:

<template><div class="father"><h3>父组件</h3><h4>银子:{{ money }}万元</h4><h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4><Child/></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref,reactive,provide} from 'vue'let money = ref(100)let car = reactive({brand:'奔驰',price:100})function updateMoney(value:number){money.value -= value}// 向后代提供数据provide('moneyContext',{money,updateMoney})provide('car',car)

孙组件:

<template><div class="grand-child"><h3>我是孙组件</h3><h4>银子:{{ money }}</h4><h4>车子:一辆{{car.brand}}车,价值{{car.price}}万元</h4><button @click="updateMoney(6)">花爷爷的钱</button></div>
</template><script setup lang="ts" name="GrandChild">import { inject } from "vue";let {money,updateMoney} = inject('moneyContext',{money:0,updateMoney:(param:number)=>{}})let car = inject('car',{brand:'未知',price:0})
</script>

五、兄弟、任意组件

1、mitt任意组件通信

用法:

(1)提供数据的用emitter.emit触发事件。

@click="emitter.emit('send-toy',toy)">

(2)接收数据的用emitter.on绑定事件。

emitter.on('send-toy',(value:any)=>{

        toy.value = value

    })

Child1.vue

<template><div class="child1"><h3>子组件1</h3><h4>玩具:{{ toy }}</h4><button @click="emitter.emit('send-toy',toy)">玩具给弟弟</button></div>
</template><script setup lang="ts" name="Child1">
// @ts-nocheckimport {ref} from 'vue'import emitter from '@/utils/emitter';// 数据let toy = ref('奥特曼')
</script>

Child2.vue 

<template><div class="child2"><h3>子组件2</h3><h4>电脑:{{ computer }}</h4><h4>哥哥给的玩具:{{ toy }}</h4></div>
</template><script setup lang="ts" name="Child2">
// @ts-nocheckimport {ref,onUnmounted} from 'vue'import emitter from '@/utils/emitter';// 数据let computer = ref('联想')let toy = ref('')// 给emitter绑定send-toy事件emitter.on('send-toy',(value:any)=>{toy.value = value})// 在组件卸载时解绑send-toy事件onUnmounted(()=>{emitter.off('send-toy')})
</script>

2、pinia 

vue3组件常用的通信方式 Pinia_pinia实现组件的通信-CSDN博客

// 在 store.js 中定义 Pinia store
import { defineStore } from 'pinia';export const useCounterStore = defineStore({id: 'counter',state: () => ({count: 0,}),actions: {increment() {this.count++;},decrement() {this.count--;},},
});// 在组件中使用 store
<template><div><p>Count: {{ count }}</p><button @click="increment">Increment</button><button @click="decrement">Decrement</button></div>
</template><script>
import { useCounterStore } from './store';export default {setup() {const counterStore = useCounterStore();return {count: counterStore.count,increment: counterStore.increment,decrement: counterStore.decrement,};},
};
</script>

六、总结

这篇关于6、组件通信详解(父子、兄弟、祖孙)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1046274

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

LabVIEW FIFO详解

在LabVIEW的FPGA开发中,FIFO(先入先出队列)是常用的数据传输机制。通过配置FIFO的属性,工程师可以在FPGA和主机之间,或不同FPGA VIs之间进行高效的数据传输。根据具体需求,FIFO有多种类型与实现方式,包括目标范围内FIFO(Target-Scoped)、DMA FIFO以及点对点流(Peer-to-Peer)。 FIFO类型 **目标范围FIFO(Target-Sc