Vue3.0组件通信mitt源码ts分析笔记

背景介绍

前言:近期业务开发,会想起之前做的两个组件的通信,社区推荐使用一个迷你库miit (200b), 因为vue3开发中没有了 EventBus 跨组件通信,这个替代的方案 mitt.js,原理还是 EventBus

EventBus在多个组件之间进行事件通信的场景下还是比较有用的,通过监听事件和触发事件,可以在订阅者和发布者之间解耦,实现一个常规的eventBus也比较简单

Vue3.0组件通信mitt源码ts分析笔记_第1张图片

以上实例是组件B想和组件C通信,但是mitt不管组件嵌套多深都可以直接拿来用

使用方法

先安装 npm i mitt -S到项目中,然后像以前封装EventBus一样封装

// 可以在项目目录utils下封装一个event.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt 

业务逻辑组件中通信使用

// 组件 A


// 组件 B 
 

源码分析

一行行看,看懂每一行的写法和整体思想

export type EventType = string | symbol;
// 源码第一段分析
export 一个类型别名 EventType,上面例子中我们mitter.emit('search-change', obj); 
search-change就是一个string类型,
同时EventType也可以是联合类型symbol,为了保证事件的唯一性

export type Handler = (event: T) => void;
export type WildcardHandler> = ( type: keyof T,event: T[keyof T] ) => void;
// 源码第二段分析
使用类型别名定义函数Handler,Handler接受一个泛型参数,默认值是unknown

export type EventHandlerList = Array>;
export type WildCardEventHandlerList>
= Array>;
// 源码第三段分析
当前所有注册的事件列表类型定义Array数组的泛型定义

export type EventHandlerMap>
= Map 
| WildCardEventHandlerList>;
// 源码第四段分析
这里是事件类型及其对应的事件处理程序的映射Map做了定义,使用extend继承一个Record对象,
该对象的两个参数一个是限制为Events上已知的公共属性名的联合或者*, 
另外一个参数要是是EventHandlerList或者是WildCardEventHandlerList

export interface Emitter> {all: EventHandlerMap;on(type: Key, handler: Handler): void;on(type: '*', handler: WildcardHandler):void;off(type: Key, handler?:Handler): void;off(type: '*', handler: WildcardHandler):void;
 emit(type: Key, event: Events[Key]):void;emit(type: undefined extends Events[Key] ? Key : never):void;

}
// 源码第五段分析
interface Emitter用于下面一段核心代码的返回值类型定义,这个interface定义了具体函数的结构类型
Emitter这个类型的泛型是Events继承一个Record对象,该对象的key为EventType,value为unknown

导出了一个 mitt([all])函数,调用该函数返回一个 Emitter,该对象包含all、
on(type, handler)、off(type, [handler])和emit(type, [evt])这几个属性


/**
* Mitt: Tiny (~200b) functional event emitter / pubsub.
* @name mitt
* @returns {Mitt}
*/

export default function mitt>(
all?: EventHandlerMap
): Emitter {type GenericEventHandler =| Handler| WildcardHandler;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(type: Key, handler: GenericEventHandler) {const handlers: Array | undefined =all!.get(type);if (handlers) {handlers.push(handler);} else {all!.set(type, [handler] as EventHandlerList);}},/*** 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( type: Key,handler?: GenericEventHandler) {const handlers: Array | 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(type: Key, evt?: Events[Key]) {let handlers = all!.get(type);if (handlers) {(handlers as EventHandlerList).slice().map((handler) => {handler(evt!);});}handlers = all!.get('*');if (handlers) {(handlers as WildCardEventHandlerList).slice().map((handler) => {handler(type, evt!);}); }}};
}

// 核心代码
主要实现就是:
1.all = all || new Map() mitt 支持传入 all 参数用来存储事件类型和事件处理函
数的映射Map,如果不传,就 `new Map()`赋值给 all
2.on(type, handler)定义函数 on来注册事件,以type为属性,[handler]为属性值,
存储在 all 中,属性值为数组的原因是可能存在监听一个事件,多个处理程序
3.off(type, [handler])来取消某个事件的某个处理函数,根据 type 找到对应的事件处理数组,
对比 handler 是否相等,相等则删除该处理函数,不传则删除该事件的全部处理函数
4.emit(type, [evt])来派发事件,根据 type 找到对应的事件处理数组并依次执行
,传入参数 evt(对象最好,传多个参数只会取到第一个) 

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

你可能感兴趣的:(vue.js,前端,javascript)