由于once不常用,所以写的逻辑比较多;并且要表达的意思是多次emit,只有第一次emit会触发once的回调,如果官方once不是这个意思或者代码可优化请指出,学习中~
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
class ZJBus {
constructor() {
this.eventBus = {}
this.onceFns = {} // 只执行一次的fn们
}
on(eventName, eventFn, thisArg) {
let handlers = this.eventBus[eventName]
if (!handlers) {
handlers = []
this.eventBus[eventName] = handlers
}
handlers.push({
eventFn,
thisArg
})
}
once(eventName, eventFn) {
this.on(eventName, eventFn)
let handlers = this.onceFns[eventName]
if (!handlers) {
handlers = []
this.onceFns[eventName] = handlers
}
handlers.push(eventFn)
}
emit(eventName, ...args) {
const handlers = this.eventBus[eventName]
if (!handlers) return
for (let handler of handlers) {
const {eventFn, thisArg} = handler
eventFn.apply(thisArg ?? this, args)
}
// 对once的相关处理
const needUnloadFns = this.onceFns[eventName]
if (needUnloadFns) {
const originHandlers = this.eventBus[eventName]
this.eventBus[eventName] = originHandlers.filter(({eventFn}) => {
return !needUnloadFns.includes(eventFn)
})
this.onceFns[eventName] = undefined
}
}
off(eventName, eventFn) {
const handlers = this.eventBus[eventName]
if (!handlers) return
for (let i = 0; i < handlers.length; i++) {
const {eventFn: currentFn} = handlers[i]
if (currentFn === eventFn) {
this.eventBus[eventName].splice(i, 1)
}
}
}
}
const eventBus = new ZJBus()
const onceFn = () => {
console.log("你好2")
}
eventBus.on("hello", () => {
console.log("你好")
})
eventBus.once("hello", onceFn)
eventBus.emit("hello")
eventBus.emit("hello")
eventBus.emit("hello")
</script>
</body>
</html>