当前位置: 首页> 健康> 知识 > Vue3组件通信详解

Vue3组件通信详解

时间:2025/8/23 9:17:16来源:https://blog.csdn.net/m0_55049655/article/details/141872778 浏览次数:0次

Vue 3 中的组件通讯是 Vue 应用开发中非常重要的一环,它允许组件之间传递数据和方法,从而实现数据的共享和功能的调用。下面将分别介绍父子组件、孙子组件(祖孙组件)、兄弟组件之间的通讯方式,并给出示例代码和总结表格。

一、父子组件通讯

1. 父传子(props)

父组件通过 props 向子组件传递数据。

父组件示例代码

<template>  <ChildComponent :message="parentMessage" />  
</template>  <script setup>  
import ChildComponent from './ChildComponent.vue';  
import { ref } from 'vue';  const parentMessage = ref('Hello from Parent');  
</script>

子组件示例代码

<template>  <div>{{ message }}</div>  
</template>  <script setup>  
import { defineProps } from 'vue';  const props = defineProps({  message: String  
});  
</script>

2. 子传父($emit)

子组件通过 $emit 触发事件,向父组件传递数据或信号。

子组件示例代码

<template>  <button @click="sendMessage">Send Message to Parent</button>  
</template>  <script setup>  
//this.$emit->”定义emit“,传数据
const emit = defineEmits(['update:message']);  function sendMessage() {  emit('update:message', 'Hello from Child');  
}  
</script>

父组件示例代码(监听子组件触发的事件):

<template>  <ChildComponent @update:message="handleMessage" />  
</template>  <script setup>  
import ChildComponent from './ChildComponent.vue';  function handleMessage(message) {  console.log(message); // 输出: Hello from Child  
}  
</script>

二、祖孙组件通讯(provide/inject)

祖先组件通过 provide 选项提供数据或方法,后代组件通过 inject 选项接收数据或方法。

祖先组件示例代码

<template>  <ChildComponent />  
</template>  <script setup>  
import { provide, ref } from 'vue';  const grandParentData = ref('Data from GrandParent');  provide('grandParentData', grandParentData);  
</script>

三、兄弟组件通讯

兄弟组件之间的通讯通常不直接进行,而是通过共同的父组件或全局状态管理(如 Vuex、Pinia)来实现。

示例:通过事件总线(不推荐,Vue 3 中可用第三方库如 mitt 替代)

事件总线(mitt.js)

// eventBus.js  
import mitt from 'mitt';  
const emitter = mitt();  
export default emitter;

组件A(发送方)

<template>  <button @click="sendMessage">Send Message to Brother</button>  
</template>  <script setup>  
import emitter from './eventBus.js';  function sendMessage() {  emitter.emit('message', 'Hello from Component A');  
}  
</script>

组件B(接收方)

<template>  <p>{{ message }}</p>  
</template>  <script setup>  
import { ref } from 'vue';  
import emitter from './eventBus.js';  const message = ref('');  //emitter.on接收,‘message’通信主体标识
emitter.on('message', (newMessage) => {  message.value = newMessage;  
});  
</script>

四、总结

通讯类型通讯方式发送方接收方示例说明
父子组件props父组件子组件父组件通过 props 传递数据给子组件
父子组件$emit子组件父组件子组件通过 $emit 触发事件,父组件监听并处理
祖孙组件provide/inject祖先组件后代组件祖先组件通过 provide 提供数据,后代组件通过 inject 接收
兄弟组件通过父组件兄弟组件A兄弟组件B兄弟组件A通过事件通知父组件,父组件再传递给兄弟组件B
兄弟组件全局状态管理(Vuex/Pinia)兄弟组件A兄弟组件B使用 Vuex 或 Pinia 管理全局状态,兄弟组件共享状态
兄弟组件第三方库(如 mitt)兄弟组件A兄弟组件B通过第三方库实现事件总线,兄弟组件间通过事件总线通讯

 五、事件总线底层原理

