聊一聊如何在Vue中使用事件总线( Event Bus)进行组件间通信

d0cbb511dca99165271893f026d16d9a.jpeg

事件总线模式允许不同的组件之间进行通信。它要求一个中央枢纽,组件可以通过它发送和接收事件,从而使组件之间的数据交换和交互更加顺畅。本文探讨了它的使用方法,以便开发人员能够充分利用它在Vue开发中的潜力。

跨通信是应用程序中组件之间的交互。这有助于应用程序的不同部分之间的顺畅协作。其重要性体现在以下几个方面:

  • 数据共享:跨组件通信确保组件之间的数据高效交换。

  • 处理事件:它帮助它们更新状态并触发必要的事件。它确保组件对事件做出相应的反应。

  • 简化开发和可重用性:当组件互相交互时,它们可以独立工作。因此,管理代码并在整个应用程序中重用组件变得更加容易。

  • 提升用户体验:有效的沟通有助于流畅而互动的用户体验。

  • 可扩展性:跨组件通信帮助开发人员管理他们的应用程序。它将应用程序拆分为更小、可管理的部分。随着时间的推移,这种可扩展性对于应用程序的演进和扩展至关重要。

Vue中事件总线的概述

Vue中的事件总线是一种类似于信使的机制,用于帮助组件之间进行通信。就像朋友之间互发消息一样,即使彼此不认识也能进行交流。通过全局事件总线,组件可以在没有紧密连接的情况下进行交互,这使得它具有灵活性和高效性。你可以设置事件总线,然后在需要的时候组件可以发出事件。其他组件可以监听这些事件并做出相应的反应。它有助于保持代码的组织性,并促进Vue应用中组件之间的协作。

事件总线具有一些方法,用于促进组件间的交互通信。它们包括:$on(eventName, callback) 监听事件, $emit(eventName, data) 触发带有可选数据负载的事件,以及 $off(eventName, callback) 移除事件监听器。在Vue中, $once 方法是另一个事件总线方法,允许组件仅监听一次事件。它的功能类似于 $on 方法,但不同之处在于在事件触发一次后自动移除事件监听器。

搭建一个Vue项目

我们将从创建一个Vue应用程序开始,然后继续设置事件总线以进行跨组件通信。

接下来,在目录中运行以下命令来创建一个新的Vue项目。

npm create vue@latest

按照向导的指示,根据项目需求选择适合你的设置的正确工具。

bb175f8712a6bf82bc9d2b276643d170.jpeg

一旦设置完成,通过运行以下命令进入项目目录:

cd eventBus-app

npm install

npm run dev

现在,您可以运行开发服务器来查看您的Vue应用程序的运行情况,打开你的浏览器,访问提供的本地开发URL:http://127.0.0.1:5173/

设置事件总线

在Vue中,设置事件总线是一个简单的过程,允许组件之间进行通信而无需直接依赖。

要创建事件总线实例,我们首先定义一个专门处理事件的新Vue实例。这可以在一个单独的JavaScript文件或主Vue应用程序文件中完成。

首先,由于我们正在使用Vue 3,我们必须更新事件总线设置,以使用mitt库进行事件处理:

打开终端并使用以下命令安装mitt库:

npm install mitt

或者

yarn add mitt

接下来,在src文件夹中创建一个名为 eventBus.js 的单独的js文件。

// eventBus.js file for Vue3import mitt from 'mitt';// Create a new event bus using mitt
const Event Bus = mitt();export default eventBus;

通过导入Vue并创建一个新实例,我们现在拥有了一个事件总线,可以方便组件之间的通信。

注意:如果您使用的是Vue 2,不需要使用mitt库;您可以按照下面的配置继续进行:eventBus.js

// eventBus.js file for Vue2import Vue from 'vue';// Create a new Vue instance to act as the Event Bus
const eventBus = new Vue();export default eventBus;

发出和监听事件

一旦事件总线实例设置完成,组件就可以开始发出事件并监听它们。组件使用Vue中可用的 $emit 方法来发出事件。该方法的第一个参数是事件名称,第二个参数是可选的负载,如果需要传递数据与事件一起使用。

// ComponentA.vue<template><div><button @click="handleClick">Say Hello</button></div>
</template><script setup>
import eventBus from "../eventBus";const handleClick = () => {// Emitting an event with the name 'sayHello'eventBus.emit("sayHello", "Hello from Component A!");
};
</script>

在接收端,其他组件可以监听发出的事件,并在事件发生时执行相应的操作。这是通过使用 $on 方法实现的,该方法监听特定的事件名称。

