mitt
[TOC]
索引
- mitt():
(all?)
,用于创建一个事件总线实例,支持事件的监听、触发和移除。 - emitter.all:
{eventName: Handler[]}
,用于存储所有已注册的事件类型及其对应的事件处理器列表,用于调试或高级操作。 - emitter.on():
(type,handler)
,用于 监听指定类型的事件,当该事件被触发时,执行绑定的处理函数。支持监听具体事件类型或使用通配符*
监听所有事件。 - emitter.off():
(type,handler?)
,用于 移除指定事件类型的监听器,支持移除单个处理函数或清空某事件类型的所有监听器,避免内存泄。 - emitter.emit():
(type,data?)
,用于 触发指定类型的事件,并传递相关数据给所有监听该事件的处理器。
mitt
Mitt 是一个轻量级的事件发布/订阅(PubSub)库,用于在 JavaScript/TypeScript 中实现组件或模块间的事件通信。
mitt()
mitt():(all?)
,用于创建一个事件总线实例,支持事件的监听、触发和移除。
T:
默认:Record<string, unknown>
,定义事件类型与对应事件数据的类型约束。all?:
EventHandlerMap<T>
,默认:{}
,预定义的事件处理器映射,通常无需手动传入。保留给高级场景或库扩展使用。返回:
emitter:
Emitter<T>
,返回一个 Emitter 对象实例,包含事件监听、触发等方法:- emitter.all:
EventHandlerMap<T>
,获取所有已注册的事件处理器,用于调试或高级操作。 - emitter.on():
(type, handler)
,监听指定类型的事件。 - emitter.off():
(type, handler)
,移除指定类型的事件监听。 - emitter.emit():
(type, event?)
,触发指定类型的事件,传递事件数据。
- emitter.all:
语法:
泛型参数T:用户自定义的事件类型对象。
tstype MyEvents = { click: MouseEvent; message: string; 'user-updated': { id: number; name: string }; }; const emitter = mitt<MyEvents>();
all
emitter.all:{eventName: Handler[]}
,用于存储所有已注册的事件类型及其对应的事件处理器列表,用于调试或高级操作。
返回:
eventName:
string
,事件类型。Handler:
(event)=>void
,该事件类型对应的处理器函数数组。语法:
访问方式:
tsconst emitter = mitt<MyEvents>(); const handlersMap = emitter.all; // 直接访问属性
结构示例
ts// 假设监听了一个 'click' 事件和一个通配符 '*' 事件 emitter.all = { 'click': [ (event) => console.log(event) ], '*': [ (type, event) => console.log(type, event) ] };
常见用途:
调试事件监听器:查看所有已注册的事件类型及其处理器数量。
jsconsole.log(emitter.all); // 输出示例: { click: [ [Function] ], '*': [ [Function] ] }
批量移除监听器:清空所有事件类型的监听器。
jsObject.keys(emitter.all).forEach(type => { emitter.all[type].forEach(handler => { emitter.off(type, handler); }); });
动态管理特定事件:直接操作处理器数组(需谨慎)。
js// 移除某个事件类型的所有监听器 delete emitter.all['click']; // 添加一个监听器(等效于 emitter.on('click', handler)) emitter.all['click'] = emitter.all['click'] || []; emitter.all['click'].push(handler);
克隆事件总线状态:
tsfunction cloneEmitter(original) { const cloned = mitt(); Object.entries(original.all).forEach(([type, handlers]) => { cloned.all[type] = [...handlers]; }); return cloned; }
注意事项:
避免直接修改:直接操作 all,如增删数组元素,可能破坏 Mitt 内部状态,建议优先使用 on()/off() 方法。
通配符事件处理:通配符事件
'*'
的处理器存储在all['*']
中,其函数签名为(type, event) => void
。TS类型安全:若使用泛型定义事件类型,访问 all 时会自动推断键名和处理器类型。
tstype MyEvents = { message: string }; const emitter = mitt<MyEvents>(); emitter.on('message', (data) => {}); // data 类型自动推断为 string const handlers = emitter.all['message']; // 类型为 Array<Handler<string>>
on()
emitter.on():(type,handler)
,用于 监听指定类型的事件,当该事件被触发时,执行绑定的处理函数。支持监听具体事件类型或使用通配符 *
监听所有事件。
type:
string|*
,指定要监听的事件类型。若为*
,则监听所有事件。handler:事件触发时执行的回调函数。根据 type 不同,函数参数不同:
(data)=>void
:监听具体事件时。(type,data)=>void
:监听通配符时。
注意事项:
重复监听:同一事件类型可绑定多个处理函数,触发时按添加顺序执行。
内存泄漏:若组件或对象销毁,需调用 off() 移除相关监听,避免残留引用。
匿名函数问题:使用匿名函数作为处理函数时,无法直接通过 off() 移除,需保存函数引用。
js// 错误示例:无法移除 emitter.on('event', () => {}); emitter.off('event', () => {}); // 无效 // 正确做法:保存引用 const handler = () => {}; emitter.on('event', handler); emitter.off('event', handler);
示例:
基础用法
jsimport mitt from 'mitt'; const emitter = mitt(); // 监听具体事件 emitter.on('login', (user) => { console.log('User logged in:', user); }); // 监听所有事件(通配符) emitter.on('*', (eventType, data) => { console.log(`Global listener: ${eventType} ->`, data); }); // 触发事件 emitter.emit('login', { name: 'Alice' }); // 输出: // User logged in: { name: 'Alice' } // Global listener: login -> { name: 'Alice' }
TS类型安全用法
tstype AppEvents = { error: Error; notification: { title: string; content: string }; }; const emitter = mitt<AppEvents>(); // 监听具体事件(自动推断参数类型) emitter.on('error', (err) => { console.error(err.message); // err 类型为 Error }); emitter.on('notification', (notice) => { console.log(notice.title, notice.content); // notice 类型为 { title: string; content: string } }); // 监听所有事件(通配符) emitter.on('*', (type, data) => { if (type === 'error') { console.log('Error occurred:', data.message); // data 类型为 Error } else if (type === 'notification') { console.log('New notification:', data.title); // data 类型为 { title: string; content: string } } }); // 触发事件(类型检查) emitter.emit('error', new Error('Auth failed')); emitter.emit('notification', { title: 'Update', content: 'New version available' });
off()
emitter.off():(type,handler?)
,用于 移除指定事件类型的监听器,支持移除单个处理函数或清空某事件类型的所有监听器,避免内存泄。
type:
string|*
,指定要移除监听的事件类型。若为*
,表示移除通配符监听器。handler?:
function
,指定要移除的特定处理函数。若省略,则移除该事件类型下的所有监听器。语法:
移除指定的单个监听器:需传入与 on() 绑定时相同的函数引用。
jsconst handler1 = (data) => console.log('Handler 1:', data); const handler2 = (data) => console.log('Handler 2:', data); emitter.on('event', handler1); emitter.on('event', handler2); emitter.off('event', handler1); // 仅移除 handler1
清空所有指定类型的监听器:
jsemitter.on('event', handler1); emitter.on('event', handler2); emitter.off('event'); // 移除所有 'event' 监听器
清空所有监听器:可通过遍历 all 属性批量移除监听器(谨慎操作)。
jsObject.keys(emitter.all).forEach(type => { emitter.off(type); // 移除所有类型的监听器 });
移除通配符监听器:通配符
*
监听器必须通过off('*', handler)
移除,不可省略 handler 参数。jsemitter.on('*', wildcardHandler); emitter.off('*', wildcardHandler); // 正确移除
emit()
emitter.emit():(type,data?)
,用于 触发指定类型的事件,并传递相关数据给所有监听该事件的处理器。
type:
string
,指定要触发的事件类型。data?:
any
,传递给事件处理器的数据。语法:
触发事件-无数据:
jsimport mitt from 'mitt'; const emitter = mitt(); // 监听事件 emitter.on('refresh', () => { console.log('Page refreshed'); }); // 触发事件(无数据) emitter.emit('refresh'); // 输出: Page refreshed
触发事件-带数据:
jsimport mitt from 'mitt'; const emitter = mitt(); // 监听事件 emitter.on('message', (data) => { console.log('Received:', data); }); // 触发事件(带数据) emitter.emit('message', 'Hello World!'); // 输出: Received: Hello World!
触发通配符事件:当调用 emit() 时,所有监听
*
的处理器也会被触发,接收事件类型和数据。jsemitter.on('*', (type, data) => { console.log(`[${type}]`, data); }); emitter.emit('message', 'Hello'); // 输出: [message] Hello
默认值处理:若未传递 event,处理器接收 undefined,需在代码中处理可能的空值。
jsemitter.on('event', (data) => { console.log(data?.value); // 使用可选链避免错误 }); emitter.emit('event'); // data 为 undefined
TS事件类型约束:
- 必须与泛型 T 中定义的事件类型严格匹配,否则触发类型错误。
tstype Events = { message: string; error: Error }; const emitter = mitt<Events>(); emitter.emit('message', 'Hello'); // 正确 emitter.emit('error', new Error('Fail')); // 正确 emitter.emit('warning', 'Oops'); // TS 报错:'warning' 不在 Events 中定义
- 若事件类型对应的数据为 void(无数据),可省略 data 参数。否则必须传递 data 参数。
tstype Events = { refresh: void; // 无数据 update: { id: number }; }; const emitter = mitt<Events>(); emitter.emit('refresh'); // 正确(无数据) emitter.emit('update', { id: 1 }); // 正确 emitter.emit('update'); // TS 报错:缺少数据
注意事项:
事件数据不可变性:若传递对象或数组,确保数据未被意外修改,避免副作用。
jsconst data = { value: 1 }; emitter.emit('update', data); data.value = 2; // 所有监听器看到的 data.value 会被修改!
异步触发问题:emit() 是同步方法,处理器按注册顺序立即执行。若需异步触发,可包裹在 setTimeout 或 Promise 中。
jssetTimeout(() => { emitter.emit('async-event', 'Delayed data'); }, 1000);
避免循环触发:防止在处理器中再次触发相同事件,导致无限循环。
jsemitter.on('event', () => { emitter.emit('event'); // 危险:可能导致堆栈溢出 });