vue3事件库mitt原理解读及实现
因为vue3去除了on和off方法,这样也导致在vue2中使用的事件总线不能在vue3上继续使用,以下是对于mitt库的解读和重新实现。
mitt的基本思想是构造出一个对象,该对象满足下面的四个基本要求:
- 有存储各种事件回调函数容器
- 可以对相应的的事件绑定回调函数
- 可以触发相关的回调函数
- 可以取消相关事件的回调函数
上面的四个点对应着这个对象有四个属性方法,分别是:all,on,off和emit。
type EventType = string | symbole //事件的名称是字符串或者符号类型
type Handler<T> = (event: T) => void //接收一个参数T的消费型函数
//存储事件回调函数的容器,那么就有两个结构来存储,这里源码用的是array,而这里选择使用set
//map中装入Array来存储
//type EventHandlerMap<Events extends Record<EventType, unknow>> = Map<keyof Events,Array<Handler<Events[keyof Events]>>>
//map中装入set来存储
type EventHandlerMap<Events extends Record<EventType,unknow>> = Map<keyof Events,Set<Handler<Events[keyof Events]>>>
interface Emitter<Events extends Record<EventType,unknow>>{
all: EventHanlderMap<Events>
on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void
off<Key extends keyof Events>(type: Key): void
emit<Key extends keyof Events>(type:Key, args: Events[Key]): void
}
这里的所有回调函数都只接收一个参数。例如:
type MyMitter = {
oneEvent: string
hello: {
name: string
age: number
}
}
const emitter:Emitter<MyMitter> ;
//这里的emitter就是一个事件对象,它有oneEvent和hello两个事件,
//oneEvent事件的回调函数接受一个字符串函数即 (arg: string) => void
//hello事件的回调函数接收一个{name: string, age: number}类型参数的函数即
// (arg: {name: string, age: number}) => void
那么目标就清晰了 => 构造出这个对象
那么构造这个对象又有多种方法了,官方使用是一个函数接收一个参数,返回这个需要构造的对象。源码如下:
export default function mitt<Events extends Record<EventType, unknown>>(
all?: EventHandlerMap<Events>
): Emitter<Events> {
//type GenericEventHandler =
// | Handler<Events[keyof Events]>
// | WildcardHandler<Events>;源码后面那种在这里可以忽略
type GenericEventHandler = Handler<Events[keyof Events]>
all = all || new Map();
return {
/**
* A Map of event names to registered handler functions.
*/
all,
/**
* Register an event handler for the given type.
* @param {string|symbol} type Type of event to listen for, or `'*'` for all events
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
if (handlers) {
handlers.push(handler);
} else {
all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
}
},
/**
* Remove an event handler for the given type.
* If `handler` is omitted, all handlers of the given type are removed.
* @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler)
* @param {Function} [handler] Handler function to remove
* @memberOf mitt
*/
off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
if (handlers) {
if (handler) {
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
} else {
all!.set(type, []);
}
}
},
/**
* Invoke all handlers for the given type.
* If present, `'*'` handlers are invoked after type-matched handlers.
*
* Note: Manually firing '*' handlers is not supported.
*
* @param {string|symbol} type The event type to invoke
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt
*/
emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
let handlers = all!.get(type);
if (handlers) {
(handlers as EventHandlerList<Events[keyof Events]>)
.slice()
.map((handler) => {
handler(evt!);
});
}
handlers = all!.get('*');
if (handlers) {
(handlers as WildCardEventHandlerList<Events>)
.slice()
.map((handler) => {
handler(type, evt!);
});
}
}
};
}
而这里使用类的方式进行构造
//使用Map<EventType,Set<Handler>>结构
type EventHandlersMap<Events extends Record<EventType, unknown>> = Map<
keyof Events,
Set<Handler<Events[keyof Events]>>
>;
class Mitter<Events extends Record<EventType, unknown>> {
constructor(private all?: EventHandlersMap<Events>) {
this.all = all || new Map();
}
on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void {
type GenericEventHandler = Handler<Events[keyof Events]>
let handlers = this.all!.get(type);
if (!handlers) {
this.all!.set(type, (handlers = new Set()));
}
handlers.add(handler as GenericEventHandler);
}
emit<Key extends keyof Events>(type: Key, arg: Events[Key]): void {
const handlers = this.all!.get(type);
if (!handlers || handlers.size === 0) return;
else {
for (let handler of handlers) {
handler.call(null, arg);
}
}
}
off<Key extends keyof Events>(type: Key): void {
this.all!.delete(type);
}
clear(): void {
this.all = new Map();
}
}
这里也就是顺便加了个清空所有回调函数的的方法。
到这里也就结束啦!若有错误还请指正!