// ComponentB.vue<template><div><p>{{ message }}</p></div>
</template><script setup>
import { onMounted, ref } from "vue";
import eventBus from "../eventBus";const message = ref("")onMounted(() => {// Listening for the 'sayHello' event from the 'eventBus'eventBus.on("sayHello", (data) => {// Handling the event and accessing the payload datamessage.value = data});
});
</script>

使用事件总线传递数据

使用事件总线传递数据涉及到事件负载的使用和复杂数据结构的共享。让我们通过代码示例来说明这些概念:

使用事件负载(Event Payloads)

事件负载允许组件在发出事件时传递附加数据。当从一个组件向另一个组件发送特定信息时,这非常有用。上面的示例中已经说明了这个工作原理。发射器 ComponentA 发出一个带有负载为“Hello from Component A!”的 sayHello 事件。监听器 ComponentB 监听该事件,并使用事件发送的负载更新其 message 值。这基本上就是事件负载的工作原理。

共享复杂数据结构

事件总线还可以在组件之间共享更复杂的数据结构,例如对象或数组。这使得组件可以交换结构化数据,而无需紧密耦合。以下是共享复杂数据结构的示例:

让我们更新我们的初始组件A(发射器),使用更复杂的有效载荷数据。

// ComponentA<template><div><button @click="fetchUserDetail">Fetch User</button></div>
</template><script setup>
import { reactive, ref } from "vue";
import eventBus from "../eventBus";const userDetails = reactive({name: "Hannah",dob: "23-Nov",favColor: "Gray",
});const fetchUserDetail = () => {eventBus.emit("getUserDetails", userDetails);
};
</script>

接收组件(监听器)实现了一个事件处理程序并访问共享数据是:

// ComponentB<template><div><p>{{ user.name }}</p><p>{{ user.dob }}</p><p>{{ user.favColor }}</p></div>
</template><script setup>
import { onMounted, reactive, ref } from "vue";
import eventBus from "../eventBus";const user = ref({})onMounted(() => {eventBus.on("getUserDetails", (userData) => {user.value = userData});
});
</script>

最佳实践和技巧

保持事件名称一致性:保持事件名称一致性至关重要,以确保清晰明了,避免混淆。通过使用有意义且描述性的事件名称,您可以轻松识别每个事件的目的及其相应的功能。例如,上述使用了 sayHello 和 getUserDetails ,它们具有自我描述性,人们可以轻松说明它们的功能。

处理异步事件:在处理事件总线中的异步操作时,适当地处理它们非常重要。例如,如果一个事件涉及数据获取或API调用,请使用async/await或Promises来有效地管理异步代码流程。

// emitteronMounted(async () => {const data = await fetchData(); // Some asynchronous data fetching functioneventBus.emit("data-fetched", data);
});
// listener  onMounted(() => {eventBus.on("data-fetched", async (data) => {// Handle the asynchronously received data hereawait processData(data); // Some asynchronous data processing function});
});

避免事件冲突:当两个或多个组件使用相同的事件名称时,可能会发生事件冲突。这可能导致意外的行为或冲突。为了避免这种情况,可以根据组件名称或特定目的对事件进行命名空间划分。

// In Component A<script setup>
import eventBus from "../eventBus";const handleClick = () => {// Emitting an event with the name 'sayHello'eventBus.emit("componentA-sayHello", "Hello from Component A!");
};
</script>
// In Component BonMounted(() => {eventBus.on('componentA-sayHello', (data) => {message.value = data;});}

通过在事件名称前加上特定组件的标识符,可以最大程度地减少事件冲突的风险。

事件总线与Props相比

事件总线和Props是Vue中常用的两种组件间通信的方法。让我们来探索它们的区别。

事件总线

事件总线允许不直接相关的组件之间进行通信,无需通过父组件传递数据。它作为一个中央事件中心,用于发射和监听自定义事件。

示例

在A组件中:

<template><button @click="send">Emit Event</button>
</template><script setup>
import eventBus from "../eventBus";
import {ref } from "vue";const send = () => {eventBus.emit('sendFile', { message: 'File Sent' });
},
</script>

在B组件中:

<template><div><p>{{ message }}</p></div>
</template><script setup>
import eventBus from "../eventBus";
import { onMounted, ref } from "vue";const message = ref("")onMounted(()=> {eventBus.on('custom-event', (data) => {message.value = data.message;})
}),
</script>

Props(属性)

Props涉及通过属性将数据从父组件传递给子组件。

示例:

在ParentComponent中:

// Parent Component<template><child-component :message="message" />
</template><script setup>
import ChildComponent from './ChildComponent';
import { ref } from "vue";const message = ref("Happy Holidays")
</script>

在ChildComponent中:

<template><div><p>{{ message }}</p></div>
</template><script setup>
defineProps({message: {type: String,required: true}
})
</script>

比较事件总线与Vuex

