手写实现简单的Vue事件总线

Posted 小小白学计算机

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写实现简单的Vue事件总线相关的知识,希望对你有一定的参考价值。

一、什么是事件总线

自定义事件总线属于一种观察者模式,其中包括三个角色:

  • 发布者(Publisher):发出事件(Event);
  • 订阅者(Subscriber):订阅事件(Event),并且会进行响应(Handler);
  • 事件总线(EventBus):无论是发布者还是订阅者都是通过事件总线作为中台的;

当然我们可以选择一些第三方的库:

  • Vue2默认是带有事件总线的功能;
  • Vue3中推荐一些第三方库,比如mitt;

二、手写实现事件总线

当然我们也可以实现自己的事件总线:

  • 事件的监听方法on:存储对应事件名需要执行的事件函数
  • 事件的发射方法emit:执行对应事件名需要执行的事件函数
  • 事件的取消监听off:删除对应事件名需要执行的事件函数

    运行结果:
// eventBus对象:
// 
//     abc: [
//         需要监听的函数, 为需要监听的事件函数绑定的this,
//         需要监听的函数, 为需要监听的事件函数绑定的this
//     ]
// 
class EventBus 
    constructor() 
        this.eventBus = 
    
    /*
    * on函数:
    * 被调用时,需要把eventCallback和thisArg放到一个对象中,然后把这个对象push到一个数组里,
    * 然后把eventName作为key,把这个数组作为value存到eventBus对象中
    * eventName:需要监听的事件名称
    * eventCallback:需要监听的事件函数
    * thisArg:为需要监听的事件函数绑定this
    */
    on(eventName, eventCallback, thisArg) 
        let handlers = this.eventBus[eventName]
        if (!handlers) 
            // 如果在eventBus对象中找不到key为eventName的handlers,
            // 则创建一个handlers空数组,并放到eventBus对象中
            handlers = []
            this.eventBus[eventName] = handlers
        
        // 如果handlers存在,则把需要监听的eventCallback函数、函数需要绑定的this
        // 以对象的形式存到handlers中
        handlers.push(
            eventCallback,
            thisArg
        )
    
    /*
    * emit函数:
    * 一旦被调用,则需要执行eventBus对象中key为eventName所对应的的数组中
    * 的每个对象中的eventCallback函数
    */
    emit(eventName, ...payload) 
        // 获取eventBus对象中key为eventName所对应的的数组
        const handlers = this.eventBus[eventName]
        if (!handlers) return
        // 如果数组存在则遍历数组,调用需要执行的事件函数
        handlers.forEach(handler => 
            handler.eventCallback.apply(handler.thisArg, payload)
        )
    
    /*
    * off函数:
    * 被调用时,删除eventBus中key为eventName,
    * value为一个handler对象,且该对象中的eventCallback属性与off函数第二个参数相等的这个value对象
    */
    off(eventName, eventCallback) 
        // 获取eventBus对象中key为eventName所对应的的数组
        const handlers = this.eventBus[eventName]
        if (!handlers) return
        // 复制handlers,然后使用newHandlers新数组来进行遍历,确保遍历的数组是始终保持不变的
        // 防止出现后续删除某个handlers数组中的对象后,在进行遍历时出现问题
        const newHandlers = [...handlers]
        // 遍历newHandlers
        for (let i = 0; i < newHandlers.length; i++) 
            // 获取newHandlers中的每个handler
            const handler = newHandlers[i]
            // 如果handler的eventCallback 等于 参数中传进来的eventCallback,
            // 则获取到这个handler对象在handlers数组中的下标,然后删除这个handler对象
            if (handler.eventCallback === eventCallback) 
                const index = handlers.indexOf(handler)
                handlers.splice(index, 1)
            
        
    



// 以下为测试代码:
const eventBus = new EventBus()

// main.js文件
eventBus.on('abc', function (payload) 
    console.log('监听abc事件', this, payload)
, name: 'zep')

const handleCallback = function (payload) 
    console.log('监听abc事件', this, payload)

eventBus.on('abc', handleCallback, name: 'lala')

// utils.js文件
eventBus.emit('abc', 123)

eventBus.off('abc', handleCallback)
eventBus.emit('abc', 123)

以上是关于手写实现简单的Vue事件总线的主要内容,如果未能解决你的问题,请参考以下文章

手写eventBus事件总线

Vue 快速入门系列Vue数据实现本地存储自定义事件绑定全局事件总线$nextTick的使用

非父子组件间通信

Vue中的Bus(总线)实现非父子组件通信

Vue开发中的中央事件总线

Vue2 EventBus事件总线 | 实现组件间的通信&改变大屏背景颜色实践