TypeScript是否支持类的事件?
我只是想知道,如果在TypeScript中,你可以在你的类或接口定义自定义事件?
这是什么样子?
这个简单的事件如何被用作财产? 更强大的拥有类的打字和没有inheritance要求:
interface ILiteEvent<T> { on(handler: { (data?: T): void }) : void; off(handler: { (data?: T): void }) : void; } class LiteEvent<T> implements ILiteEvent<T> { private handlers: { (data?: T): void; }[] = []; public on(handler: { (data?: T): void }) : void { this.handlers.push(handler); } public off(handler: { (data?: T): void }) : void { this.handlers = this.handlers.filter(h => h !== handler); } public trigger(data?: T) { this.handlers.slice(0).forEach(h => h(data)); } public expose() : ILiteEvent<T> { return this; } }
像这样使用:
class Security{ private readonly onLogin = new LiteEvent<string>(); private readonly onLogout = new LiteEvent<void>(); public get LoggedIn() { return this.onLogin.expose(); } public get LoggedOut() { return this.onLogout.expose(); } // ... onLogin.trigger('bob'); } function Init() { var security = new Security(); var loggedOut = () => { /* ... */ } security.LoggedIn.on((username?) => { /* ... */ }); security.LoggedOut.on(loggedOut); // ... security.LoggedOut.off(loggedOut); }
改进?
这是一个要点
我想你是问一个类实例是否可以像DOM元素一样实现addEventListener()和dispatchEvent()。 如果这个类不是一个DOM节点,那么你将不得不编写你自己的事件总线。 您可以为可以发布事件的类定义接口,然后在类中实现接口。 这是一个天真的例子。
interface IEventDispatcher{ // maintain a list of listeners addEventListener(theEvent:string, theHandler:any); // remove a listener removeEventListener(theEvent:string, theHandler:any); // remove all listeners removeAllListeners(theEvent:string); // dispatch event to all listeners dispatchAll(theEvent:string); // send event to a handler dispatchEvent(theEvent:string, theHandler:any); } class EventDispatcher implement IEventDispatcher { private _eventHandlers = {}; // maintain a list of listeners public addEventListener(theEvent:string, theHandler:any) { this._eventHandlers[theEvent] = this._eventHandlers[theEvent] || []; this._eventHandlers[theEvent].push(theHandler); } // remove a listener removeEventListener(theEvent:string, theHandler:any) { // TODO } // remove all listeners removeAllListeners(theEvent:string) { // TODO } // dispatch event to all listeners dispatchAll(theEvent:string) { var theHandlers = this._eventHandlers[theEvent]; if(theHandlers) { for(var i = 0; i < theHandlers.length; i += 1) { dispatchEvent(theEvent, theHandlers[i]); } } } // send event to a handler dispatchEvent(theEvent:string, theHandler:any) { theHandler(theEvent); } }
TypeScript项目的强types事件 (版本0.3 )实现了3种types的事件: IEvent<TSender, TArgs>
, ISimpleEvent<TArgs>
和ISignal
。 这使得您的项目使用正确的事件更容易。 它也隐藏了你的事件的调度方法,好的信息隐藏应该做的。
事件types/接口 – 事件的定义:
interface IEventHandler<TSender, TArgs> { (sender: TSender, args: TArgs): void } interface ISimpleEventHandler<TArgs> { (args: TArgs): void } interface ISignalHandler { (): void; }
示例 – 此示例显示如何使用滴答时钟实现3种types的事件:
class Clock { //implement events as private dispatchers: private _onTick = new SignalDispatcher(); private _onSequenceTick = new SimpleEventDispatcher<number>(); private _onClockTick = new EventDispatcher<Clock, number>(); private _ticks: number = 0; constructor(public name: string, timeout: number) { window.setInterval( () => { this.Tick(); }, timeout); } private Tick(): void { this._ticks += 1; //trigger event by calling the dispatch method and provide data this._onTick.dispatch(); this._onSequenceTick.dispatch(this._ticks); this._onClockTick.dispatch(this, this._ticks); } //expose the events through the interfaces - use the asEvent //method to prevent exposure of the dispatch method: public get onTick(): ISignal { return this._onTick.asEvent(); } public get onSequenceTick() : ISimpleEvent<number>{ return this._onSequenceTick.asEvent(); } public get onClockTick(): IEvent<Clock, number> { return this._onClockTick.asEvent(); } }
用法 – 可以这样使用:
let clock = new Clock('Smu', 1000); //log the ticks to the console clock.onTick.subscribe(()=> console.log('Tick!')); //log the sequence parameter to the console clock.onSequenceTick.subscribe((s) => console.log(`Sequence: ${s}`)); //log the name of the clock and the tick argument to the console clock.onClockTick.subscribe((c, n) => console.log(`${c.name} ticked ${n} times.`))
在这里阅读更多: 在事件,调度和列表(系统的一般解释)
教程
我已经写了一些关于这个主题的教程:
- TypeScript中的强types事件处理程序(第1部分)
- 在带有接口的TypeScript中使用强types事件(第2部分)
- 使用事件列表在TypeScript中强types化事件(第3部分)
- 将命名事件添加到您的类(第4部分)
- 0.2.0简单的事件支持
- 0.3.0信号支持
您可以在TypeScript中使用自定义事件。 我不确定你想要做什么,但是这里是一个例子:
module Example { export class ClassWithEvents { public div: HTMLElement; constructor (id: string) { this.div = document.getElementById(id); // Create the event var evt = document.createEvent('Event'); evt.initEvent('customevent', true, true); // Create a listener for the event var listener = function (e: Event) { var element = <HTMLElement> e.target; element.innerHTML = 'hello'; } // Attach the listener to the event this.div.addEventListener('customevent', listener); // Trigger the event this.div.dispatchEvent(evt); } } }
如果你正在寻找更具体的东西,请让我知道。
该解决scheme允许您直接在函数调用中编写参数,而不需要将所有参数包含在对象中。
interface ISubscription { (...args: any[]): void; } class PubSub<T extends ISubscription> { protected _subscribed : ISubscriptionItem[] = []; protected findSubscription(event : T) : ISubscriptionItem { this._subscribed.forEach( (item : ISubscriptionItem) =>{ if (item.func==event) return item; } ); return null; } public sub(applyObject : any,event : T) { var newItem = this.findSubscription(event); if (!newItem) { newItem = {object : applyObject, func : event }; this._subscribed.push(newItem); this.doChangedEvent(); } } public unsub(event : T) { for ( var i=this._subscribed.length-1 ; i>=0; i--) { if (this._subscribed[i].func==event) this._subscribed.splice(i,1); } this.doChangedEvent(); } protected doPub(...args: any[]) { this._subscribed.forEach((item : ISubscriptionItem)=> { item.func.apply(item.object, args); }) } public get pub() : T { var pubsub=this; var func= (...args: any[]) => { pubsub.doPub(args); } return <T>func; } public get pubAsync() : T { var pubsub=this; var func = (...args: any[]) => { setTimeout( () => { pubsub.doPub(args); }); } return <T>func; } public get count() : number { return this._subscribed.length } }
用法:
interface ITestEvent { (test : string): void; } var onTestEvent = new PubSub<ITestEvent>(); //subscribe to the event onTestEvent.sub(monitor,(test : string) => {alert("called:"+test)}); //call the event onTestEvent.pub("test1");
如果您正在寻找使用标准发射器模式进行智能types检查,现在可以执行以下操作:
type DataEventType = "data"; type ErrorEventType = "error"; declare interface IDataStore<TResponse> extends Emitter { on(name: DataEventType, handler : (data: TResponse) => void); on(name: ErrorEventType, handler: (error: any) => void); }