设计模式—观察者模式与发布订阅-CSDN博客

Javascript常见设计模式-CSDN博客

发布——订阅者模式

发布-订阅模式是一种消息传递模式,允许发送者(发布者)发送消息而不直接关心谁将接收这些消息,同时接收者(订阅者)可以监听并接收这些消息,而不需要了解消息是从哪里发送的。mitt 作为一个轻量级的事件总线库,正是基于这种模式设计的。

在 mitt 中,你可以:

  • 使用 .on(eventName, handler) 方法来订阅一个事件,其中 eventName 是事件的名称(一个字符串),而 handler 是当事件发生时被调用的处理函数。
  • 使用 .emit(eventName, ...args) 方法来发布一个事件,其中 eventName 是事件的名称,而 ...args 是传递给事件处理函数的参数列表。
  • (可选地)使用 .off(eventName, handler) 方法来取消订阅之前订阅的事件。如果不提供 handler,则取消该事件的所有订阅者。

这些操作完全符合发布-订阅模式的典型特征:

  • 发布者(在 mitt 的上下文中是调用 .emit() 方法的代码)发布一个事件,不需要知道有哪些订阅者会接收这个事件。
  • 订阅者(在 mitt 的上下文中是通过 .on() 方法注册的处理函数)监听并响应特定的事件,不需要知道事件是由谁发布的。
  • 事件总线(在 mitt 的上下文中是 mitt 实例本身)负责事件的分发,确保事件能够到达所有相关的订阅者。

因此,可以说 mitt 确实是通过发布-订阅模式来实现其功能的。

// 创建一个简单的发布订阅者管理类  
class EventEmitter {  constructor() {  this.events = {}; // 用于存储事件的字典,键为事件名,值为订阅者数组  }  // 订阅事件  on(eventName, callback) {  if (!this.events[eventName]) {  this.events[eventName] = []; // 如果该事件尚未被订阅,则初始化一个空数组  }  this.events[eventName].push(callback); // 将回调函数添加到订阅者数组中  return this; // 支持链式调用  }  // 取消订阅事件  off(eventName, callback) {  if (this.events[eventName]) {  // 移除指定的回调函数  this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);  // 如果订阅者数组为空,则删除该事件  if (this.events[eventName].length === 0) {  delete this.events[eventName];  }  }  return this; // 支持链式调用  }  // 发布事件  emit(eventName, ...args) {  if (this.events[eventName]) {  // 遍历订阅者数组,并执行每个回调函数  this.events[eventName].forEach(callback => {  callback.apply(this, args);  });  }  return this; // 支持链式调用  }  // 可选:监听一次后自动取消订阅  once(eventName, callback) {  const onceCallback = (...args) => {  callback.apply(this, args);  this.off(eventName, onceCallback);  };  this.on(eventName, onceCallback);  return this; // 支持链式调用  }  
}  // 使用示例  
const eventBus = new EventEmitter();  // 订阅者1  
function subscriber1(price) {  console.log('订阅者1收到消息:当前价格已降至' + price + '元');  
}  // 订阅者2  
function subscriber2(price) {  console.log('订阅者2也收到消息:价格更新为' + price + '元');  
}  // 订阅事件  
eventBus.on('priceUpdate', subscriber1);  
eventBus.on('priceUpdate', subscriber2);  // 使用once方法监听一次  
eventBus.once('specialOffer', (offer) => {  console.log('只接收一次的特别优惠:' + offer);  
});  // 发布事件  
eventBus.emit('priceUpdate', 99); // 订阅者1和订阅者2都会收到消息  
eventBus.emit('specialOffer', '买一赠一'); // 只有一个订阅者会收到这个特别优惠的消息  // 取消订阅  
eventBus.off('priceUpdate', subscriber1);  
eventBus.emit('priceUpdate', 88); // 只有订阅者2会收到消息

关键字:Vue3组件通信详解

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: