在 Vue 2 里,開(kāi)發(fā)者常常使用 event bus 來(lái)處理非父子組件之間的通信。不過(guò),這種方式在大型項(xiàng)目中容易讓代碼變得難以維護(hù),因?yàn)槭录牧飨蚝陀|發(fā)位置會(huì)變得不清晰。Vue 3 推薦采用組合式 API 和 provide/inject、Vuex(狀態(tài)管理庫(kù))、Pinia(狀態(tài)管理庫(kù))等方式來(lái)實(shí)現(xiàn)組件間的通信,這些方式能讓代碼結(jié)構(gòu)更加清晰,易于維護(hù)。
如果仍需要使用event bus,可以使用輕量級(jí)的事件發(fā)布 - 訂閱庫(kù) mitt
來(lái)實(shí)現(xiàn) event bus 功能,它可以幫助你實(shí)現(xiàn)組件間的通信和解耦。下面詳細(xì)介紹 mitt
的使用方法。
安裝
npm install mitt
在項(xiàng)目中使用
1. 創(chuàng)建全局事件總線
在 Vue 項(xiàng)目中,你可以創(chuàng)建一個(gè)全局的事件總線,方便在不同組件之間進(jìn)行通信。
// event-bus.js
import mitt from 'mitt';
// 創(chuàng)建一個(gè) mitt 實(shí)例作為事件總線
const eventBus = mitt();
export default eventBus;
2. 在組件中使用事件總線
<!-- ComponentA.vue -->
<template>
<div>
<button @click="sendMessage">發(fā)送消息</button>
</div>
</template>
<script setup>
import eventBus from './event-bus';
const sendMessage = () => {
// 發(fā)布事件
eventBus.emit('message', '來(lái)自 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
方法可以取消訂閱事件,該方法接受兩個(gè)參數(shù):事件名稱和要取消的回調(diào)函數(shù)。
// 定義回調(diào)函數(shù)
const handleMessage = (data) => {
console.log('收到消息:', data);
};
// 訂閱事件
emitter.on('message', handleMessage);
// 取消訂閱事件
emitter.off('message', handleMessage);
清空所有事件監(jiān)聽(tīng)器
使用 all.clear()
方法可以清空所有的事件監(jiān)聽(tīng)器。
// 清空所有事件監(jiān)聽(tīng)器
emitter.all.clear();
案例
有了發(fā)布-訂閱事件,我們就可以實(shí)現(xiàn)在封裝好的js文件中發(fā)布事件,在頁(yè)面中訂閱事件了。例如我封裝了webSocket.js,在收到新消息的時(shí)候發(fā)布事件攜帶消息,然后在頁(yè)面中訂閱拿到新消息。
webSocket.js
import bus from "@/utils/bus";
export class Socket {
constructor(url) {
this.url = url;
this.socket = null;
}
connectSocket() {
// 監(jiān)聽(tīng)WebSocket打開(kāi)連接
this.socket.onopen = () => {
console.log("WebSocket連接打開(kāi)成功!");
};
// 監(jiān)聽(tīng)WebSocket錯(cuò)誤
this.socket.onerror = (res: any) => {
console.log("WebSocket連接打開(kāi)失敗,請(qǐng)檢查!", res);
};
// 監(jiān)聽(tīng)WebSocket接受到服務(wù)器的消息
this.socket.onmessage = (res: any) => {
console.log("收到服務(wù)器內(nèi)容:", 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
});
});
});