wake-up-neo.com

Event-Listener entfernen, der mit bind hinzugefügt wurde

Was ist der beste Weg, um in JavaScript eine als Event-Listener hinzugefügte Funktion mithilfe von bind () zu entfernen?

Beispiel

(function(){

    // constructor
    MyClass = function() {
        this.myButton = document.getElementById("myButtonID");
        this.myButton.addEventListener("click", this.clickListener.bind(this));
    };

    MyClass.prototype.clickListener = function(event) {
        console.log(this); // must be MyClass
    };

    // public method
    MyClass.prototype.disableButton = function() {
        this.myButton.removeEventListener("click", ___________);
    };

})();

Die einzige Möglichkeit, die ich mir vorstellen kann, ist, jeden mit bind hinzugefügten Listener im Auge zu behalten.

Beispiel oben mit dieser Methode:

(function(){

    // constructor
    MyClass = function() {
        this.myButton = document.getElementById("myButtonID");
        this.clickListenerBind = this.clickListener.bind(this);
        this.myButton.addEventListener("click", this.clickListenerBind);
    };

    MyClass.prototype.clickListener = function(event) {
        console.log(this); // must be MyClass
    };

    // public method
    MyClass.prototype.disableButton = function() {
        this.myButton.removeEventListener("click", this.clickListenerBind);
    };

})();

Gibt es bessere Wege, dies zu tun?

126
takfuruya

Das, was @machineghost gesagt hat, war wahr, dass Ereignisse auf dieselbe Weise hinzugefügt und entfernt werden, aber der fehlende Teil der Gleichung war der folgende:

Nach dem Aufruf von .bind() wird eine neue Funktionsreferenz erstellt!

Siehe Ändert bind () die Funktionsreferenz? | Wie dauerhaft einstellen?

Um es hinzuzufügen oder zu entfernen, weisen Sie die Referenz einer Variablen zu:

var x = this.myListener.bind(this);
Toolbox.addListener(window, 'scroll', x);
Toolbox.removeListener(window, 'scroll', x);

Das funktioniert wie erwartet für mich.

221
Ben

Für diejenigen, die dieses Problem beim Registrieren/Entfernen des Listeners der React-Komponente im Flux-Store haben, fügen Sie dem Konstruktor Ihrer Komponente die folgenden Zeilen hinzu:

class App extends React.Component {
  constructor(props){
    super(props);
    // it's a trick! needed in order to overcome the remove event listener
    this.onChange = this.onChange.bind(this);  
  }
  // then as regular...
  componentDidMount (){
    AppStore.addChangeListener(this.onChange);
  }
  
  componentWillUnmount (){
    AppStore.removeChangeListener(this.onChange);
  }

  onChange () {
    let state = AppStore.getState();
    this.setState(state);
  }
  
  render() {
    // ...
  }
  
}

39
Raichman Sergey

Es spielt keine Rolle, ob Sie eine gebundene Funktion verwenden oder nicht. Sie entfernen es auf dieselbe Weise wie alle anderen Ereignishandler. Wenn Ihr Problem darin besteht, dass die gebundene Version ihre eigene einzigartige Funktion ist, können Sie entweder die gebundenen Versionen nachverfolgen oder die removeEventListener-Signatur verwenden, für die kein bestimmter Handler erforderlich ist (obwohl dadurch natürlich auch andere Ereignishandler derselben entfernt werden Art).

(Als Randbemerkung funktioniert addEventListener nicht in allen Browsern. Sie sollten eine Bibliothek wie jQuery verwenden, um Ihre Event-Hook-ups für verschiedene Browser zu erstellen. Außerdem hat jQuery das Konzept von Namespace-Ereignissen Sie können sich an "click.foo" binden. Wenn Sie das Ereignis entfernen möchten, können Sie jQuery "alle foo-Ereignisse entfernen" mitteilen, ohne den jeweiligen Handler zu kennen oder andere Handler zu entfernen.)

3
machineghost

Hier ist die Lösung:

var o = {
  list: [1, 2, 3, 4],
  add: function () {
    var b = document.getElementsByTagName('body')[0];
    b.addEventListener('click', this._onClick());

  },
  remove: function () {
    var b = document.getElementsByTagName('body')[0];
    b.removeEventListener('click', this._onClick());
  },
  _onClick: function () {
    this.clickFn = this.clickFn || this._showLog.bind(this);
    return this.clickFn;
  },
  _showLog: function (e) {
    console.log('click', this.list, e);
  }
};


// Example to test the solution
o.add();

setTimeout(function () {
  console.log('setTimeout');
  o.remove();
}, 5000);
0

jQuery-Lösung:

let object = new ClassName();
let $elem = $('selector');

$elem.on('click', $.proxy(object.method, object));

$elem.off('click', $.proxy(object.method, object));
0
Ed Kolosovsky

Wir hatten dieses Problem mit einer Bibliothek, die wir nicht ändern konnten. Office Fabric-Benutzeroberfläche, was bedeutete, dass wir die Art und Weise, in der Ereignishandler hinzugefügt wurden, nicht ändern konnten. Wir haben es so gelöst, dass wir die addEventListener auf dem EventTarget-Prototyp überschrieben haben.

Dadurch wird eine neue Funktion für Objekte hinzugefügt. element.removeAllEventListers("click")

(Originalbeitrag: Click-Handler aus Stoffdialog-Overlay entfernen )

        <script>
            (function () {
                "use strict";

                var f = EventTarget.prototype.addEventListener;

                EventTarget.prototype.addEventListener = function (type, fn, capture) {
                    this.f = f;
                    this._eventHandlers = this._eventHandlers || {};
                    this._eventHandlers[type] = this._eventHandlers[type] || [];
                    this._eventHandlers[type].Push([fn, capture]);
                    this.f(type, fn, capture);
                }

                EventTarget.prototype.removeAllEventListeners = function (type) {
                    this._eventHandlers = this._eventHandlers || {};
                    if (type in this._eventHandlers) {
                        var eventHandlers = this._eventHandlers[type];
                        for (var i = eventHandlers.length; i--;) {
                            var handler = eventHandlers[i];
                            this.removeEventListener(type, handler[0], handler[1]);
                        }
                    }
                }

                EventTarget.prototype.getAllEventListeners = function (type) {
                    this._eventHandlers = this._eventHandlers || {};
                    this._eventHandlers[type] = this._eventHandlers[type] || [];
                    return this._eventHandlers[type];
                }

            })();
        </script>
0
Peter

kann über ES7 verwenden:

class App extends React.Component {
  constructor(props){
    super(props);
  }
  componentDidMount (){
    AppStore.addChangeListener(this.onChange);
  }

  componentWillUnmount (){
    AppStore.removeChangeListener(this.onChange);
  }

  onChange = () => {
    let state = AppStore.getState();
    this.setState(state);
  }

  render() {
    // ...
  }

}
0
chiic