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?
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.
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() {
// ...
}
}
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.)
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);
solution jQuery:
let object = new ClassName();
let $elem = $('selector');
$elem.on('click', $.proxy(object.method, object));
$elem.off('click', $.proxy(object.method, object));
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>
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() {
// ...
}
}