D'où cela vient
Quand j'ai appris jQuery pour la première fois, j'attachais normalement des événements comme celui-ci:
$('.my-widget a').click(function() {
$(this).toggleClass('active');
});
Après en avoir appris davantage sur la vitesse du sélecteur et la délégation d'événements, j'ai lu à plusieurs endroits que «la délégation d'événements jQuery rendra votre code plus rapide». J'ai donc commencé à écrire du code comme celui-ci:
$('.my-widget').on('click','a',function() {
$(this).toggleClass('active');
});
C'était également la méthode recommandée pour répliquer le comportement de l'événement obsolète .live (). Ce qui est important pour moi car beaucoup de mes sites ajoutent / suppriment dynamiquement des widgets tout le temps. Ce qui précède ne se comporte pas exactement comme .live (), puisque seuls les éléments ajoutés au conteneur déjà existant '.my-widget' obtiendront le comportement. Si j'ajoute dynamiquement un autre bloc de html après l'exécution de ce code, ces éléments ne recevront pas les événements qui leur sont liés. Comme ça:
setTimeout(function() {
$('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);
Ce que je veux réaliser:
- l'ancien comportement de .live () // signifiant attacher des événements à des éléments qui n'existent pas encore
- les avantages de .on ()
- performances les plus rapides pour lier des événements
- Un moyen simple de gérer les événements
J'attache maintenant tous les événements comme celui-ci:
$(document).on('click.my-widget-namespace', '.my-widget a', function() {
$(this).toggleClass('active');
});
Ce qui semble répondre à tous mes objectifs. (Oui, c'est plus lent dans IE pour une raison quelconque, je ne sais pas pourquoi?) C'est rapide car un seul événement est lié à un élément singulier et le sélecteur secondaire n'est évalué que lorsque l'événement se produit (veuillez me corriger si cela ne va pas ici). L'espace de noms est génial car il facilite le basculement de l'écouteur d'événements.
Ma solution / question
Je commence donc à penser que les événements jQuery devraient toujours être liés à $ (document).
Y a-t-il une raison pour laquelle vous ne voudriez pas faire cela?
Cela pourrait-il être considéré comme une meilleure pratique? Si non, pourquoi?
Si vous avez lu tout cela, merci. J'apprécie tous / tous les commentaires / idées.
Hypothèses:
- Utilisation de jQuery qui prend en charge
.on()
// au moins la version 1.7 - Vous voulez que l'événement soit ajouté au contenu ajouté dynamiquement
Lectures / Exemples:
Réponses:
Non - vous ne devez PAS lier tous les gestionnaires d'événements délégués à l'
document
objet. C'est probablement le scénario le moins performant que vous puissiez créer.Tout d'abord, la délégation d'événements ne rend pas toujours votre code plus rapide. Dans certains cas, c'est avantageux et dans certains cas non. Vous devez utiliser la délégation d'événements lorsque vous avez réellement besoin d'une délégation d'événements et lorsque vous en bénéficiez. Sinon, vous devez lier les gestionnaires d'événements directement aux objets où l'événement se produit, car cela sera généralement plus efficace.
Deuxièmement, vous ne devez PAS lier tous les événements délégués au niveau du document. C'est exactement pourquoi a
.live()
été déconseillé car cela est très inefficace lorsque de nombreux événements sont liés de cette manière. Pour la gestion déléguée des événements, il est BEAUCOUP plus efficace de les lier au parent le plus proche qui n'est pas dynamique.Troisièmement, tous les événements ne fonctionnent pas ou tous les problèmes peuvent être résolus par délégation. Par exemple, si vous souhaitez intercepter des événements clés sur un contrôle d'entrée et empêcher la saisie de clés non valides dans le contrôle d'entrée, vous ne pouvez pas le faire avec la gestion déléguée des événements car au moment où l'événement remonte jusqu'au gestionnaire délégué, il a déjà été traité par le contrôle d'entrée et il est trop tard pour influencer ce comportement.
Voici les moments où la délégation d'événements est requise ou avantageuse:
Pour comprendre un peu plus cela, il faut comprendre comment fonctionnent les gestionnaires d'événements délégués jQuery. Lorsque vous appelez quelque chose comme ça:
Il installe un gestionnaire d'événements jQuery générique sur l'
#myParent
objet. Lorsqu'un événement de clic atteint ce gestionnaire d'événements délégué, jQuery doit parcourir la liste des gestionnaires d'événements délégués attachés à cet objet et voir si l'élément d'origine de l'événement correspond à l'un des sélecteurs dans les gestionnaires d'événements délégués.Étant donné que les sélecteurs peuvent être assez impliqués, cela signifie que jQuery doit analyser chaque sélecteur, puis le comparer aux caractéristiques de la cible d'événement d'origine pour voir s'il correspond à chaque sélecteur. Ce n'est pas une opération bon marché. Ce n'est pas grave s'il n'y en a qu'un, mais si vous placez tous vos sélecteurs sur l'objet document et qu'il y avait des centaines de sélecteurs à comparer à chaque événement bouillonnant, cela peut sérieusement commencer à entraver les performances de gestion des événements.
Pour cette raison, vous souhaitez configurer vos gestionnaires d'événements délégués afin qu'un gestionnaire d'événements délégués soit aussi proche que possible de l'objet cible. Cela signifie que moins d'événements apparaîtront dans chaque gestionnaire d'événements délégué, améliorant ainsi les performances. Placer tous les événements délégués sur l'objet document est la pire performance possible, car tous les événements à bulles doivent passer par tous les gestionnaires d'événements délégués et être évalués par rapport à tous les sélecteurs d'événements délégués possibles. C'est exactement pourquoi
.live()
est obsolète parce que c'est ce qui a.live()
fait et cela s'est avéré très inefficace.Donc, pour obtenir des performances optimisées:
la source
$(document).on('click', '[myCustomAttr]', function () { ... });
?document
, ou de lier à des sélections plus spécifiques surpage:load
et de dissocier ces événements surpage:after-remove
? HmmmLa délégation d'événements est une technique pour écrire vos gestionnaires avant que l'élément n'existe réellement dans DOM. Cette méthode a ses propres inconvénients et ne doit être utilisée que si vous avez de telles exigences.
Quand devriez-vous utiliser la délégation d'événements?
Pourquoi vous ne devriez pas utiliser la délégation d'événements?
PS: Même pour les contenus dynamiques, vous n'avez pas besoin d'utiliser la méthode de délégation d'événements si vous liez le gestionnaire après que le contenu est inséré dans DOM. (Si le contenu dynamique n'est pas souvent ajouté / supprimé)
la source
Apparemment, la délégation d'événements est actuellement recommandée. au moins pour vanilla js.
https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-vanilla-js/
"Performances Web # On a l'impression qu'écouter chaque clic dans le document serait mauvais pour les performances, mais c'est en fait plus performant que d'avoir un groupe d'écouteurs d'événements sur des éléments individuels."
la source
Je voudrais ajouter quelques remarques et contre-arguments à la réponse de jfriend00. (principalement juste mes opinions basées sur mon instinct)
Bien qu'il soit vrai que les performances pourraient être légèrement meilleures si vous ne vous enregistrez et n'organisez un événement que pour un seul élément, je pense que cela ne compense pas les avantages d'évolutivité que la délégation apporte. Je pense également que les navigateurs vont (vont) gérer cela de plus en plus efficacement, même si je n'en ai aucune preuve. À mon avis, la délégation d'événements est la voie à suivre!
Je suis plutôt d'accord là-dessus. Si vous êtes sûr à 100% qu'un événement ne se produira qu'à l'intérieur d'un conteneur, il est logique de lier l'événement à ce conteneur, mais je serais toujours contre la liaison d'événements à l'élément déclencheur directement.
Ce n'est tout simplement pas vrai. Veuillez consulter ce codePen: https://codepen.io/pwkip/pen/jObGmjq
Il illustre comment vous pouvez empêcher un utilisateur de taper en enregistrant l'événement keypress sur le document.
Je voudrais répondre avec cette citation de https://ehsangazar.com/optimizing-javascript-event-listeners-for-performance-e28406ad406c
Event delegation promotes binding as few DOM event handlers as possible, since each event handler requires memory. For example, let’s say that we have an HTML unordered list we want to bind event handlers to. Instead of binding a click event handler for each list item (which may be hundreds for all we know), we bind one click handler to the parent unordered list itself.
De plus, rechercher sur Google
performance cost of event delegation google
renvoie plus de résultats en faveur de la délégation d'événements.Où est-ce documenté? Si c'est vrai, alors jQuery semble gérer la délégation de manière très inefficace, et mes contre-arguments ne devraient être appliqués qu'à vanilla JS.
Pourtant: j'aimerais trouver une source officielle soutenant cette affirmation.
:: ÉDITER ::
On dirait que jQuery fait effectivement des bulles d'événements de manière très inefficace (car ils prennent en charge IE8) https://api.jquery.com/on/#event-performance
Donc, la plupart de mes arguments ici ne sont valables que pour JS vanilla et les navigateurs modernes.
la source