事件匯流排Mitt使用非常簡單,本篇隨筆介紹在Vue3+TypeScript 前端項目中使用的一些場景和思路。我們在Vue 的項目中,經常會通過emits 觸發事件來通知組件或者頁面進行相應的處理,不過我們使用事件匯流排Mitt來操作一些事件的處理,也是非常方便的。 ...
事件匯流排Mitt使用非常簡單,本篇隨筆介紹在Vue3+TypeScript 前端項目中使用的一些場景和思路。我們在Vue 的項目中,經常會通過emits 觸發事件來通知組件或者頁面進行相應的處理,不過我們使用事件匯流排Mitt來操作一些事件的處理,也是非常方便的。
Mitt 的GitHub官網地址如下所示:https://github.com/developit/mitt, 它的安裝和其他插件一樣,我們不再贅述,只講述它的如何使用。
Mitt
具有以下優點:
- 零依賴、體積超小,壓縮後只有
200b
。 - 提供了完整的
typescript
支持,能自動推導出參數類型。 - 基於閉包實現,沒有煩人的
this
困擾。 - 為瀏覽器編寫但也支持其它
javascript
運行時,瀏覽器支持ie9+
(需要引入Map
的polyfill
)。 - 與框架無關,可以與任何框架搭配使用。
import mitt from 'mitt' const emitter = mitt() // 訂閱一個具體的事件 emitter.on('foo', e => console.log('foo', e) ) // 訂閱所有事件 emitter.on('*', (type, e) => console.log(type, e) ) // 發佈一個事件 emitter.emit('foo', { a: 'b' }) // 根據訂閱的函數來取消訂閱 function onFoo() {} emitter.on('foo', onFoo) // listen emitter.off('foo', onFoo) // unlisten // 只傳一個參數,取消訂閱同名事件 emitter.off('foo') // unlisten // 取消所有事件 emitter.all.clear()
而我們如果在Vue3 + TypeScript 環境中使用的話,就需要類型化事件的類型,已達到強類型的處理目的。
import mitt from "mitt"; type Events = { foo: string; bar: number; }; // 提供泛型參數讓 emitter 能自動推斷參數類型 const emitter = mitt<Events>(); // 'e' 被推斷為string類型 emitter.on("foo", (e) => { console.log(e); }); // ts error: 類型 string 的參數不能賦值給類型 'number' 的參數 emitter.emit("bar", "xx"); // ts error: otherEvent 不存在與 Events 的key中 emitter.on("otherEvent", () => { // });
在前端項目使用的時候,我們在utils/mitt.ts中定義預設導出的mitt對象,如下代碼所示。
// utils/mitt.ts import mitt, { Emitter } from 'mitt'; // 類型 const emitter: Emitter<MittType> = mitt<MittType>(); // 導出 export default emitter;
在其中的MittType類型,可以單獨文件放置TypeScript的預定義文件目錄中,如types/mitt.d.ts
而我們在使用的時候,直接導入該對象就可以了,如下代碼所示。
declare type MittType<T = any> = { openSetingsDrawer?: string; restoreDefault?: string; setSendColumnsChildren: T; .................. //省略其他事件類型 noticeRead: number; // 消息已讀事件 lastAddParentId?: string | number;//新增記住最後的父信息 };
例如我們定義一個更新和記住父菜單的Mitt 事件,在頁面載入完畢的時候監聽事件,在頁面退出的時候關閉事件即可,如下代碼所示是在菜單列表頁面中處理的。
<script lang="ts" setup name="sysMenu"> import { onMounted, onUnmounted, reactive, ref } from 'vue'; import mittBus from '/@/utils/mitt'; ...... onMounted(async () => { handleQuery(); mittBus.on('submitRefresh', () => { handleQuery(); }); mittBus.on('lastAddParentId', (pid) => { state.lastAddParentId = pid as string;//記住最後的父菜單ID }); }); onUnmounted(() => { mittBus.off('submitRefresh'); mittBus.off('lastAddParentId'); }); </script>
在新增菜單的時候我們觸發對應刷新事件 submitRefresh,以及觸發選擇的父記錄ID的事件 lastAddParentId,這樣就可以做相應的處理了。
例如在菜單的編輯子控制項頁面中,我們觸發對應的事件邏輯代碼如下所示。
// 關閉彈窗 const closeDialog = () => { mittBus.emit('submitRefresh'); state.isShowDialog = false; }; // 提交 const submit = () => { ruleFormRef.value.validate(async (valid: boolean) => { if (!valid) return; if (state.ruleForm.id != undefined && state.ruleForm.id > 0) { await menuApi.update(state.ruleForm); } else { await menuApi.add(state.ruleForm); //記住最後的菜單 mittBus.emit('lastAddParentId', state.ruleForm.pid); } closeDialog(); }); };
如果為了減少每次重覆的導入mitt,也可以把它全局掛載到變數中,統一入口進行訪問,詳細可以參考隨筆《在基於vue-next-admin的Vue3+TypeScript前端項目中,為了使用方便全局掛載的對象介面》處理即可。
const $u: $u_interface = { message, test, util, date, crypto, base64, $t: i18n.global.t, fun: commonFunction(), cloneDeep, debounce, throttle, mitt }; //安裝$u組件到app上 import type { App } from 'vue'; export default { install(app: App<Element>) { // 掛載全局 app.config.globalProperties.$u = $u; } };
專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。
轉載請註明出處:撰寫人:伍華聰 http://www.iqidi.com