3
votes

onclick non capté par l'élément personnalisé

Je définis un élément personnalisé

// Only in the base class
constructor() {
  super();

  for (let prop of Object.getOwnPropertyNames(this.constructor.prototype)) {
    if (prop.indexOf("on") === 0) {
      this.addEventListener(prop.substring(2).toLowerCase(), this.constructor.prototype[prop]);
    }
  }
}

https://jsfiddle.net/tuxkjp3q/

Mais quand je clique dessus, rien ne se passe.

Pourquoi cela et comment puis-je attacher des gestionnaires d'événements à chaque instance de la classe sans remplacer le constructeur?

Éditer:

Lorsque j'inspecte l'objet DOM, il y a un gestionnaire onclick, mais il ne fonctionne pas. Ceci est déroutant

entrez la description de l'image ici

Modifier 2:

D'autres découvertes, lorsqu'elles sont omises du prototype, la définition d'un gestionnaire fonctionne

customElements.define("my-button", class extends HTMLButtonElement {
  onclick() {
    console.log("bar");
  }

  constructor() {
    super();
    this.onclick = () => console.log("bar");
  }
}, { extends: "button" })

Mais lorsque le prototype contient onclick , le même gestionnaire ne fonctionne plus

customElements.define("my-button", class extends HTMLButtonElement {
  constructor() {
    super();
    this.onclick = () => console.log("bar");
  }
}, { extends: "button" })

Je serais vraiment heureux si nous pouvions obtenir une explication de ce phénomène.

MODIFIER 3:

J'ai trouvé une solution, si quelqu'un est confronté au même problème. Il est probablement intéressant de noter que seuls les gestionnaires définis dans le prototype direct de la classe instanciée seront attachés, ce qui est bon pour les performances mais probablement une logique défectueuse. Quoi qu'il en soit, il pourrait être adapté à vos besoins.

customElements.define("my-button", class extends HTMLButtonElement {
  onclick() {
    console.log("bar");
  }
}, { extends: "button" })

Je suis toujours très intéressé à en apprendre la raison.


11 commentaires

Pourquoi ne voulez-vous pas remplacer le constructeur?


@Supersharp c'est une décision de conception, ou en termes simples - c'est moche. Il y a un problème supplémentaire, disons que j'utilise addEventListener mais mes écouteurs sont en fait liés au prototype de la classe et utilisent des noms on* , puis un jour, le standard change et implémente le comportement attendu dans cette question, alors vous auriez le même handler appelé deux fois, ce qui entraînera probablement des applications cassées.


FYI: Les Built-Ins personnalisés (étendant autre chose que HTMLElement) ne fonctionneront jamais dans Safari; Apple refuse de mettre en œuvre cette partie de la norme. Remarque: l'édition n ° 3 autorise toujours les définitions this.onclick . La raison pour laquelle cela ne fonctionne pas comme prévu (aujourd'hui) est que les gestionnaires en ligne remontent à 25 ans. this.onclick est une this.onclick ancienne (totalement valide et la plupart du temps préférée); NOTATION différente des gestionnaires addEventListener (méthode préférée selon les manuels écrits après 2010) Lorsque la class ES6 a été introduite, ils (je suppose) ne voulaient pas la faire fonctionner avec une (ancienne) notation.


Note 2: # 3 va vous causer des problèmes de mémoire ... vous ajoutez des écouteurs partout, mais vous ne les supprimez pas. Garbage Collect peut attraper la plupart / certains, mais généralement si vous ajoutez un écouteur, vous êtes également responsable de la suppression de cet écouteur (dans le disconnectedCallback )


@ Danny'365CSI'Engelman me semble que le safari sera le nouveau, c'est-à-dire si Apple ne rassemble pas leur merde. Pourriez-vous fournir des sources pour la note 2? Je crois que les auditeurs sont rassemblés avec l'élément.


Les blogs GC habituels. Par votre question, je peux vous dire ce que vous faites. Moi-même, je ne ferais pas votre ... plutôt brutal ... edit # 3 cependant, vous attachez une merde d'auditeurs, en plus de cliquer, il y a aussi ondragstart et beaucoup de ses compagnons ... JavaScript est parfois une bête étrange, don ' t le combattre.


