Comment puis-je supprimer l'écouteur de clics que j'ai lié à la fenêtre
dans le constructeur
ci-dessous? J'en ai besoin pour écouter sur window
, et j'ai besoin d'accéder à l'instance de bouton à l'intérieur.
<button is="my-el" type="button">Click me</button>
class MyEl extends HTMLButtonElement { constructor() { super(); this.clickCount = 0; window.addEventListener('click', this.clickHandler.bind(this)); } clickHandler(e) { if (e.target === this) { this.textContent = `clicked ${++this.clickCount} times`; window.removeEventListener('click', this.clickHandler); } } disconnectedCallback() { window.removeEventListener('click', this.clickHandler); } } customElements.define('my-el', MyEl, { extends: 'button' });
3 Réponses :
Ce n'est pas possible avec votre implémentation actuelle - chaque appel de Pour contourner ce problème, vous pouvez affecter la fonction liée à une propriété de l'instance: .bind
crée une nouvelle fonction séparée, et vous ne pouvez appeler removeEventListener
que pour supprimer un écouteur si la fonction passée est le même ( ===
) que celui passé à addEventListener
(tout comme .includes
pour les tableaux, ou .has pour les ensembles):
<button is="my-el" type="button">Click me</button>
class MyEl extends HTMLButtonElement {
constructor() {
super();
this.clickCount = 0;
this.boundListener = this.clickHandler.bind(this);
window.addEventListener('click', this.boundListener);
}
clickHandler(e) {
this.textContent = `clicked ${++this.clickCount} times`;
window.removeEventListener('click', this.boundListener);
}
}
customElements.define('my-el', MyEl, { extends: 'button' });
const fn = () => 'foo';
console.log(fn.bind(window) === fn.bind(window));
Créez un wrapper func pour votre clickHandler comme ceci.
<button is="my-el" type="button">Click me</button>
class MyEl extends HTMLButtonElement { constructor() { super(); this.clickCount = 0; this.wrapper = e => this.clickHandler.apply(this, e); window.addEventListener('click', this.wrapper); } clickHandler(e) { this.textContent = `clicked ${++this.clickCount} times`; window.removeEventListener('click', this.wrapper); } } customElements.define('my-el', MyEl, { extends: 'button' });
C'est celui qui a fonctionné pour moi, mais il faut noter que apply
prend un tableau d'arguments et call
les prend individuellement, donc j'ai fini par utiliser ce dernier pour passer sur l'événement.
Un autre modèle consiste à conserver votre écouteur à l'intérieur du constructeur.
Pour supprimer un écouteur d'événement (quel que soit le modèle), vous pouvez ajouter un "remove" function au moment où vous créez un Event Listener.
Puisque la fonction de suppression est appelée dans la portée listen
, elle utilise la fonction même nom
et func
tion
pseudo code:
<button id="One" is="my-el" type="button">Click me</button> <button onclick="One.mute()">Mute</button> <button onclick="One.eol()">Delete</button> <br> <button id="Two" is="my-el" type="button">Click me too</button> <button onclick="Two.disconnectedCallback()">Mute</button> <button onclick="Two.eol()">Delete</button>
Exécutez l'extrait de code ci-dessous pour le voir utilisé avec plusieurs boutons
pour vous faire gagner une heure une fois que vous le faites plus avec des événements ...
Notez que les WebComponents (c'est-à-dire CustomElements avec shadowDOM) ont besoin de CustomEvents avec la propriété compose: true
si vous veulent qu'ils passent vers le haut au-delà de sa limite shadowDOM
button{ width:12em; }
Remarque: cet exemple ne fonctionne pas sur Safari, car Apple refuse de mettre en œuvre l'extension d'élem ents: étend HTMLButtonElement
class MyEl extends HTMLButtonElement { constructor() { let ME = super();// super() retuns this scope; ME makes code easier to read let count = 0;// you do not have to stick everything on the Element ME.mute = ME.listen('click' , event => { //this function is in constructor scope, so has access to ALL its contents if(event.target === ME) //because ALL click events will fire! ME.textContent = `clicked ${ME.id} ${++count} times`; //if you only want to allow N clicks per button you call ME.mute() here }); } listen(name , func){ window.addEventListener( name , func ); console.log('added' , name , this.id ); return () => { // return a Function! console.log( 'removeEventListener' , name , 'from' , this.id); this.style.opacity=.5; window.removeEventListener( name , func ); } } eol(){ // End of Life this.parentNode.removeChild(this); } disconnectedCallback() { console.log('disconnectedCallback'); this.mute(); } } customElements.define('my-el', MyEl, { extends: 'button' });
new CustomEvent("check", { bubbles: true, //cancelable: false, composed: true // required to break out of shadowDOM });
listen(name , func){ window.addEventListener(name, func); return () => window.removeEventListener( name , func ); } let remove = listen( 'click' , () => alert('BOO!') ); //cleanup: remove();
Notes:
count
n'est pas disponible en tant que this.count
mais est disponible pour toutes les fonctions définies dans la portée du constructeur. Donc c'est (un peu) privé, seule la fonction clic peut le mettre à jour.
onclick = Two.disconnectedCallback ()
à titre d'exemple, cette fonction ne supprime PAS l'élément.
Soit je ne comprends pas, soit vous avez manqué la partie cruciale .bind (this)
lors de l'ajout de l'auditeur (qui est la cause réelle de mon problème).
bind ()
concerne la définition de la portée, puisque la fonction d'écoute de cet exemple s'exécute dans la portée constructor
, il n'est pas nécessaire d'utiliser bind ()
. Je mettrai à jour la première phrase pour dire «un autre modèle»
.. et si votre gestionnaire de clics est énorme et que vous avez des milliers et des milliers de boutons et que la mémoire est un problème, vous pouvez bien sûr lier
une fonction de classe. La même approche d'écoute / silence pour un EventListener s'applique ► ME.mute = Me.listen ('click', ME.handler.bind (ME));
Malheureusement, votre compréhension de ceci
vous échoue ici. La fonction s'exécute dans la portée de l'élément / objet auquel l'écouteur est attaché, sauf si vous utilisez .bind (this)
.
Désolé, je n'ai pas été assez clair. Voici deux modèles différents non utilisant bind ()
jsfiddle .net / dannye / a6nvk173
Contrôlez-vous le code JavaScript?
Est-ce que cela répond à votre question? Suppression de l'écouteur d'événements qui a été ajouté avec la liaison