简体   繁体   English

在对象中使用AddEventListener

[英]AddEventListener with in a object

I could need your help, at the moment I am trying to call a method within a object through a addEventListener activation. 目前,我正在尝试通过addEventListener激活在对象内调用方法时,可能需要您的帮助。 The problem is that the this pointer is changing as soon as the method get called. 问题在于,一旦方法被调用,this指针就会改变。 I tried to use the .call to give the method the right context back and it worked as expected but is this the best way ? 我尝试使用.call为方法提供正确的上下文,并且按预期方式工作,但这是最好的方法吗?

<!doctype html>
<html>
    <head>
        <title>Java Script Test</title>
        <meta charset="UTF-8" />
   <!-- <script src="//code.jquery.com/jquery-1.11.2.min.js"></script> -->
        <script src="../resurces/js/jquery-1.11.2.min.js" ></script>
        <script>
            var test_class = function(){
                this.variable = "more text";
                this.click = function(){
                    $("#return").text("Content: "+this.variable);
                }
                this.aktivate_listener = function(){
                    var that = this;
                    document.getElementById("clicker").addEventListener("click", function(){that.click.call(that)});
                }

            }

            $("document").ready(function(){
                console.log("#ready");
                var class1 = new test_class();
                class1.aktivate_listener();

            });
        </script>
    </head>
    <body>
        <p id="clicker">This is some Text to click on.</p>
        <p id="return"></p>
    </body>
</html>

Do some of you know a better way ? 你们中有人知道更好的方法吗?

Thanks for your effort , Flo 感谢您的努力,Flo

That's mostly fine, but a couple of points: 基本上没问题,但有两点:

  1. You don't need to do that.click.call(that) — simply that.click() will work. 您不需要这样做that.click.call(that) -只需that.click()就可以了。

  2. You're not passing on the event object that your anonymous function receives. 您没有传递匿名函数接收的事件对象。 If you don't need it, that's fine, but I thought I'd mention it. 如果您不需要它,那很好,但是我想我会提到它。

Another alternative is to use Function#bind : 另一种选择是使用Function#bind

this.aktivate_listener = function(){
    document.getElementById("clicker").addEventListener("click", this.click.bind(this));
}

Function#bind returns a function that, when called, turns around and calls the original function with this set to a specific value. Function#bind返回一个函数,该函数在被调用时会转回并调用原始函数,并将this函数设置为特定值。 So this.click.bind(this) creates a function that, when called, will call click on the object with this referring to the object. 所以this.click.bind(this)创建,调用它时,会调用一个函数click的对象与this参照对象。 Any arguments to the bound function are passed on when it calls the underlying function. 绑定函数的任何参数在调用基础函数时都会传递。


Re your comment: 发表您的评论:

But I read that you can't remove an EventListener that is created with .bind A problem in the example above is that you cannot remove the listener with bind . 但我读到您无法删除使用.bind创建的EventListener A problem in the example above is that you cannot remove the listener with bind That is taken from the Mozilla Developer Network. 这取自Mozilla开发人员网络。

If so, MDN is wrong. 如果是这样,则MDN是错误的。 It's community-edited, that happens. 这是由社区编辑的。 :-) :-)

In terms of being able to remove the handler with removeEventListener , there's no difference at all between your code and using Function#bind as above: You can't remove the listener in either case without changing the code to remember what we passed to addEventListener . 在能够删除与处理方面removeEventListener ,有没有区别你的代码和使用之间的所有 Function#bind如上:在不改变代码记住我们传递给您不能删除监听器在两种情况下addEventListener

There's nothing special about event handlers that use bind . 使用bind事件处理程序没有什么特别的。 Just like any other event handler, if you want to remove it with removeEventListener , you have to have a reference to the same function you added when removing it. 就像任何其他事件处理程序一样,如果要使用removeEventListener删除它,则必须具有对删除它时所添加的相同函数的引用。 In your code, that would be the anonymous function that you have wrapped around that.click.call(that); 在您的代码中,那将是您在that.click.call(that);周围包裹的匿名函数that.click.call(that); , and since you didn't keep a reference to it, you can't remove it. ,并且由于您未保留对其的引用,因此无法将其删除。 Similarly, in my code above, you can't remove the listener because I didn't keep a reference to the bound function. 同样,在上面的代码中,您无法删除侦听器,因为我没有保留对绑定函数的引用。

