Vue3.0組件通信mitt源碼ts實例解析
背景介紹
近期業(yè)務(wù)開發(fā),會想起之前做的兩個組件的通信,社區(qū)推薦使用一個迷你庫miit (200b), 因為vue3開發(fā)中沒有了 EventBus 跨組件通信,這個替代的方案 mitt.js,原理還是 EventBus
EventBus在多個組件之間進行事件通信的場景下還是比較有用的,通過監(jiān)聽事件和觸發(fā)事件,可以在訂閱者和發(fā)布者之間解耦,實現(xiàn)一個常規(guī)的eventBus也比較簡單
以上實例是組件B想和組件C通信,但是mitt不管組件嵌套多深都可以直接拿來用
使用方法
先安裝 npm i mitt -S
到項目中,然后像以前封裝EventBus一樣封裝
// 可以在項目目錄utils下封裝一個event.js import mitt from 'mitt' const mitt = mitt() export default mitt
業(yè)務(wù)邏輯組件中通信使用
// 組件 A <script setup> import mitt from '@/utils/event.js' function handleChange(obj) { mitter.emit('search-change', obj); } </script> // 組件 B <script setup> import mitt from '@/utils/event.js' import { onUnmounted ,onMounted} from 'vue' // 監(jiān)聽 onMounted(()=>{ mitt.on('search-change',(obj)=> { do sth} }) // off 監(jiān)聽 onUnmounted(()=>{ mitt.off('search-change', ()=> { do sth } }) </script>
源碼分析
一行行看,看懂每一行的寫法和整體思想
export type EventType = string | symbol; // 源碼第一段分析 export 一個類型別名 EventType,上面例子中我們mitter.emit('search-change', obj); search-change就是一個string類型, 同時EventType也可以是聯(lián)合類型symbol,為了保證事件的唯一性 export type Handler<T = unknown> = (event: T) => void; export type WildcardHandler<T = Record<string, unknown>> = ( type: keyof T, event: T[keyof T] ) => void; // 源碼第二段分析 使用類型別名定義函數(shù)Handler,Handler接受一個泛型參數(shù)<T>,默認值是unknown export type EventHandlerList<T = unknown> = Array<Handler<T>>; export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>; // 源碼第三段分析 當前所有注冊的事件列表類型定義 Array<T>數(shù)組的泛型定義 export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<keyof Events | '*',EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>>; // 源碼第四段分析 這里是事件類型及其對應(yīng)的事件處理程序的映射Map做了定義,使用extend繼承一個Record對象, 該對象的兩個參數(shù)一個是限制為Events上已知的公共屬性名的聯(lián)合或者*, 另外一個參數(shù)要是是EventHandlerList或者是WildCardEventHandlerList 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; } // 源碼第五段分析 interface Emitter用于下面一段核心代碼的返回值類型定義,這個interface定義了具體函數(shù)的結(jié)構(gòu)類型 Emitter這個類型的泛型是Events繼承一個Record對象,該對象的key為EventType,value為unknown 導(dǎo)出了一個 mitt([all])函數(shù),調(diào)用該函數(shù)返回一個 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<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!); }); } } }; }
核心代碼主要實現(xiàn)就是:
1.all = all || new Map() mitt 支持傳入 all 參數(shù)用來存儲事件類型和事件處理函
數(shù)的映射Map,如果不傳,就 `new Map()`賦值給 all
2.on(type, handler)定義函數(shù) on來注冊事件,以type為屬性,[handler]為屬性值,
存儲在 all 中,屬性值為數(shù)組的原因是可能存在監(jiān)聽一個事件,多個處理程序
3.off(type, [handler])來取消某個事件的某個處理函數(shù),根據(jù) type 找到對應(yīng)的事件處理數(shù)組,
對比 handler 是否相等,相等則刪除該處理函數(shù),不傳則刪除該事件的全部處理函數(shù)
4.emit(type, [evt])來派發(fā)事件,根據(jù) type 找到對應(yīng)的事件處理數(shù)組并依次執(zhí)行,傳入?yún)?shù) evt(對象最好,傳多個參數(shù)只會取到第一個)
以上就是Vue3.0組件通信mitt源碼ts實例解析的詳細內(nèi)容,更多關(guān)于Vue3.0組件通信mitt ts的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue利用computer解決單項數(shù)據(jù)流的問題詳解
Vue 是一個非常流行和強大的前端框架,它讓我們可以用簡潔和優(yōu)雅的方式來構(gòu)建用戶界面,今天我們來分享一個 Vue 中非常經(jīng)典的問題,也是一個非常實用的技巧,希望對大家有所幫助2023-07-07解決vue+router路由跳轉(zhuǎn)不起作用的一項原因
這篇文章主要介紹了解決vue+router路由跳轉(zhuǎn)不起作用的一項原因,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07vue響應(yīng)式更新機制及不使用框架實現(xiàn)簡單的數(shù)據(jù)雙向綁定問題
vue是一款具有響應(yīng)式更新機制的框架,既可以實現(xiàn)單向數(shù)據(jù)流也可以實現(xiàn)數(shù)據(jù)的雙向綁定。這篇文章主要介紹了vue響應(yīng)式更新機制及不使用框架實現(xiàn)簡單的數(shù)據(jù)雙向綁定問題,需要的朋友可以參考下2019-06-06