在 Vue 2 里,开发者常常使用 event bus 来处理非父子组件之间的通信。不过,这种方式在大型项目中容易让代码变得难以维护,因为事件的流向和触发位置会变得不清晰。Vue 3 推荐采用组合式 API 和 provide/inject、Vuex(状态管理库)、Pinia(状态管理库)等方式来实现组件间的通信,这些方式能让代码结构更加清晰,易于维护。
如果仍需要使用event bus,可以使用轻量级的事件发布 - 订阅库 mitt
来实现 event bus 功能,它可以帮助你实现组件间的通信和解耦。下面详细介绍 mitt
的使用方法。
安装
npm install mitt
在项目中使用
1. 创建全局事件总线
在 Vue 项目中,你可以创建一个全局的事件总线,方便在不同组件之间进行通信。
// event-bus.js
import mitt from 'mitt';
// 创建一个 mitt 实例作为事件总线
const eventBus = mitt();
export default eventBus;
2. 在组件中使用事件总线
<!-- ComponentA.vue -->
<template>
<div>
<button @click="sendMessage">发送消息</button>
</div>
</template>
<script setup>
import eventBus from './event-bus';
const sendMessage = () => {
// 发布事件
eventBus.emit('message', '来自 ComponentA 的消息');
};
</script>
<!-- ComponentB.vue -->
<template>
<div>
<!-- 显示接收到的消息 -->
<p>{{ receivedMessage }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import eventBus from './event-bus';
const receivedMessage = ref('');
const handleMessage = (data) => {
receivedMessage.value = data;
};
onMounted(() => {
// 订阅事件
eventBus.on('message', handleMessage);
});
onUnmounted(() => {
// 取消订阅事件
eventBus.off('message', handleMessage);
});
</script>
取消订阅事件
使用 off
方法可以取消订阅事件,该方法接受两个参数:事件名称和要取消的回调函数。
// 定义回调函数
const handleMessage = (data) => {
console.log('收到消息:', data);
};
// 订阅事件
emitter.on('message', handleMessage);
// 取消订阅事件
emitter.off('message', handleMessage);
清空所有事件监听器
使用 all.clear()
方法可以清空所有的事件监听器。
// 清空所有事件监听器
emitter.all.clear();
案例
有了发布-订阅事件,我们就可以实现在封装好的js文件中发布事件,在页面中订阅事件了。例如我封装了webSocket.js,在收到新消息的时候发布事件携带消息,然后在页面中订阅拿到新消息。
webSocket.js
import bus from "@/utils/bus";
export class Socket {
constructor(url) {
this.url = url;
this.socket = null;
}
connectSocket() {
// 监听WebSocket打开连接
this.socket.onopen = () => {
console.log("WebSocket连接打开成功!");
};
// 监听WebSocket错误
this.socket.onerror = (res: any) => {
console.log("WebSocket连接打开失败,请检查!", res);
};
// 监听WebSocket接受到服务器的消息
this.socket.onmessage = (res: any) => {
console.log("收到服务器内容:", res.data);
const data = JSON.parse(res.data);
bus.emit("newMessage", data.message);
};
}
...
}
message.vue
在message.vue中订阅新消息
import bus from "@/utils/bus";
onMounted(() => {
const socket = new Socket("wss://xxx");
messageStore.messageSocket = socket;
socket.connectSocket();
// 收到新消息弹出消息通知
bus.on("newMessage", (data: any) => {
ElNotification({
title: data.title,
message: data.content
});
});
});