【问题标题】:How can I bind an eventhandler to a class method in typescript?如何将事件处理程序绑定到打字稿中的类方法?
【发布时间】:2016-08-14 08:36:43
【问题描述】:

我使用打字稿编写应用程序。并将其编译为js,除了事件绑定部分外,它运行良好。 _stateService 是我注入到这个类中的一个类。

下面的类是尝试使用jQuery创建一个DOM元素,然后将其传递给另一个类进行渲染,创建部分运行良好,最终呈现在页面上。但是事件绑定有点棘手。

一开始想用$().click()来绑定,但是因为元素还没有渲染失败。

然后我尝试使用 $().on() 进行绑定,它可以工作。但在运行时,它会抛出一个错误:

TemplatingService.ts:37 未捕获类型错误:无法读取属性 未定义的“回调”(匿名函数)@ TemplatingService.ts:37dispatch@jquery.min.js:3q.handle@ jquery.min.js:3

看来,如果我只是在该绑定函数中使用 console.log("test"),它就可以工作。但是如果我尝试将它绑定到一个类方法,它就会失败。似乎失去了上下文,我该如何解决这个问题?

原来的打字稿是:

export class TemplatingService implements ITemplatingService {
    _stateService: IStateService;

    constructor(stateService: IStateService) {
        this._stateService = stateService;
    }

    createPage(page:IPage):JQuery{
        let outerDiv = this.createLayout();
        for (let element of page.rawLayout){
            switch(element.type){
                case "button":
                    let temp = this.createJQueryButton();
                    $(".emulator").on('click', "#"+element.name, function(){
                                   this._stateService.CallBack(element);
                    });
                    outerDiv.append(temp);
                    break;
            }
        }
        return outerDiv;
    }
}

相关的生成js如下:

"use strict";
var TemplatingService = (function () {
    function TemplatingService(stateService) {
        this._stateService = stateService;
    }

    TemplatingService.prototype.createPage = function (page) {
        var outerDiv = this.createLayout();
        var _loop_1 = function(element1) {
            switch (element.type) {
                case "button":
                    var temp = this_1.createjQueryButton();
                    $(".emulator").on('click', "#" + element.name, function () {
                        this._stateService.CallBack(element);
                    });
                    outerDiv.append(temp);
                    break;
            }
        };
        var this_1 = this;
       for (var _a = 0, _b = page.rawLayout; _a < _b.length; _a++) {
            var element1 = _b[_a];
            _loop_1(element1);
        }
        return outerDiv;

}());

exports.TemplatingService = TemplatingService;
//# sourceMappingURL=TemplatingService.js.map

【问题讨论】:

    标签: jquery events typescript binding


    【解决方案1】:

    问题确实是您传递给.on 的函数有自己的this 上下文。对于普通的 ES5,你可以使用 .bind(this)var self = this; 来“修复”this 上下文,但是对于 TypeScript 和 ES6,你也可以使用箭头函数:

    export class TemplatingService implements ITemplatingService {
        _stateService: IStateService;
    
        constructor(stateService: IStateService) {
            this._stateService = stateService;
        }
    
        createPage(page:IPage):JQuery{
            let outerDiv = this.createLayout();
            for (let element of page.rawLayout){
                switch(element.type){
                    case "button":
                        let temp = this.createJQueryButton();
                        $(".emulator").on('click', "#"+element.name, () => { // <<< arrow!
                                       this._stateService.CallBack(element);
                        });
                        outerDiv.append(temp);
                        break;
                }
            }
            return outerDiv;
        }
    }
    

    【讨论】:

    • 嗨,谢谢你的回答。箭头函数不只是一个简单的匿名函数吗?如果它是一个函数,为什么它的行为与原来的不同?
    • @AlbertGao 箭头函数不仅仅是匿名函数的较短语法。它们没有自己的this 上下文,而是从周围范围(the "lexical this")“捕获”this 上下文。如果您查看 TypeScript 编译器为此代码生成的内容,您会发现它等同于 var self = this; 技巧。
    • 谢谢,现在我知道为什么了?
    【解决方案2】:

    回调需要绑定this

     $(".emulator").on('click', "#"+element.name, function(){
         this._stateService.CallBack(element);
     }.bind(this));
    

    或者更好的解决方案是将this 保存到变量中

    createPage(page:IPage):JQuery{
        const self = this;
        let outerDiv = this.createLayout();
        for (let element of page.rawLayout){
            switch(element.type){
                case "button":
                    let temp = this.createJQueryButton();
                    $(".emulator").on('click', "#"+element.name, function(){
                         self._stateService.CallBack(element);
                    });
                    outerDiv.append(temp);
                    break;
            }
        }
        return outerDiv;
    }
    

    【讨论】:

    • 你是我的天使!!
    • 或者更好:使用箭头函数。
    • @MattiasBuelens 您好,感谢您的评论。当你提到箭头函数时,你指的是哪种方法?那 stateService.CallBack() 还是 this.createPage()?
    • @AlbertGao 正如 Mattias 所说,使用箭头函数。我认为这是您使用 TypeScript 时的最佳选择 :)
    • @AlbertGao 点击回调:$(".emulator").on('click', "#"+element.name, () =&gt; { this._stateService.CallBack(element); });
    猜你喜欢
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 2013-11-20
    • 2021-07-29
    • 2016-12-10
    • 2013-04-18
    • 1970-01-01
    相关资源
    最近更新 更多