If that's something you need to do, just remember the function you want to remove — that's a reference to your anonymous function, or a reference to the function returned by Function#bind . 如果这是您需要做的事情,只需记住要删除的函数,即对您的匿名函数的引用,或对Function#bind返回的Function#bind的引用。 You might store it on your object, for instance. 例如,您可以将其存储在对象上。

this.aktivate_listener = function(){
    if (this.boundClick) {
        this.deaktivate_listener();
    }
    this.boundClick = this.click.bind(this);
    document.getElementById("clicker").addEventListener("click", this.boundClick);
};
this.deacktivate_listener = function(){
    document.getElementById("clicker").removeEventListener("click", this.boundClick);
    this.boundClick = null;
};

Looking again at your code, you have a third option: Your click function is a closure over the call to test_class that created the instance, so you don't need to create another closure, just use the one you already have: 再次查看您的代码,您有第三个选择: click函数是对创建实例的test_class的调用的闭包,因此您无需创建另一个闭包,只需使用已有的闭包即可:

var test_class = function(){
    // Remember `this` in a variable
    var self = this;
    this.variable = "more text";
    this.click = function(){
        // Use it here
        $("#return").text("Content: "+self.variable);
    };
    this.aktivate_listener = function(){
        // Just use `this.click` here
        document.getElementById("clicker").addEventListener("click", this.click);
    };
    this.deaktivate_listener = function(){
        // Just use `this.click` here
        document.getElementById("clicker").removeEventListener("click", this.click);
    };
};

Side note: You need a ; 旁注:您需要一个; at the end of statements like var f = function() { }; 在类似var f = function() { };的语句末尾var f = function() { }; , because those are statements, not declarations. ,因为这些是语句,而不是声明。 I've added them above. 我已经在上面添加了它们。 If you don't provide it, Automatic Semicolon Insertion will add it for you most of the time, but you can trip up if you're not careful. 如果您没有提供,自动分号插入将在大多数情况下为您添加,但是如果不小心,可能会跳闸。


Examples of all of the above: 以上所有示例:

Your way without .call (without deaktivate): 你没有办法.call (无deaktivate):

 var Test = function(id, name) { this.id = id; this.name = name; this.click = function() { snippet.log("My name is " + this.name); }; this.aktivate_listener = function() { var that = this; document.getElementById(this.id).addEventListener( "click", function() { that.click(); }, false ); }; }; var t1 = new Test("one", "test one"); t1.aktivate_listener(); var t2 = new Test("two", "test two"); t2.aktivate_listener(); 
 <div id="one">Click me (one)</div> <div id="two">Click me (two)</div> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

With Function#bind (without deaktivate): 使用Function#bind (不消散):

 var Test = function(id, name) { this.id = id; this.name = name; this.click = function() { snippet.log("My name is " + this.name); }; this.aktivate_listener = function() { document.getElementById(this.id).addEventListener( "click", this.click.bind(this), false ); }; }; var t1 = new Test("one", "test one"); t1.aktivate_listener(); var t2 = new Test("two", "test two"); t2.aktivate_listener(); 
 <div id="one">Click me (one)</div> <div id="two">Click me (two)</div> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

Using the existing closure (without deaktivate): 使用现有的闭包(不消散):

 var Test = function(id, name) { var self = this; this.id = id; this.name = name; this.click = function() { snippet.log("My name is " + self.name); }; this.aktivate_listener = function() { document.getElementById(this.id).addEventListener( "click", this.click, false ); }; }; var t1 = new Test("one", "test one"); t1.aktivate_listener(); var t2 = new Test("two", "test two"); t2.aktivate_listener(); 
 <div id="one">Click me (one)</div> <div id="two">Click me (two)</div> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

