前言:
此刻朋友们对“html工作室源码”都比较讲究,兄弟们都需要分析一些“html工作室源码”的相关资讯。那么小编也在网上网罗了一些有关“html工作室源码””的相关知识,希望姐妹们能喜欢,兄弟们快快来学习一下吧!介绍
Tiny 200b functional event emitter / pubsub.
200b大小的微型功能事件发布/订阅库
Mitt was made for the browser, but works in any JavaScript runtime. It has no dependencies and supports IE9+.
Mitt是为浏览器设计的,但可以在任意JavaScript运行时使用,无依赖且支持IE9+。
一般在现代框架跨组件通信时会比较常用,例如在vue跨组件通信时会比较有用,在vue2中可以使用自带的 $on,$off,$emit 等api进行通信,当在vue3中移除了这些api,取而代之的有 mitt 或者 tiny-emitter 。
install
npm install --save mittES6 Modules
import mitt from "mitt"CommonJs Modules
const mitt = require("mitt");CDN
<script src=";></script>// 然后在wndow上访问window.mittUsage基本使用
import mitt from 'mitt';const emitter = mitt();// 监听事件emitter.on('foo', e => console.log('foo', e) );// 解除监听emitter.off('foo', onFoo);// 监听全部事件emitter.on('*', (type, e) => console.log(type, e) );// 触发事件emitter.emit('foo', { a: 'b' });// 清除所有事件监听emitter.all.clear()typescript支持
import mitt from 'mitt';type Events = { foo: string; bar?: number;};const emitter = mitt<Events>();emitter.on('foo', (e) => {}); // e的类型为string简单的封装
// mitt.tsimport mitt from "mitt";type Events = { change: string | undefined; submit: number[]}const emitter = mitt<Events>();export default emitter;// 组件 A<script setup lang="ts">import Emitter from "@/shared/mitt";Emitter.emit("submit", [1]);</script>// 组件B<script setup lang="ts">import Emitter from "@/shared/mitt";Emitter.on("submit", (params) => { // params 的类型 => number[] console.log(params);})</script>源码解析
完整的源码如下
export type EventType = string | symbol;// An event handler can take an optional event argument// and should not return a valueexport type Handler<T = unknown> = (event: T) => void;export type WildcardHandler<T = Record<string, unknown>> = ( type: keyof T, event: T[keyof T]) => void;// An array of all currently registered event handlers for a typeexport type EventHandlerList<T = unknown> = Array<Handler<T>>;export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;// A map of event types and their corresponding event handlers.export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map< keyof Events | '*', EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>>;export interface Emitter<Events extends Record<EventType, unknown>> { all: EventHandlerMap<Events>; on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void; on(type: '*', handler: WildcardHandler<Events>): void; off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void; off(type: '*', handler: WildcardHandler<Events>): void; emit<Key extends keyof Events>(type: Key, event: Events[Key]): void; emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;}/** * Mitt: Tiny (~200b) functional event emitter / pubsub. * @name mitt * @returns {Mitt} */export default function mitt<Events extends Record<EventType, unknown>>( all?: EventHandlerMap<Events>): Emitter<Events> { type GenericEventHandler = | Handler<Events[keyof Events]> | WildcardHandler<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!); }); } } };}
可以看到,整个库暴露的api只有以下4个
all,on(),off(),emit()
接下来了解一下每个api的实现
all
从源码可以看出 all 是一个 Map 对象,用来存储所有的事件,如果初始化没有传入会自动创建一个空的 Map 对象,所以支持所有 Map 的方法,如:
// 获取监听函数Emitter.all.get(key); // 设置监听事件Emitter.all.set(key, [handler]);// 清除所有事件Emitter.all.clear();on
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]>); }},
on() 用于监听事件,接收两个参数:
type 事件名称handler 回调函数
Emitter.on(type, handler);
在函数内部,首先获取对应 type 的 handler 列表,如果存在,则向 handlers 中 push
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);if (handlers) { handlers.push(handler);}
如果不存在,则设置对应事件处理回调
all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);off
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, []); } }}
off() 用于移除事件监听,接收两个参数:
type 事件名称handler 要移除的回调函数,可选
首先获取对应 type 的 handler 列表,然后判断 handlers 是否存在,如果此时传入了 handler,则删除对应的 handler
if (handler) { handlers.splice(handlers.indexOf(handler) >>> 0, 1);}
需要注意的是,这里使用了 无符号右移运算符(>>>)(具体用法请查阅MDN),且移位了 0,对于 非负数 来说,进行该运算没有任何作用,而如果是 -1 >>> 0,其运算结果就是4294967295,而 splice 方法如果传入的 start > array.length,并不会删除任何元素,其实就是省略了一步判断而已,使代码更精简,相当于如下代码
let index = handlers.indexOf(handler);if (index > -1) { handlers.splice(index, 1);}
如果没有传入 handler,则清空对应的监听列表
all!.set(type, []);emit
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!); }); }}
emit() 用于触发事件监听,接收两个参数:
type 事件名称evt 传入回调的参数
emit() 的逻辑就是获取对应的 handlers,然后循环执行回调,并且会通知 type = * 的订阅回调
以上就是本文的全部内容了,如果觉得有用的话,可以关注作者哦!
本文为原创作品,未经同意禁止转载!
标签: #html工作室源码