事件总线和Vuex在范围和用例上有所不同。事件总线适用于局部通信,而Vuex是一个用于在多个组件之间共享全局数据的状态管理解决方案。

事件总线(本地通信):

上面已经演示了事件总线的示例。当只有少数组件需要通信且数据交换不复杂时,它是合适的。

Vuex(全局状态管理):

Vuex 允许集中式状态管理,这意味着数据可以在整个应用程序中被多个组件共享和访问。

示例

在 store.js (Vuex设置)中:

import { createStore } from 'vuex';export default createStore({state() {return {message: 'Hello from Vuex store',};},mutations: {setMsg: (state, msg) => state.message = msg},actions: {},getters: {getMsg: (state) => state.message,},
});

在A组件中:

<template><div><p>{{ message }}</p></div>
</template><script setup>
import { computed, onMounted, reactive, ref } from "vue";
import { useStore } from 'vuex';const store = useStore();const message = computed(() => {return store.getters['getMsg'];
});
</script><style></style>

在B组件中:

<template><div><button @click="updateMsg">Update Message</button></div>
</template><script setup>
import { useStore } from "vuex";const store = useStore();const updateMsg = () => {store.commit("setMsg", "Hello World");
};
</script>

事件总线和Vuex都有各自的优势,应根据应用程序的具体通信需求来选择。事件总线适用于简单和局部化的通信,而Vuex则推荐用于管理跨多个组件的复杂全局状态。

结束

Vue中的事件总线促进了高效的跨组件通信,增强了模块化和可重用性。它的好处包括简化的数据共享、灵活性和可维护性。通过遵循最佳实践,开发人员可以确保有组织的事件系统和顺畅的通信。事件总线赋予了Vue应用程序强大的能力,简化了开发过程,丰富了用户体验。

由于文章内容篇幅有限,今天的内容就分享到这里,文章结尾,我想提醒您,文章的创作不易,如果您喜欢我的分享,请别忘了点赞和转发,让更多有需要的人看到。同时,如果您想获取更多前端技术的知识,欢迎关注我,您的支持将是我分享最大的动力。我会持续输出更多内容,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114226.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32F4X定时器之基本定时器

一、定时器的概述 进行有规律的计数&#xff0c;每记一次数的时间都是固定的 定时器的本质&#xff1a;计数的总时间 记一次数的时间&#xff08;时钟的频率&#xff09; * 记多少次&#xff08;重装载值&#xff09;。 基本定时器属于片上外设&#xff0c;系统滴答定时器是…

GitHub下载太慢的解决方案

修改hosts文件&#xff1a; windows的hosts文件在 C:\Windows\System32\drivers\etc\hosts cmd管理员运行命令notepad C:\Windows\System32\drivers\etc\hosts 然后cmd命令重启网络ipconfig /flushdns windows修改hosts Ubuntu22.04修改hosts sudo vim /etc/hosts # This fil…

Java面试题-Java核心基础-第九天(泛型)

目录 一、泛型的理解 二、泛型的作用 三、泛型有哪些使用方式 四、上限、下限通配符的使用 五、泛型的原理 一、泛型的理解 泛型在jdk5中开始有的&#xff0c;泛型其实就是将类型进行参数话&#xff0c;使得类型在编译时就确定了&#xff0c;这种类型参数可以用在类、接口…

解决Docker安装MySQL不区分大小写问题

Docker安装MySQL忽略大小写问题的问题 连接MySQL&#xff1a; 查看当前mysql的大小写敏感配置 show global variables like %lower_case%; ------------------------------- | Variable_name | Value | ------------------------------- | lower_case_file_system …

openEuler 服务器安装 JumpServer (all-in-one 模式)

openEuler 服务器安装 JumpServer JumpServer 简介什么是 JumpServer &#xff1f;JumpServer 的各种类型资产JumpServer 产品特色或优势JumpServer 符合 4A 规范 JumpServer 系统架构应用架构组件说明 JumpServer 安装部署环境要求网络端口网络端口列表防火墙常用命令 在线脚本…

LeetCode 414. Third Maximum Number【数组】简单

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

vlookup函数踩坑(wps)

使用wps的朋友看过来 vlookup函数踩坑&#xff0c;vlookup&#xff08;查找值&#xff0c;查找范围&#xff0c;返回值的索引&#xff0c;精确查找or模糊查找&#xff09; 我们要查找的数据的那一列&#xff0c;必须是查找范围的第一列&#xff01; 案例&#xff0c;看下面的…

02、Python 字符串

目录 字符串的基础用法字符串包含引号字符串拼接获取用户输入长字符串原始字符串字节串字符串与字节串转换 字符串的基础用法 列字符串的内容几乎可以包含任何字符&#xff0c;英文字符也行&#xff0c;中文字符也行。 既可用单引号&#xff0c;也可用双引号 字符串包含引号…