Your way without .call (with deaktivate): 你没有办法.call (含deaktivate):

 var Test = function(id, name) { this.id = id; this.name = name; this.counter = 0; this.click = function() { snippet.log("My name is " + this.name); if (++this.counter == 2) { this.deaktivate_listener(); }; }; this.aktivate_listener = function() { var that = this; if (this.boundClick) { this.deaktivate_listener(); } this.boundClick = function() { that.click(); }; document.getElementById(this.id).addEventListener( "click", this.boundClick, false ); }; this.deaktivate_listener = function() { if (this.boundClick) { document.getElementById(this.id).removeEventListener( "click", this.boundClick, false ); this.boundClick = null; } }; }; var t1 = new Test("one", "test one"); t1.aktivate_listener(); var t2 = new Test("two", "test two"); t2.aktivate_listener(); 
 <div id="one">Click me (one) (second click deactivates)</div> <div id="two">Click me (two) (second click deactivates)</div> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

With Function#bind (with deaktivate): 使用Function#bind (带有deaktivate):

 var Test = function(id, name) { this.id = id; this.name = name; this.counter = 0; this.click = function() { snippet.log("My name is " + this.name); if (++this.counter == 2) { this.deaktivate_listener(); }; }; this.aktivate_listener = function() { if (this.boundClick) { this.deaktivate_listener(); } this.boundClick = this.click.bind(this); document.getElementById(this.id).addEventListener( "click", this.boundClick, false ); }; this.deaktivate_listener = function() { if (this.boundClick) { document.getElementById(this.id).removeEventListener( "click", this.boundClick, false ); this.boundClick = null; } }; }; var t1 = new Test("one", "test one"); t1.aktivate_listener(); var t2 = new Test("two", "test two"); t2.aktivate_listener(); 
 <div id="one">Click me (one) (second click deactivates)</div> <div id="two">Click me (two) (second click deactivates)</div> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

Using the existing closure (with deaktivate): 使用现有的闭包(带有deaktivate):

 var Test = function(id, name) { var self = this; this.id = id; this.name = name; this.counter = 0; this.click = function() { snippet.log("My name is " + self.name); if (++self.counter == 2) { self.deaktivate_listener(); }; }; this.aktivate_listener = function() { document.getElementById(this.id).addEventListener( "click", this.click, false ); }; this.deaktivate_listener = function() { document.getElementById(this.id).removeEventListener( "click", this.click, false ); }; }; var t1 = new Test("one", "test one"); t1.aktivate_listener(); var t2 = new Test("two", "test two"); t2.aktivate_listener(); 
 <div id="one">Click me (one) (second click deactivates)</div> <div id="two">Click me (two) (second click deactivates)</div> <!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 --> <script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script> 

Here is the version I use at the moment, it is made of @TJ Crowder answers. 这是我目前使用的版本,它由@TJ Crowder答案组成。

function boxOperator(){
    this.event      = [];

    this.addEvent = function(element, event, tocall_function, arg){         
        var call_function = tocall_function.bind(this, arg);
        this.event[this.event.length] = {
            "element"       : element,
            "event"         : event,
            "call_function" : call_function
        };
        document.getElementById(element).addEventListener(event,call_function);
    };

    this.removeEvent = function(element, event){
        if(!element){return false;};
        var remove_entry = function(index, array){return array.slice(0,index-1).concat(array.slice(index+1));}
        for(var i = 0; i < this.event.length;i++){
            if(this.event[i].element == element){
                var entry = this.event[i];
                if(entry.event == event){
                    document.getElementById(entry.element).removeEventListener(entry.event,entry.call_function);
                    this.event = remove_entry(i, this.event);
                }               
                if(typeof event == "undefined"){
                    document.getElementById(entry.element).removeEventListener(entry.event,entry.call_function);                
                    this.event = remove_entry(i, this.event);
                }
            }
        }
    };
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM