在vue3中简单实现事件监听与分发(EventBus)

vue3 中简单实现事件监听与分发

因为 vue3 不能通过 创建实例新建 事件总线,vue 3.0 移除了 o n , on, onoff 和 o n c e 方 法 , once 方法, onceemit 仍然是现有 API 的一部分,因为它用于触发由父组件以声明方式附加的事件处理程序
也可以使用 第三方库 比如 mitt,我这个只是简单处理事件

创建 eventBus.ts 文件用于处理事件
interface EventType {
    eventName: string
    params: any
    callbacks: Array<EventFnc>
}

interface EventFnc {
    (...args: any): void
}

export interface EventBusProps {
    $on (eventName: string, callback: EventFnc, immediate: boolean): void

    $emit (eventName: string, ...args: any): void

    $off (eventName?: string | Array<string>): void

    $once (eventName: string, callback: EventFnc): void
}

export default class EventBus implements EventBusProps {
    private _eventList: Array<EventType> = []

    // 重写toString方法
    private _toString = (callback: EventFnc): string => Object.toString.call(callback)

    /**
     * 监听
     * @param {string} eventName 需要监听的名字
     * @param {Function} callback 监听触发的回调
     * @param immediate 是否立即执行
     * */
    public $on (eventName: string, callback: EventFnc, immediate = false): void {
        const event: UndefinedAble<EventType> = this._findEvent(eventName)
        if (event) {
            // 不比较引用。通过方法字符串去对比callback
            const fnc: UndefinedAble<EventFnc> = event?.callbacks?.find((fnc: EventFnc) => this._toString(fnc) === this._toString(callback))
            if (!fnc) {
                // 如果没有事件,需要往list中加一个
                event.callbacks.push(callback)
                immediate && callback(...event.params)
            }
        } else {
            // 如果没有事件,需要往list中加一个
            this._addEvent(eventName, '', [callback])
        }
    }

    /**
     * 分发事件
     * @param {string} eventName 需要分发的监听的名字
     * @param { any } args 传递的参数
     * */
    // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
    public $emit (eventName: string, ...args: any): Promise<void | void[]> {
        const event: UndefinedAble<EventType> = this._findEvent(eventName)
        if (event) {
            event.params = args
            return Promise.all(event.callbacks?.map((fnc: EventFnc) => fnc(...event.params)))
        } else {
            // 如果没有事件,需要往list中加一个
            this._addEvent(eventName, args)
        }
        return Promise.resolve()
    }

    /**
     * 取消监听
     * @param {string | Array<string>} eventName 需要取消的监听名称
     * */
    public $off (eventName?: string | Array<string>): void {
        if (typeof eventName === 'string') {
            const index: number = this._eventList.findIndex((event: EventType) => event.eventName === eventName)
            if (index > -1) this._eventList.splice(index, 1)
        } else if (eventName instanceof Array) {
            eventName.map((m: string) => this.$off(m))
        } else {
            this._eventList = []
        }
    }

    /**
     * 执行一次的监听之后立即销毁
     * @param {string} eventName 需要监听的名字
     * @param {Function} callback 监听触发的回调
     * */
    public $once (eventName: string, callback: EventFnc): void {
        this.$emit(eventName, callback, true)
        this.$off(eventName)
    }

    private _findEvent (eventName: string): UndefinedAble<EventType> {
        return this._eventList.find((event: EventType) => event.eventName === eventName)
    }

    private _addEvent (eventName: string, params?: any, callbacks?: Array<EventFnc>): void {
        this._eventList.push({
            eventName,
            params: params ?? '',
            callbacks: callbacks ?? []
        })
    }
}
使用
  • 定义eventBus,分发事件
<template>
    <div class="a-content">
    </div>
</template>

<script lang='ts'>
import {defineComponent, provide} from 'vue'
import { EventBus } from '@utils'

export default defineComponent({
    name: 'a-content',
    setup() {
        const eventBus: EventBus = new EventBus()
        // 可以通过 provide 注入,子组件可以通过 这个 eventBus 监听或者分发
        provide('eventBus', eventBus)
        eventBus.$emit('test', '测试')
    }
})
</script>
  • 接收事件
<template>
    <div class="b-content">
    </div>
</template>

<script lang='ts'>
import {defineComponent, inject} from 'vue'
import { EventBus } from '@utils'

export default defineComponent({
    name: 'b-content',
    setup() {
        const eventBus: EventBus = <EventBus>inject('eventBus')
        eventBus.$on('test', (arg: any) => {
            console.log(arg)
        })

		// 注意:如果注册事件在监听事件之后。那么可以在监听的时候设置自动执行,增加第三个参数为true即可自动执行
		eventBus.$on('test', (arg: any) => {
            console.log(arg)
        }, true)
    }
})
</script>

这只是简单的使用,如果大佬们有啥别的好办法,欢迎指教~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值