【问题标题】:Create custom event within class in TypeScript在 TypeScript 的类中创建自定义事件
【发布时间】:2019-01-11 20:20:54
【问题描述】:

我试图弄清楚如何在 TypeScript 中为类创建自定义事件。像this one 这样的例子对我理解如何做到这一点没有多大帮助。

我的示例类如下所示。

猫.ts:

export class Cat {
    public getName(): string {
        return this.catName;
    }

    public setName(catName: string) {
        this.catName = catName;
    }

    constructor(private catName: string) { }

    public makeMeow() {
        this.onWillMeow();
        console.log("Cat meows!");
        this.onDidMeow();
    }

    public onWillMeow() {
        console.log("onWillMeow");
    }

    public onDidMeow() {
        console.log("onDidMeow");
    }
}

现在我希望能够从外部声明事件,就像下面的代码旨在演示的那样。

const myCat: Cat = new Cat("Tikki");
myCat.onWillMeow({event => {
     console.log("Tikki the cat is just about to meow!");
}});
myCat.onWillMeow({event => {
     console.log("Tikki the cat did just meow!");
}});
myCat.makeMeow();

现在,我想得到一些像这样的输出:

onWillMeow
Tikki the cat is just about to meow!
Cat meows!
onDidMeow
Tikki the cat did just meow!

我必须做什么才能在 TypeScript 中完成这项工作?这个具体怎么称呼?创建自定义事件还是创建自定义事件处理程序

【问题讨论】:

    标签: typescript events event-handling


    【解决方案1】:

    类似这样的:

    type Handler<E> = (event: E) => void;
    
    class EventDispatcher<E> { 
        private handlers: Handler<E>[] = [];
        fire(event: E) { 
            for (let h of this.handlers)
                h(event);
        }
        register(handler: Handler<E>) { 
            this.handlers.push(handler);
        }
    }
    
    interface WillMeowEvent { }
    interface DidMeowEvent { }
    
    class Cat {
        public getName(): string {
            return this.catName;
        }
    
        public setName(catName: string) {
            this.catName = catName;
        }
    
        constructor(private catName: string) { }
    
        public makeMeow() {
            this.fireWillMeow({});
            console.log("Cat meows!");
            this.fireDidMeow({});
        }
    
        private willMeowDispatcher = new EventDispatcher<WillMeowEvent>();
        public onWillMeow(handler: Handler<WillMeowEvent>) {
            this.willMeowDispatcher.register(handler);
        }
        private fireWillMeow(event: WillMeowEvent) { 
            console.log("onWillMeow");
            this.willMeowDispatcher.fire(event);
        }
    
        private didMeowDispatcher = new EventDispatcher<DidMeowEvent>();
        public onDidMeow(handler: Handler<DidMeowEvent>) {
            this.didMeowDispatcher.register(handler);
        }
        private fireDidMeow(event: DidMeowEvent) { 
            console.log("onDidMeow");
            this.didMeowDispatcher.fire(event);
        }
    }
    
    const myCat: Cat = new Cat("Tikki");
    myCat.onWillMeow(event => {
         console.log("Tikki the cat is just about to meow!");
    });
    myCat.onDidMeow(event => {
         console.log("Tikki the cat did just meow!");
    });
    myCat.makeMeow();
    

    我确信有些库可以提供帮助。有人想在另一个答案中推荐图书馆吗?

    【讨论】:

    • 感谢您的回答。你能评价一下type Handler&lt;E&gt; = (event: E) =&gt; void;之间的含义吗?为什么指向voidHandler 这个名字只是一个名字,可以是任何东西,对吧?
    • void 表示事件处理程序(例如,带有console.log("Tikki the cat is just about to meow!"); 的函数)不返回值。确实,Handler 只是一个可以更改的名称,但它是一个非常标准的术语。
    • I'm sure there are libraries that can help. Anyone want to recommend a library in another answer?。是的,并且没有简单地提供链接,我添加了一个使用sub-events 来实现原始问题中所问内容的完整示例。
    【解决方案2】:

    今天在实现自定义事件时,重要的是事件是强类型的,即在转译期间推断事件发送的数据类型,以减少代码出错的可能性。

    今天有几个图书馆可以做到这一点。以下是使用sub-events 的方法:

    import {SubEvent} from 'sub-events';
    
    class Cat {
    
        // strongly-typed event that expects a string:
        readonly onMeow: SubEvent<string> = new SubEvent();
    
        constructor(private catName: string) {
        }
    
        public makeMeow(message: string) {
            this.onMeow.emit(`${this.catName} ${message}`);
        }
    }
    
    const myCat = new Cat('Tikki');
    
    myCat.onMeow.subscribe(message => {
        // message is strongly-typed here;
    
        console.log(message); //-> Tikki cat is doing something
    });
    
    myCat.makeMeow('cat is doing something'); // send the event
    

    由于您发送的事件类型相同,只是消息不同,因此您通常会将其概括为单个事件。这就是为什么在示例中我将其简化为一个事件onMeow

    另外,subscribe 几乎是当今的标准方法,让您可以随时轻松取消订阅,如下所示:

    const sub = myCat.onMeow.subscribe(message => {
        console.log(message); // message is strongly-typed here;
    });
    

    当不再需要该事件时,您取消订阅:

    sub.cancel();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-11
      • 2020-02-05
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-14
      相关资源
      最近更新 更多