Vue3.0組件通信mitt源碼ts實(shí)例解析
背景介紹
近期業(yè)務(wù)開(kāi)發(fā),會(huì)想起之前做的兩個(gè)組件的通信,社區(qū)推薦使用一個(gè)迷你庫(kù)miit (200b), 因?yàn)関ue3開(kāi)發(fā)中沒(méi)有了 EventBus 跨組件通信,這個(gè)替代的方案 mitt.js,原理還是 EventBus
EventBus在多個(gè)組件之間進(jìn)行事件通信的場(chǎng)景下還是比較有用的,通過(guò)監(jiān)聽(tīng)事件和觸發(fā)事件,可以在訂閱者和發(fā)布者之間解耦,實(shí)現(xiàn)一個(gè)常規(guī)的eventBus也比較簡(jiǎn)單

以上實(shí)例是組件B想和組件C通信,但是mitt不管組件嵌套多深都可以直接拿來(lái)用
使用方法
先安裝 npm i mitt -S到項(xiàng)目中,然后像以前封裝EventBus一樣封裝
// 可以在項(xiàng)目目錄utils下封裝一個(gè)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)聽(tīng)
onMounted(()=>{ mitt.on('search-change',(obj)=> { do sth} })
// off 監(jiān)聽(tīng)
onUnmounted(()=>{ mitt.off('search-change', ()=> { do sth } })
</script>
源碼分析
一行行看,看懂每一行的寫(xiě)法和整體思想
export type EventType = string | symbol;
// 源碼第一段分析
export 一個(gè)類型別名 EventType,上面例子中我們mitter.emit('search-change', obj);
search-change就是一個(gè)string類型,
同時(shí)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接受一個(gè)泛型參數(shù)<T>,默認(rèn)值是unknown
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
export type WildCardEventHandlerList<T = Record<string, unknown>>
= Array<WildcardHandler<T>>;
// 源碼第三段分析
當(dāng)前所有注冊(cè)的事件列表類型定義 Array<T>數(shù)組的泛型定義
export type EventHandlerMap<Events extends Record<EventType, unknown>>
= Map<keyof Events | '*',EventHandlerList<Events[keyof Events]>
| WildCardEventHandlerList<Events>>;
// 源碼第四段分析
這里是事件類型及其對(duì)應(yīng)的事件處理程序的映射Map做了定義,使用extend繼承一個(gè)Record對(duì)象,
該對(duì)象的兩個(gè)參數(shù)一個(gè)是限制為Events上已知的公共屬性名的聯(lián)合或者*,
另外一個(gè)參數(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用于下面一段核心代碼的返回值類型定義,這個(gè)interface定義了具體函數(shù)的結(jié)構(gòu)類型
Emitter這個(gè)類型的泛型是Events繼承一個(gè)Record對(duì)象,該對(duì)象的key為EventType,value為unknown
導(dǎo)出了一個(gè) mitt([all])函數(shù),調(diào)用該函數(shù)返回一個(gè) Emitter,該對(duì)象包含all、
on(type, handler)、off(type, [handler])和emit(type, [evt])這幾個(gè)屬性
/**
* 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!);
});
}
}
};
}
核心代碼主要實(shí)現(xiàn)就是:
1.all = all || new Map() mitt 支持傳入 all 參數(shù)用來(lái)存儲(chǔ)事件類型和事件處理函
數(shù)的映射Map,如果不傳,就 `new Map()`賦值給 all
2.on(type, handler)定義函數(shù) on來(lái)注冊(cè)事件,以type為屬性,[handler]為屬性值,
存儲(chǔ)在 all 中,屬性值為數(shù)組的原因是可能存在監(jiān)聽(tīng)一個(gè)事件,多個(gè)處理程序
3.off(type, [handler])來(lái)取消某個(gè)事件的某個(gè)處理函數(shù),根據(jù) type 找到對(duì)應(yīng)的事件處理數(shù)組,
對(duì)比 handler 是否相等,相等則刪除該處理函數(shù),不傳則刪除該事件的全部處理函數(shù)
4.emit(type, [evt])來(lái)派發(fā)事件,根據(jù) type 找到對(duì)應(yīng)的事件處理數(shù)組并依次執(zhí)行,傳入?yún)?shù) evt(對(duì)象最好,傳多個(gè)參數(shù)只會(huì)取到第一個(gè))
以上就是Vue3.0組件通信mitt源碼ts實(shí)例解析的詳細(xì)內(nèi)容,更多關(guān)于Vue3.0組件通信mitt ts的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
為vue-router懶加載時(shí)下載js的過(guò)程中添加loading提示避免無(wú)響應(yīng)問(wèn)題
這篇文章主要介紹了為vue-router懶加載時(shí)下載js的過(guò)程中添加loading提示避免無(wú)響應(yīng)問(wèn)題,需要的朋友可以參考下2018-04-04
vite的proxy查看真實(shí)請(qǐng)求地址方式詳解
這篇文章主要為大家介紹了vite的proxy查看真實(shí)請(qǐng)求地址方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
vue使用Element組件時(shí)v-for循環(huán)里的表單項(xiàng)驗(yàn)證方法
這篇文章主要介紹了vue使用Element組件時(shí)v-for循環(huán)里的表單項(xiàng)驗(yàn)證方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
Vue2.0基于vue-cli+webpack同級(jí)組件之間的通信教程(推薦)
下面小編就為大家?guī)?lái)一篇Vue2.0基于vue-cli+webpack同級(jí)組件之間的通信教程(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
Vue用v-for給循環(huán)標(biāo)簽自身屬性添加屬性值的方法
這篇文章主要介紹了Vue用v-for給循環(huán)標(biāo)簽自身屬性添加屬性值的方法,文中大家給大家列舉了三種方法 ,需要的朋友可以參考下2018-10-10
前端不用跑項(xiàng)目vscode組件效果所見(jiàn)即所得
這篇文章主要為大家介紹了一款不用跑項(xiàng)目的vscode組件所見(jiàn)即所得效果的使用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
webpack vue 項(xiàng)目打包生成的文件,資源文件報(bào)404問(wèn)題的修復(fù)方法(總結(jié)篇)
這篇文章主要介紹了解決webpack vue 項(xiàng)目打包生成的文件,資源文件報(bào)404問(wèn)題的修復(fù)方法,需要的朋友可以參考下2018-01-01

