分享好友 前端技术首页 频道列表

Vue3.0组件通信mitt源码ts实例解析

vue  2023-02-08 17:460

背景介绍

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

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

Vue3.0组件通信mitt源码ts实例解析

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

使用方法

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

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

业务逻辑组件中通信使用

// 组件 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'
// 监听
onMounted(()=>{ mitt.on('search-change',(obj)=> { do sth} })
// off 监听 
onUnmounted(()=>{ mitt.off('search-change', ()=> { do sth } })
</script>

源码分析

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

export type EventType = string | symbol;
// 源码第一段分析
export 一个类型别名 EventType,上面例子中我们mitter.emit('search-change', obj); 
search-change就是一个string类型,
同时EventType也可以是联合类型symbol,为了保证事件的唯一性
export type Handler<T = unknown> = (event: T) => void;
export type WildcardHandler<T = Record<string, unknown>> = (
    type: keyof T,
    event: T[keyof T]
) => void;
// 源码第二段分析
使用类型别名定义函数Handler,Handler接受一个泛型参数<T>,默认值是unknown
export type EventHandlerList<T = unknown> = Array<Handler<T>>;
export type WildCardEventHandlerList<T = Record<string, unknown>>
= Array<WildcardHandler<T>>;
// 源码第三段分析
当前所有注册的事件列表类型定义  Array<T>数组的泛型定义
export type EventHandlerMap<Events extends Record<EventType, unknown>>
= Map<keyof Events | '*',EventHandlerList<Events[keyof Events]> 
| WildCardEventHandlerList<Events>>;
// 源码第四段分析
这里是事件类型及其对应的事件处理程序的映射Map做了定义,使用extend继承一个Record对象,
该对象的两个参数一个是限制为Events上已知的公共属性名的联合或者*, 
另外一个参数要是是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定义了具体函数的结构类型
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<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!);
                });
             }
        }
    };
}

核心代码主要实现就是:

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(对象最好,传多个参数只会取到第一个)

以上就是Vue3.0组件通信mitt源码ts实例解析的详细内容,更多关于Vue3.0组件通信mitt ts的资料请关注其它相关文章!

原文地址:https://juejin.cn/post/7168832978921979940

查看更多关于【vue】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
vue3+TS 自定义指令:长按触发绑定的函数
vue3+TS 自定义指令:长按触发绑定的函数而然间看到一个在vue2中写的长按触发事件的自定义指定,想着能不能把他copy到我的vue3项目中呢。编写自定义指令时遇到的几个难点1.自定义指令的类型在ts中写任何东西都要考虑到类型的问题,自定义指令的类型问题依然存

0评论2023-03-08326

Vue3 企业级优雅实战 - 组件库框架 - 9 实现组件库 cli - 上
上文搭建了组件库 cli 的基础架子,实现了创建组件时的用户交互,但遗留了 cli/src/command/create-component.ts 中的 createNewComponent 函数,该函数要实现的功能就是上文开篇提到的 —— 创建一个组件的完整步骤。本文咱们就依次实现那些步骤。(友情提示

0评论2023-03-08947

Vue3+TypeScript 项目中,配置 ESLint 和 Prettier
接上篇:从0搭建vite-vue3-ts项目框架:配置less+svg+pinia+vant+axios文档同步项目gitee:https://gitee.com/lixin_ajax/vue3-vite-ts-pinia-vant-less.git 一、Eslint:用于检测代码安装eslint相关依赖yarn add eslint eslint-plugin-vue @typescript-esli

0评论2023-03-08825

vue3项目目录结构示例详解 vue3.0目录结构
目录一、vue3项目的目录结构详解二、部分主要文件详解1、index.html2、main.js(main.ts)3. package.json三、其他说明1. node版本错误2. 如何调用全局属性3. vue文件中应用vue3.0的api总结一、vue3项目的目录结构详解node_modules:通过 npm install 下载安

0评论2023-03-08703

一文秒懂Vue3的v-model vue3 vite2
目录1:什么是 v-model2:v-model 的扩展1:自定义名称2:内置修饰符3:自定义修饰符总结1:什么是 v-modelv-model 是 Vue 内置的指令作为属性接收一个变量(不能是常量)绑定到普通组件和自定义组件中// 作为普通组件的属性, 只有作为表单内的元素属性时才会

0评论2023-03-08408

vue3.0 动态css变量的使用
setup中定义变量以及在style中的使用(有单位的需要calc 计算)setup() {const rotate = refnumber(0);const color: string = "red";const changeStatus = (): void = {rotate.value = -90;};return {rotate,color,};},style.test { color: v-bind(color); tran

0评论2023-03-08539

vue3 | isRef、unref、toRef、toRefs
isRef检查某个值是否是ref。是返回true,否则返回false。const num = ref(10);const num1 = 20;const num2 = reactive({ data: 30 });console.log(isRef(num)); //trueconsole.log(isRef(num1)); //falseconsole.log(isRef(num2)); //falseunref()如果参数是r

0评论2023-03-08836

更多推荐