小满老师课程观看的随笔~
前言:什么是发布订阅模式?
- 比如
原生js
中的addEventListener
、removeEventListener
- 比如 vue 中的
EventBus(全局事件总线)
($emit、$on) - 即
收集
一些事件后,统一处理
- 发布者 $emit,订阅者 $on,再加一个调度者(调度中心)
实战编写
- type/index.js 存放 类型约束
// 存放事件的容器约束,key是事件名,value是对应的事件列表
export interface List {
[key: string]: Array<Function>
}
// 类的约束
export interface DispatchClass {
on: (name: string, fn: Function) => void
emit: (name: string, ...args: Array<any>) => void
off: (name: string, fn: Function) => void
once: (name: string, fn: Function) => void
}
- index.ts 存放主要逻辑
import { DispatchClass, List } from './type/index'
// 调度中心
class Dispatch implements DispatchClass {
// 存放事件的容器
list: List
constructor () {
this.list = {}
}
// 注册事件
on (name: string, fn: Function) {
// 把传入的事件放入对应名称的事件数组中
let callbacks = this.list[name] || []
callbacks.push(fn)
this.list[name] = callbacks
}
// 调用事件
emit (name: string, ...args: Array<any>) {
const callbacks = this.list[name]
if (callbacks && callbacks.length) {
// 找到名称对应的事件数组,将数组中事件全部调用
callbacks.forEach(fns => {
fns.apply(this, args)
})
} else {
console.log('无可调用的事件,名称错误')
}
}
// 解绑事件
off (name: string, fn: Function) {
// 找到对应名称下的事件数组,删除指定的事件函数
const callbacks = this.list[name]
if (callbacks && fn) {
const index = callbacks.findIndex(fns => fns === fn)
if (index > -1) {
callbacks.splice(index, 1)
}
} else {
console.log('该事件未监听')
}
}
// 注册一个仅执行一次的事件:执行结束后立刻解绑(仅注册,还是需要 emit 执行)
once (name: string, fn: Function) {
// 创建一个临时函数用于绑定,在临时函数内部执行完 fn 之后即刻解绑
const temFn = (...args: Array<any>) => {
fn.apply(this, args)
this.off(name, temFn)
}
this.on(name, temFn)
}
}
// 使用:
const o = new Dispatch()
const callback1 = (...args: any) => {
console.log('1111--callback', args)
}
const callback2 = (...args: any) => {
console.log('2222--callback', args)
}
const callback3 = (...args: any) => {
console.log('3333--callback', args)
}
// 注册了两个回调函数 给 test
o.on('test', callback1)
o.on('test', callback2)
// 这里调用后,就会执行两个函数
o.emit('test', 123, false, { name: 'blue' })
// 这里先解绑一个事件
o.off('test', callback1)
// 这里再调用就只会执行一个了(callback2)
o.emit('test', 456, true, { name: 'blue' })
// 注册一个仅执行一次的事件
o.once('test2', callback3)
// 调用这个事件
o.emit('test2', 789, false)
// 第二次调用,找不到了,无法调用
o.emit('test2','once第二次调用')