js实现自定义事件

自定义事件类

从自定义事件的功能上分析,它应该拥有以下几个方法:

  1. 能够注册某个事件,并允许添加相应的方法
  2. 能够移除某个事件
  3. 能够触发某个事件
  4. 有一个队列或者映射来缓存当前已注册的事件

话不多说,先上代码

class Observer {
    constructor() {
        this.eventMap = {}
    }
    /**
     * 注册事件
     * @param {String} event 事件名称 
     * @param {Function}  fn 回调函数 
     */
    on(event, fn) {
        const map = this.eventMap
        if (!map[event]) {
            map[event] = []
        }
        map[event].push(fn)
    }
    /**
     * 触发事件
     */
    emit(event, ...args) {
        const map = this.eventMap
        if (map[event].length) {
            map[event].forEach(fn => {
                fn.apply(null, args)
            });
        } else {
            console.error('无待执行函数')
        }
    }
    /**
     * 移除事件
     */
    off(event, fn) {
        const map = this.eventMap
        const index = map[event]?.indexOf(fn)
        if (index > -1) {
            map[event].splice(index, 1)
        } else {
            console.error('目标函数不存在')
        }
    }
    /**
     * 注册只执行一次的事件
     */
    onOnce(event, fn) {
        const self = this
        function on() {
            fn.apply(null, arguments)// 先执行fn
            self.off(event, on)// 立刻移除fn
        }
        this.on(event, on)// 注册代理函数
    }
}

自身属性eventMap

Observer 实例化以后用一个eventMap对象保存所有事件,事件的值是一个数组,存储将要被执行的函数

// 例:
eventMap = {
	input:[FunctionA],
	change:[FunctionA,FunctionB]
}

on方法

用来注册事件

on(event, fn) {
        const map = this.eventMap
        if (!map[event]) {
            map[event] = []
        }
        map[event].push(fn)
 }

传入参数为:事件名称以及回调函数

  • 首先查看当前map中是否已注册该事件,
  • 没有注册就先初始化为一个空数组,随后把回调push进去。
  • 由于是数组结构,也就是说允许多次注册同一个事件,每次注册在数组中多放入一个回调
const o= new Observer()
o.on('change',()=>{console.log('我第一次注册')});
o.on('change',()=>{console.log('我又注册了一次')});

off方法

既然可以注册事件,就必然需要有移除事件的操作

off(event, fn) {
        const map = this.eventMap
        const index = map[event]?.indexOf(fn)
        if (index > -1) {
            map[event].splice(index, 1)
        } else {
            console.error('目标函数不存在')
        }
}

传入的参数为 事件名称以及上次的回调函数

  • 获取当前事件对应的函数数组,
  • 查找目标函数的索引位置,
  • 如果这个函数被找到了,就把他剔除出去。
  • 数组中其他函数不受影响。

emit方法

事件的触发很简单,只需要调用emit方法,传入事件名称就可以了。当然允许传入需要的若干个参数。

emit(event, ...args) {
        const map = this.eventMap
        if (map[event].length) {
            map[event].forEach(fn => {
                fn.apply(null, args)
            });
        } else {
            console.error('无待执行函数')
        }
    }
  • 首先查看目标事件是否存在,
  • 若数组不为空,就遍历调用其中的函数,
  • 并顺便把emit传入的参数传递过去

onOnce方法

如果我想事件只能执行一次,该如何处理呢?

onOnce(event, fn) {
        const self = this
        function on() {
            fn.apply(null, arguments)// 先执行fn
            self.off(event, on)// 立刻移除fn
        }
        this.on(event, on)// 注册代理函数
}

这就要求在事件注册的时候做一些处理,就是把回调函数替换成我们定义的on函数,它干了两件事情:

  • 先执行一下原本的fn
  • 执行之后立刻移除原事件,这样事件就只能执行一次。
const o= new Observer()
o.onOnce('change', (name, age) => {
    console.log(`我是${name},现在已经${age}岁了`)
})
o.emit('change', '熏悟空', 600)// 第一次会执行------->输出“我是熏悟空,现在已经600岁了”
o.emit('change', '居八戒', 400)// 第二次事件已经被移除,不会执行
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值