@ Danny'365CSI'Engelman vous avez probablement manqué quelque chose, j'utilise actuellement une version légèrement modifiée de cette approche et mes éléments n'ont que quelques écouteurs attachés - autant que j'ai défini dans la classe elle-même. Peut-être avez-vous manqué qu'il n'attachera un écouteur que si la classe a sa propre propriété commençant par "on". Ce n'est pas très utile une fois que vous commencez à étendre une classe et que vous vous demandez pourquoi les on* s parent ne fonctionnent pas, donc dans ma version modifiée, j'ai autorisé cela avec un simple ajustement mais je ne l'ai pas ajouté ici car c'est un peu plus difficile pour comprendre et nécessite un appel.


Consultez le code que j'ai joint à votre question. Vous combattez la bête JavaScript avec des centaines d'auditeurs ON inutiles ... Eh bien, ce n'est pas un combat , vous êtes tellement occupé avec des auditeurs que vous avez déjà perdus ...


@ Danny'365CSI'Engelman Oui, c'est exactement ce que je voulais dire, ces propriétés ne seront pas prises en compte car mon exemple fonctionnera sur une classe qui étend HTMLElement qui ne les aura pas comme propriétés propres . Découvrez-le ici . Évidemment, cela devrait être utilisé comme un mixin ou quelque chose comme ça.


C'est votre code, c'est votre fête. this.onclick = this.onClick; réalise la même chose. Eh bien ... presque le même, à proprement parler c'est un autre gestionnaire (c'est un "vieux" JavaScript, pas un Event Listener ajouté par addEventListener ). Mais le but est qu'un clic sur un bouton soit traité. Avec les composants, je préfère cette notation, car un utilisateur peut facilement l'écraser ... ce qui ne peut pas être fait avec un écouteur ajouté avec addEventListener moins que le fournisseur de composants n'ait inclus une méthode removeListener .


@ Danny'365CSI'Engelman oui, c'est essentiellement cette question. Pourquoi cela fonctionne-t-il si je l'attribue dans le constructeur mais pas si dans le prototype. J'ai juste choisi la meilleure solution pour la solution de contournement.


3 Réponses :


3
votes

Le problème est que vous devez définir l'écouteur du clic ... pas la fonction onClick

<button is="custom-button">
  Hi
</button>

html

class CustomButton extends HTMLButtonElement  {
  constructor() {
    super();

    this.addEventListener('click', () => {
      console.log('clicked');
    });
  }
}

customElements.define('custom-button', CustomButton, { extends: "button" });


1 commentaires

J'ai spécifiquement souligné que je cherchais une solution sans surcharger le constructeur. En définissant la fonction onclick je devrais définir ce qui est essentiellement l'attribut d'événement onclick . Ce qui fonctionne bien si je le déclare dans my-button comme une balise HTML, pas via JavaScript.



0
votes

Tout ce que vous avez vraiment fait est de créer une propriété onclick pour votre élément personnalisé et de lui attribuer une fonction. Ce n'est pas parce qu'il est nommé onclick que le système sait qu'il s'agit d'un événement click parce que vous créez votre propre élément. Vous devrez créer un événement personnalisé pour votre élément personnalisé.


1 commentaires

Merci pour votre temps! Comme vu dans l'édition 2, s'il est ajouté en tant que propriété, le système sait qu'il s'agit d'un gestionnaire d'événements.



0
votes

Vous êtes très émoussé à attacher tous les gestionnaires qui commencent par le

Devinez combien il pourrait y en avoir:

document.body.append(
  ...Object.getOwnPropertyNames(window).filter(prop => prop.indexOf("on") === 0)
  .map((prop, idx, arr) => {
    let div = document.createElement("div");
    div.innerHTML = `${arr.length-idx} &nbsp; ${prop}`;
    return div;
  }));

Vous n'êtes pas obligé d'utiliser addEventListener ;

L'utilisation du ( ancien ) gestionnaire this.onclick= dans Components peut être plus flexible,
car l'utilisateur du composant peut facilement l'écraser.
Avec addEventListener l' auteur du composant doit fournir une méthode removeListener ; sinon l'utilisateur ne peut pas supprimer un écouteur.

Informations sur les différents modèles d'événements JavaScript:


1 commentaires

Comme indiqué dans les commentaires, il s'agit d'une utilisation inappropriée de mon exemple. Essayez de l'exécuter sur window.constructor.prototype et voyez combien il y en a.