TypeScript自定义事件侦听器

时间:2015-11-06 23:50:52

标签: typescript

我认为我从这里的理解中遗漏了一些非常重要的东西,所以也许一点点解释也会非常有帮助。

我有一个班级,如此:

class Entity {
    protected pos: number = [0,0];

    ...

    public setPos(x: number, y: number) {
        this.pos = [x, y];
    }
}

并想要像

这样的东西
class EntityPositionListener {
    //do stuff when an Entity position changes
}

我也有Entity类的后代。因此,只要EntityEntity的任何后代本身更改pos变量(在给定的实例中),我想知道它,以便我可以更新位置地图,以及捕获实例,所以我理论上可以做其他事情。

我注意到Firefox有Object.watch()命令,我找到了一个"跨浏览器"有人在另一个问题上发布的解决方案 - 无济于事 - 而且我已经尝试过"包装"在初始化后阶段的Entity类,但后者最终会覆盖Entity类或创建一个无限循环,所以我显然在某处忽略了这一点。如果包装是答案,我该如何在TypeScript中执行此操作? JS版本创建了一个循环或者没有工作。

//This created an infinite loop in runtime, but more importantly overwrote the Entity class
function EntityListener(name) {
    cout(name);
}
var oldEntity = Entity;
function Entity(name) {
    if (typeof EntityListener === "function") {
        EntityListener(name);
    }

    oldEntity(name);
}

理想情况下,我想听一个特定课程上的几件事情 - 例如在游戏更新循环中 - 这个特殊情况仅用于演示。我发现了无数的链接,其中许多是JS而不是明确的TypeScript,所以我真的很喜欢TypeScript解决方案以及一些关于发生了什么的解释。我基本上不理解如何解决这个问题。

修改

如果这是问题的更好版本,可能更简单,我如何监听Entity.setPos()被调用?

2 个答案:

答案 0 :(得分:1)

Object.observe最有可能droppedObject.watch仅在Gecko中受支持,因此请不要在代码中使用它,除非您只定位Firefox。

这意味着您必须编写自己的事件发射。如果您愿意,可以使用TypeScript getter和setter:

class Entity {
    private entitityListener:EntityPositionListener;
    private _pos:number[] = [];

    get pos():number[] {
        return this._pos;
    }
    set pos(value:number[]) {            
        this._pos = value;

        if (this.entitityListener) {
            this.entitityListener.reportEvent('pos', value);
        }
    }
}

class SuperEntity extends Entity {

}

let superEntity = new SuperEntity();
superEntity.pos = [1,2]; // this will call 'this.entitityListener.reportEvent()' and you don't need superEntity.setPos([1,2]);

转化为:

var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Entity = (function () {
    function Entity() {
        this._pos = [];
    }
    Object.defineProperty(Entity.prototype, "pos", {
        get: function () {
            return this._pos;
        },
        set: function (value) {
            this._pos = value;
            if (this.entitityListener) {
                this.entitityListener.reportEvent('pos', value);
            }
        },
        enumerable: true,
        configurable: true
    });
    return Entity;
})();
var SuperEntity = (function (_super) {
    __extends(SuperEntity, _super);
    function SuperEntity() {
        _super.apply(this, arguments);
    }
    return SuperEntity;
})(Entity);
var superEntity = new SuperEntity();
superEntity.pos = [1, 2];

您可以使用Object.defineProperty()来定义getter和setter,这意味着您可以定义setter以包含对EntityListener方法的调用。

答案 1 :(得分:0)

最好使用subscribe方法,因此您可以自动在对象上支持任意数量的事件侦听器,而不仅仅是一个。并使用强类型事件,以确保类型安全。

今天,几个图书馆可以做到这一点。这是通过sub-events实现的:

import {SubEvent} from 'sub-events';

class Entity {

   // strongly-typed event:
   readonly onPosChanged: SubEvent<{newPos: number[], oldPos: number[]}> = new SubEvent();

   private _pos: number[] = [];

   get pos(): number[] {
       return this._pos;
   }

   set pos(newPos: number[]) {
       const oldPos = this._pos;
       this._pos = newPos;
       this.onPosChanged.emit({newPos, oldPos});
   }
}

然后,任何派生类都可以预订pos的更改以及该类的任何变量实例:

const e = new Entity();

e.onPosChanged.subscribe(data => {
    // data is strongly-typed

    console.log(data); //-> { newPos: [ 1, 2, 3 ], oldPos: [] }
});

e.pos = [1, 2, 3]; // this will trigger the event