周末总得学点什么吧~
奥利给!
设计模式: 事件订阅派发模式
简单说就是:事件调度中心,负责接收事件发布者的消息,并将这些消息分发给所有订阅了该事件的订阅者
为什么用它,在构建大型、复杂或交互性强的应用程序时,用该模式非常方便,解耦以及提高灵活性方便管理等,下方举例:js 事件分发的使用和扩充
事件分发管理
- 事件分发基础管理
最基本的事件分发管理,下方有扩充
class EventDispatcher {
static events: { [key: string]: any[] } = {};
// 绑定事件
static on(eventName: string, callback: Function) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
// 移除事件
static off(eventName: string, callback: Function) {
if (this.events[eventName]) {
const index = this.events[eventName].indexOf(callback);
if (index !== -1) {
this.events[eventName].splice(index, 1);
}
}
}
// 触发事件
static emit(eventName: string, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach((callback) => {
callback(...args);
});
}
}
}
// 绑定事件处理函数
EventDispatcher.on("customEvent", (message) => {
console.log("Received custom event:", message);
});
// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");
如果涉及到target this的指向的话,可以通过apply来操作target指向
- 加入target指向
class EventDispatcher {
static readonly events: { [key: string]: any[] } = {};
/**
* 绑定事件
* @param {string} eventName 监听事件
* @param {function} callback 监听函数
* @param {object} target 监听目标
*/
static on(eventName: string, callback: Function,target: any) {
const objHandler: {} = {callback: callback, target: target};
let handlerList: Array<any> = this.events[eventName];
if (!handlerList) {
handlerList = [];
this.events[eventName] = handlerList;
}
handlerList.push(objHandler);
}
// 移除事件
static off(eventName: string, callback: Function,target: any) {
const list = this.events[eventName];
if (list) {
for (let i = 0; i < list.length; i++) {
const oldObj = list[i];
if (oldObj.callback === callback && (!target || target === oldObj.target)) {
list.splice(i, 1);
break;
}
}
}
}
// 触发事件
static emit(eventName: string, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach((objHandler) => {
if (objHandler.callback) {
objHandler.callback.apply(objHandler.target, args);
}
});
}
}
/**
* 销毁全部事件分发
*/
static destroyAll():void{
//销毁方法1
for (const eventName in this.events) {
if (this.events.hasOwnProperty(eventName)) {
this.events[eventName].length = 0;
delete this.events[eventName];
}
}
//销毁方法2 这个比较暴力
// (this.events as any) = {};
}
}
// 绑定事件处理函数
EventDispatcher.on("customEvent", (message) => {
console.log("Received custom event:", message);
},this);
// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");
有没有发现当使用了off
移除时间并没有删除
因为用的是钩子函数判断不匹配也就删除不了,下方解决:
除了上面target this指向还可以扩展更高级的处理如优先级,一次性事件和阻止事件冒泡等功能
- 添加优先级处理
多加入一个sort进行排序
class EventDispatcher {
static readonly events: { [key: string]: any[] } = {};
/**
* 绑定事件
* @param {string} eventName 监听事件
* @param {function} callback 监听函数
* @param {object} target 监听目标
* @param {number} priority 事件处理优先级
*/
static on(
eventName: string,
callback: Function,
target: any,
priority: number = 0
) {
const objHandler: {} = { callback, target, priority };
let handlerList: Array<any> = this.events[eventName];
if (!handlerList) {
handlerList = [];
this.events[eventName] = handlerList;
}
handlerList.push(objHandler);
handlerList.sort((a, b) => b.priority - a.priority); // 按优先级降序排序
}
// 移除事件
static off(eventName: string, callback: Function, target: any) {
const list = this.events[eventName];
if (list) {
for (let i = 0; i < list.length; i++) {
const oldObj = list[i];
if (
oldObj.callback === callback &&
(!target || target === oldObj.target)
) {
list.splice(i, 1);
break;
}
}
}
}
// 触发事件
static emit(eventName: string, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach((objHandler) => {
if (objHandler.callback) {
objHandler.callback.apply(objHandler.target, args);
}
});
}
}
/**
* 销毁全部事件分发
*/
static destroyAll(): void {
//销毁方法1
for (const eventName in this.events) {
if (this.events.hasOwnProperty(eventName)) {
this.events[eventName].length = 0;
delete this.events[eventName];
}
}
//销毁方法2 这个比较暴力
// (this.events as any) = {};
}
}
function customEventHandle1(message) {
console.log("这个优先级设置是0,所以优先级靠后:", message);
}
function customEventHandle2(message) {
console.log("这个优先级设置是1,所以优先级靠前:", message);
}
// 绑定事件处理函数
EventDispatcher.on("customEvent", customEventHandle1, this, 0);
EventDispatcher.on("customEvent", customEventHandle2, this, 1);
// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");
- 添加一次性事件
处理原理就是在on
绑定事件中添加参数once
,在emit
触发事件并移除一次性事件处理函数
class EventDispatcher {
static readonly events: { [key: string]: any[] } = {};
/**
* 绑定事件
* @param {string} eventName 监听事件
* @param {function} callback 监听函数
* @param {object} target 监听目标
* @param {number} priority 事件处理优先级
* @param {boolean} once 一次性事件
*/
static on(
eventName: string,
callback: Function,
target: any,
priority: number = 0,
once: boolean = false
) {
const objHandler: {} = { callback, target, priority, once };
let handlerList: Array<any> = this.events[eventName];
if (!handlerList) {
handlerList = [];
this.events[eventName] = handlerList;
}
handlerList.push(objHandler);
handlerList.sort((a, b) => b.priority - a.priority); // 按优先级降序排序
}
// 移除事件
static off(eventName: string, callback: Function, target: any) {
const list = this.events[eventName];
if (list) {
for (let i = 0; i < list.length; i++) {
const oldObj = list[i];
if (
oldObj.callback === callback &&
(!target || target === oldObj.target)
) {
list.splice(i, 1);
break;
}
}
}
}
// 触发事件
static emit(eventName: string, ...args) {
if (this.events[eventName]) {
// 触发事件并移除一次性事件处理函数
this.events[eventName] = this.events[eventName].filter((item) => {
item.callback(...args);
return !item.once;
});
}
}
/**
* 销毁全部事件分发
*/
static destroyAll(): void {
//销毁方法1
for (const eventName in this.events) {
if (this.events.hasOwnProperty(eventName)) {
this.events[eventName].length = 0;
delete this.events[eventName];
}
}
//销毁方法2 这个比较暴力
// (this.events as any) = {};
}
}
function customEventHandle1(message) {
console.log("这个优先级设置是0,所以优先级靠后:", message);
}
function customEventHandle2(message) {
console.log("这个优先级设置是1,所以优先级靠前:", message);
}
// 绑定事件处理函数
EventDispatcher.on("customEvent", customEventHandle1, this, 0, true);
EventDispatcher.on("customEvent", customEventHandle2, this, 1, false);
// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");
// 再次触发事件,一次性事件处理函数将不会被调用 customEventHandle1
EventDispatcher.emit("customEvent", "Hello again!");
- 添加阻止事件冒泡
class EventDispatcher {
static readonly events: { [key: string]: any[] } = {};
/**
* 绑定事件
* @param {string} eventName 监听事件
* @param {function} callback 监听函数
* @param {object} target 监听目标
* @param {number} priority 事件处理优先级
* @param {boolean} once 一次性事件
* @param {boolean} stopped 阻止事件冒泡
*/
static on(
eventName: string,
callback: Function,
target: any,
priority: number = 0,
once: boolean = false,
stopped: boolean = false
) {
const objHandler: {} = { callback, target, priority, once, stopped };
let handlerList: Array<any> = this.events[eventName];
if (!handlerList) {
handlerList = [];
this.events[eventName] = handlerList;
}
handlerList.push(objHandler);
handlerList.sort((a, b) => b.priority - a.priority); // 按优先级降序排序
}
// 移除事件
static off(eventName: string, callback: Function, target: any) {
const list = this.events[eventName];
if (list) {
for (let i = 0; i < list.length; i++) {
const oldObj = list[i];
if (
oldObj.callback === callback &&
(!target || target === oldObj.target)
) {
list.splice(i, 1);
break;
}
}
}
}
// 触发事件
static emit(eventName: string, ...args) {
if (this.events[eventName]) {
let stopFlag: boolean = false;
// 触发事件并移除一次性事件处理函数
this.events[eventName] = this.events[eventName].filter((item) => {
if (stopFlag) {
return true;
}
item.callback(...args);
if (item.stopped) {
stopFlag = true;
}
return !item.once;
});
}
}
/**
* 销毁全部事件分发
*/
static destroyAll(): void {
//销毁方法1
for (const eventName in this.events) {
if (this.events.hasOwnProperty(eventName)) {
this.events[eventName].length = 0;
delete this.events[eventName];
}
}
//销毁方法2 这个比较暴力
// (this.events as any) = {};
}
}
function buttonEventHandle1(message) {
console.log("这个优先级设置是0,所以优先级靠后:", message);
}
function buttonEventHandle2(message) {
console.log("这个优先级设置是1,所以优先级靠前:", message);
}
// 绑定事件处理函数
EventDispatcher.on("buttonEvent", buttonEventHandle1, this, 0, false, false); // stopped false不阻止
EventDispatcher.on("buttonEvent", buttonEventHandle2, this, 1, false, true); // stopped true阻止事件冒泡 因为这里设置了所以后面的buttonEventHandle1方法将不会调用
const testArgs = { message: "Hello, World!" };
// 触发事件
EventDispatcher.emit("buttonEvent", testArgs);