shell的for循环与结构化

shell笔记 列表for循环不带列表for循环for循环举例1.例1 所有文件名大写替换为小写2. 例2 读取/etc/passwd文件&#xff0c;依次输出ip段3. 例3 读取/etc/hosts内容for循环&#xff0c;执行ping4. 例4 循环ip列表&#xff0c;输出对应编号5. 例5 批量添加用户 break1. 例1 brea…

C++ vector 的模拟实现

目录 1. vector 类的成员变量 2. 无参构造 3. 析构函数 4. size_t capacity() 5. size_t size() 6. void reserve(size_t n) 7. 迭代器 8. void push_back(const T& x) 9. T& operator[](size_t pos) 10. iterator insert(iterator pos, const T& val…

使用Redis发布订阅模式实现 Session共享

其实并不是实现session共享&#xff0c;而是通过redis的发布订阅&#xff0c;让所有集群的服务器&#xff0c;都让自己的session发送一下消息。比如说userId在第35台服务器上&#xff0c; 有100台服务器&#xff0c;那么第1台服务器收到消息&#xff0c;需要通知userId&#xf…

vue 组件封装 综合案例2

vue 组件封装 综合案例2 main.js import Vue from vue import App from ./App.vueVue.config.productionTip false//封装全局指令 focus Vue.directive(focus, {// 指令所在的dom元素&#xff0c;被插入到页面中时触发inserted(el) {el.focus();} })new Vue({render: h >…

MySQL 三大日志(bin log、redo log、undo log)

redo log redo log (重做日志) 是 InnoDB 存储引擎独有的&#xff0c;它让 MySQL有了崩溃恢复的能力&#xff0c;是事务中实现 持久化的重要操作 比如 MySQL 实例宕机了&#xff0c;重启时&#xff0c;InnoDB 存储引擎会使用 redo log 恢复数据&#xff0c;保证数据的持久性与…

设计模式——七大原则详解

目录 设计模式单一职责原则应用实例注意事项和细节 接口隔离原则应用实例 依赖倒转&#xff08;倒置&#xff09;原则基本介绍实例代码依赖关系传递的三种方式注意事项和细节 里氏替换原则基本介绍实例代码 开闭原则基本介绍实例代码 迪米特法则基本介绍实例代码注意事项和细节…

golang笔记17--编译调试go源码

golang笔记17--编译调试go源码 前置条件编译源码在 fmt 包中加自定义函数说明 当前go语言越来越流行了&#xff0c;各大厂商都有加大go工程师的需求&#xff0c;作为go语言的学习者&#xff0c;我们除了要了解如何使用go语言外&#xff0c;也有必要了解一下如何编译、调试go源码…

解决XXLJOB重复执行问题--Redis加锁+注解+AOP

基于Redis加锁注解AOP解决JOB重复执行问题 现象解决方案自定义注解定义AOP策略redis 加锁实践 现象 线上xxljob有时候会遇到同一个任务在调度的时候重复执行&#xff0c;如下图&#xff1a; 线上JOB服务运行了2个实例&#xff0c;有时候会重复调度到同一个实例&#xff0c;有…

交换机端口灯常亮 端口up状态 服务器设置ip交换机获取不到服务器网卡mac地址 不能通信

环境: 深信服防火墙 8.0.75 AF-2000-FH2130B-SC S6520X-24ST-SI交换机 version 7.1.070, Release 6530P02 问题描述: 交换机一个vlan下有3台服务器,连接端口2、3、4,2和3连接的服务器正常,交换机3端口灯常亮 端口up状态 服务器自动获取不了地址,改为手动设置ip后,交…

力扣labuladong——一刷day01

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、21. 合并两个有序链表二、力扣86. 分隔链表三、力扣23. 合并 K 个升序链表四、力扣删除链表的倒数第 N 个结点 前言 一、21. 合并两个有序链表 /*** Defin…

微信小程序 onLoad和onShow的区别

在微信小程序中&#xff0c;onLoad() 和 onShow() 是两个常用的生命周期函数&#xff0c;用于监听页面的加载和显示事件。这两个函数的区别如下&#xff1a; 触发时机 onLoad() 函数只会在页面加载时触发一次&#xff0c;而 onShow() 函数每次页面显示时都会被触发。因此&#…

Xubuntu16.04系统中安装create_ap创建无线AP

1.背景说明 在Xubuntu16.04系统的设备上安装无线WIFI模块后&#xff0c;想通过设备自身的无线AP&#xff0c;进行和外部设备的连接&#xff0c;需要安装create_ap软件&#xff0c;并设置无线AP的名称和密码&#xff0c;并设置为开机自启动。 create_ap是一个用于在Linux系统上创…