初衷
vue3.0取消了全局emit和on,官方推荐使用mitt。由于之前vue2.0全局bus项目出现了问题(页面多个相同组件,其中一个组件卸载调用off事件,其他相同组件失去监听),而且因为我们项目基本off都在组件卸载调用,想要支持组件卸载自动off,所以就想着自己重写。
编码
由于TS项目首先先定义类型
//定义可注册事件类型(根据项目配置)
export type IEventAction = 'PROJECT_MONEY_EVENT';
//定义EventBus函数返回对象
export interface IEventBus {
emit: (event: IEventAction, ...args: Array<any>) => void;
on: (event: IEventAction, cb: (...args: Array<any>) => void) => void;
}
创建on函数
//存储所有事件map
const eventMap = new Map<IEventAction, Map<number, (...args: Array<any>) => void>>();
export function useEventBus(): IEventBus {
//获取当前注册组件的实例用于区别代码复用的组件
const currentInstance = getCurrentInstance();
//储存当前组件注册的所有事件
const currentEvents: Array<IEventAction> = [];
function on(event: IEventAction, cb: (...args: Array<any>) => void) {
currentEvents.push(event);
//根据事件获取是否存在该事件map对象
const eventUidMap = eventMap.get(event);
if (currentInstance) {
//有map对象就根据组件id添加函数
if (eventUidMap) {
eventUidMap.set(currentInstance.uid, cb);
} else {
const eventUidMap = new Map();
if (currentInstance) eventUidMap.set(currentInstance.uid, cb);
eventMap.set(event, eventUidMap);
}
}
}
}
创建emit函数
export function useEventBus(): IEventBus {
//获取当前注册组件的实例用于区别代码复用的组件
const currentInstance = getCurrentInstance();
//储存当前组件注册的所有事件
const currentEvents: Array<IEventAction> = [];
function emit(event: IEventAction, ...args: Array<any>) {
//根据发射事件获取全部组件函数并调用
const eventUidMap = eventMap.get(event);
if (eventUidMap) {
eventUidMap.forEach((eventAction) => {
if (typeof eventAction === 'function') {
eventAction(...args);
}
});
}
}
}
根据组件卸载自动注销该组件的所有事件
onBeforeUnmount(() => {
if (currentInstance) {
//根据当前组件注册的所有事件,清空相同组件id的事件函数
for (const event of currentEvents) {
const eventUidMap = eventMap.get(event);
if (eventUidMap) {
eventUidMap.delete(currentInstance.uid);
if (eventUidMap.size === 0) {
eventMap.delete(event);
}
}
}
}
});
全部代码如下,初步代码后续还在优化,有需要的可以参考。
import { getCurrentInstance, onBeforeUnmount } from 'vue';
//定义可注册事件类型
export type IEventAction = 'PROJECT_MONEY_EVENT';
//定义EventBus函数返回对象
export interface IEventBus {
emit: (event: IEventAction, ...args: Array<any>) => void;
on: (event: IEventAction, cb: (...args: Array<any>) => void) => void;
}
//存储所有事件map
const eventMap = new Map<IEventAction, Map<number, (...args: Array<any>) => void>>();
export function useEventBus(): IEventBus {
//获取当前注册组件的实例用于区别代码复用的组件
const currentInstance = getCurrentInstance();
//储存当前组件注册的所有事件
const currentEvents: Array<IEventAction> = [];
function emit(event: IEventAction, ...args: Array<any>) {
const eventUidMap = eventMap.get(event);
if (eventUidMap) {
eventUidMap.forEach((eventAction) => {
if (typeof eventAction === 'function') {
eventAction(...args);
}
});
}
}
function on(event: IEventAction, cb: (...args: Array<any>) => void) {
currentEvents.push(event);
const eventUidMap = eventMap.get(event);
if (currentInstance) {
if (eventUidMap) {
eventUidMap.set(currentInstance.uid, cb);
} else {
const eventUidMap = new Map();
if (currentInstance) eventUidMap.set(currentInstance.uid, cb);
eventMap.set(event, eventUidMap);
}
}
}
//自动根据组件注销 来注销当前组件的所有事件
onBeforeUnmount(() => {
if (currentInstance) {
for (const event of currentEvents) {
const eventUidMap = eventMap.get(event);
if (eventUidMap) {
eventUidMap.delete(currentInstance.uid);
if (eventUidMap.size === 0) {
eventMap.delete(event);
}
}
}
}
});
return { emit, on };
}