自定义事件类
从自定义事件的功能上分析,它应该拥有以下几个方法:
- 能够注册某个事件,并允许添加相应的方法
- 能够移除某个事件
- 能够触发某个事件
- 有一个队列或者映射来缓存当前已注册的事件
话不多说,先上代码
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)// 第二次事件已经被移除,不会执行