观察者模式,利用TypeScript简单重构Event
如果想给一个Box类的实例化对象添加事件侦听,正常来说,我们写一个Box类:
Box.ts
export default class Box extends EventTarget{
//给Box设置一个静态只读字符串类型的事件类型变量
static readonly EVENT_ID:string = "Box_event_id";
//给一个私有属性
private num:number = 2;
constructor() {
super();
}
dispatch():void{
var evt:Event = new Event(Box.EVENT_ID)
// evt.num = this.num; //如果evt是Event类型,会报错,因为Event没有num属性,
// 也就意味着在事件抛发的时候不能带一些数据出去
this.dispatchEvent(evt)
}
}
然后再Main.ts中导入,创建实例化对象b:
import Box from "./Box";
var b:Box = new Box()
// 让实例化对象侦听Box.EVENT_ID事件,并执行eventHandler回调函数
b.addEventListener(Box.EVENT_ID, eventHandler);
//Box实例化对象抛发事件
b.dispatch();
function eventHandler(e:Event):void{
console.log(e);
}
在执行页面后
<script src="require.js" data-main="./js/event/Main"></script>
会这样报错:

因为EventTarget是一个Dom对象,而ts不属于Dom,如果以上写在js里是没有问题的,但是在ts里是无法运行的,所以我们可以简单重构下Event,可以完成简单的事件抛发侦听就可以了
新建一个事件类EmitterEvent,新建一个事件目标类EmitterTarget
EmitterEvent.ts
export default class EmitterEvent{
//为了可以任意添加字符型属性
[key:string]:any;
//可以开放几个公有的事件属性,如target,currentTarget,为了简单就不加其他的属性了,而且必须只能是EmitterTarget类型因为只有EmitterTarget类型才能抛发和侦听事件
public target?:EmitterTarget;
public currentTarget?:EmitterTarget;
public type?:string;
//构造函数生成时将事件类型type带入,type是string类型
constructor(type:string) {
this.type = type;
}
EmitterTarget.ts
import EmitterEvent from "./EmitterEvent";
import IEventListener from "./IEventListener";
export default class EmitterTarget{
//由于是先侦听后抛发,所以我们可以将事件类型和handler都保存起来,当我们dispatch的时候就激活这个函数
//可以创建一个对象来保存
// private eventDic:object = {}; //不能使用object类型,是因为object不能增加属性,会报错
//为此我们新建一个接口IEventListener,让eventDic对应这个接口类型
private eventDic:IEventListener = {};
constructor() {
}
//提供事件抛发函数,public暴露
public dispatchEvent(evt:EmitterEvent):void{
//首先判断this.eventDic[evt.type as string]是否存在
if(!evt.type) return;
evt.currentTarget = this;
evt.target = this;
//console.log(evt)//EmitterEvent{type: "Box_event_id", num: 2}
//this.eventDic[(evt.type as string)](evt);//evt.type在之前定义可能为空,所以给它断言为string
//多个函数时,需要使用循环,
if(!this.eventDic[evt.type]) return;
for(var i = 0; i < this.eventDic[evt.type].length;i++){
this.eventDic[evt.type][i](evt);
}
}
//提供事件侦听函数,public暴露
public addEventListener(type:string, handler:Function):void{
//this.eventDic[type] = handler
//console.log(this.eventDic)//Box_event_id: ƒ eventHandler(e)
}
//提供删除事件函数,public暴露
public removeEventListener(type:string, handler:Function):void{
if(!this.eventDic[type]) return;
//数组长度为0,将数组释放掉,
this.eventDic[type].length = 0;
}
}
IEventListener.ts
export default interface IEventListener{
//[key:string]:any;
//函数的数组,为了可以一个事件绑定多个函数
[key:string]:Array<Function>;
}
Box.ts
import EmitterEvent from "./EmitterEvent";
import EmitterTarget from "./EmitterTarget";
//现在Box应该继承的就不该是EventTarget了,应该是我们自己写的EmitterTarget类
export default class Box extends EmitterTarget{
// export default class Box extends EventTarget{
//给Box设置一个静态只读字符串类型的事件类型变量
static readonly EVENT_ID:string = "Box_event_id";
//给一个私有属性
private num:number = 2;
constructor() {
super();
}
dispatch():void{
// var evt:Event = new Event(Box.EVENT_ID)
// evt.num = this.num; //如果evt是Event类型,会报错,因为Event没有num属性,也就意味着在事件抛发的时候不能带一些数据出去
var evt:EmitterEvent = new EmitterEvent(Box.EVENT_ID)
evt.num = this.num;
//this需要一个dispatchEvent()方法,那么就需要EmitterTarget提供一个
this.dispatchEvent(evt)
}
}
Main.ts
import Box from "./Box";
import EmitterEvent from "./EmitterEvent";
var b:Box = new Box()
// 让实例化对象侦听Box.EVENT_ID事件,并执行eventHandler回调函数
b.addEventListener(Box.EVENT_ID, eventHandler);
//侦听第二个
b.addEventListener(Box.EVENT_ID, eventHandler1);
//Box实例化对象抛发事件
b.dispatch();
//在这里e也应该为EmitterEvent类型
function eventHandler(e:EmitterEvent):void{
console.log(e);
}
//第二个事件函数
function eventHandler1(e:EmitterEvent):void{
console.log(e);
}
最后我们就完成了利用ts重构Event事件类;最后运行会得到事件对象


本文介绍如何使用TypeScript重构Event类,实现自定义事件抛发与侦听机制,通过创建EmitterEvent和EmitterTarget类,实现数据随事件传递及事件监听。
689

被折叠的 条评论
为什么被折叠?



