web-dev-qa-db-fra.com

Supprimer l'écouteur d'événement ajouté avec bind

En JavaScript, quel est le meilleur moyen de supprimer une fonction ajoutée en tant qu'écouteur d'événements à l'aide de bind ()?

Exemple

(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", ___________);
    };

})();

La seule façon dont je peux penser est de garder une trace de chaque auditeur ajouté avec bind.

Exemple ci-dessus avec cette méthode:

(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);
    };

})();

Y a-t-il de meilleures façons de le faire?

126
takfuruya

Bien que ce que @machineghost ait dit soit vrai, les événements sont ajoutés et supprimés de la même manière, mais la partie manquante de l'équation était la suivante:

Une nouvelle référence de fonction est créée après l'appel de .bind()!

Voir Est-ce que bind () change la référence de la fonction? | Comment définir en permanence?

Donc, pour l'ajouter ou le supprimer, affectez la référence à une variable:

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

Cela fonctionne comme prévu pour moi.

221
Ben

Pour ceux qui ont ce problème lors de l'enregistrement/de la suppression du programme d'écoute du composant React dans/à partir du magasin Flux, ajoutez les lignes ci-dessous au constructeur de votre composant:

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

Peu importe que vous utilisiez une fonction liée ou non; vous le supprimez de la même manière que tout autre gestionnaire d’événements. Si votre problème est que la version liée est sa propre fonction unique, vous pouvez soit garder la trace des versions liées, soit utiliser la signature removeEventListener qui ne prend pas un gestionnaire spécifique (bien que cela supprime bien sûr d'autres gestionnaires d'événements du même type).

(Remarque: addEventListener ne fonctionne pas dans tous les navigateurs; vous devez absolument utiliser une bibliothèque telle que jQuery pour effectuer vos raccordements d’événements de manière multinaveu vous permet de vous lier à "click.foo"; lorsque vous souhaitez supprimer l'événement, vous pouvez dire à jQuery "supprimer tous les événements foo" sans avoir à connaître le gestionnaire spécifique ni à supprimer les autres gestionnaires.)

3
machineghost

Voici la solution:

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
Nazar Vynnytskyi

solution jQuery:

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

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

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

Nous avons eu ce problème avec une bibliothèque que nous ne pouvions pas changer. Interface utilisateur Office Fabric, ce qui signifie que nous ne pouvions pas changer la façon dont les gestionnaires d'événements ont été ajoutés. Notre solution consistait à écraser la variable addEventListener sur le prototype EventTarget.

Cela va ajouter une nouvelle fonction sur les objets element.removeAllEventListers("click")

(message original: Supprimer le gestionnaire de clic de la superposition de la boîte de dialogue Fabric )

        <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

peut utiliser environ ES7:

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