Typescript重写事件
基础版本
Emitter.ts
//类似于事件的Event
import EmitterTarget from "./EmitterTarget.js";
export default class Emitter{
public type:string;
public target:EmitterTarget|null=null;
[key:string]:any;
//暴露属性
constructor(type:string){
this.type=type;
//把new Emitter("xxx")存入type属性中
}
}
EmitterTarget.js
import Emitter from "./Emitter.js";
export interface IHandler{
(e:Emitter):void
}
export interface IHandlerList{
[key:string]:Array<IHandler|null>;
}
//定义两个接口
export default class EmitterTarget{
private handlerList:IHandlerList={}
//把传入的回调函数以type为key 回调函数名为value放入对象中
constructor(){
}
//监听方法
public addEventListener(type:string,handler:IHandler):void
{
if(!this.handlerList[type])this.handlerList[type]=[];
//如果传入的监听的事件名没有的时 给对象中增加一个空数据放置回调函数
if(this.handlerList[type].includes(handler)) return;
//如果以该事件名的数组中有这个同样的回调函数跳出
this.handlerList[type].push(handler);
//如果都没有 把回调函数push到数组中
// console.log(this.handlerList);
}
//移除方法
public removeEventListener(type:string,handler:IHandler):void
{
if(!this.handlerList[type] || !this.handlerList[type].includes(handler)) return;
//如果handlerList对象中没有这个事件,或者这个事件中没有这个回调函数跳出
var index=this.handlerList[type].indexOf(handler);
//找到对应索引
this.handlerList[type][index]=null;
//赋值为null 注意点数组塌陷问题。之后可以有优化
}
//主动抛发方法
public dispatchEvent(evt:Emitter):void
{
// console.log(evt.type);
if(!this.handlerList[evt.type]) return;
//如果没有这个事件名跳出
var arr:Array<IHandler|null>=this.handlerList[evt.type];
for(var i=0;i<arr.length;i++){
var fn:IHandler|null=arr[i];
if(fn) fn.call(this,evt);
//改变this指向
}
for(var j=0;j<arr.length;j++){
if(!arr[j]){
arr.splice(j,1);
j--;
//删除对应的事件 并且-- 如果不会数组塌陷
}
}
}
}
测试代码
import Emitter from "./Emitter.js";
import EmitterTarget from "./EmitterTarget.js";
var target:EmitterTarget=new EmitterTarget();
target.addEventListener("a",aHandler);
target.addEventListener("a",aHandler1);
target.addEventListener("a",aHandler1);
target.addEventListener("a",aHandler2);
target.addEventListener("b",aHandler3);
target.addEventListener("b",aHandler1);
var evt:Emitter=new Emitter("a");
evt.a=1;
target.dispatchEvent(evt);
var evt:Emitter=new Emitter("a");
target.dispatchEvent(evt);
function aHandler(e:Emitter):void
{
// console.log(e.target)
console.log(e,"handler")
}
// ts中使用this时,参数需要在第一个参数前面增加this:void指出this的类型
// 如果要调用这个this的方法时,那么this必须设置为这个函数中的this类型
function aHandler1(this:EmitterTarget,e:Emitter){
console.log(e,"handler1",this);
this.removeEventListener("a",aHandler1);
}
function aHandler2(e:Emitter){
console.log(e,"handler2")
}
function aHandler3(this:EmitterTarget,e:Emitter){
console.log(e,"handler3",this)
}
优化版本
Emitter.ts
与上文一样
EmitterTarget.js
大体逻辑同上
import Emitter from "./Emitter.js";
export interface IHandler{
(e:Emitter):void
}
export default class EmitterTarget{
//考虑到Map结构松散不会有数组塌陷问题,且Set不会重复添加,使用到Map Set组合
private handlerList:Map<string,Set<IHandler>>=new Map();
constructor(){
}
public addEventListener(type:string,handler:IHandler):void
{
if(!this.handlerList.has(type)) this.handlerList.set(type,new Set<IHandler>());
this.handlerList.get(type)?.add(handler);
}
public removeEventListener(type:string,handler:IHandler):void
{
if(!this.handlerList.has(type)) return;
this.handlerList.get(type)?.delete(handler);
}
public dispatchEvent(evt:Emitter):void
{
if(!this.handlerList.has(evt.type)) return;
evt.target=this;
this.handlerList.get(evt.type)?.forEach((item:IHandler)=>{
item.call(this,evt);
})
}
}