165 votes

Direct vs. délégué - jQuery .on()

J'essaie de comprendre cette différence particulière entre la direct y délégué à l'aide de la fonction jQuery .on() méthode . En particulier, la dernière phrase de ce paragraphe :

Lorsqu'un selector est fourni, le gestionnaire d'événement est appelé délégué . Le gestionnaire n'est pas appelé lorsque l'événement se produit directement sur l'élément lié, mais uniquement pour les descendants (éléments internes) qui correspondent au sélecteur. jQuery bulle l'événement depuis la cible de l'événement jusqu'à l'élément auquel le gestionnaire est attaché (c'est-à-dire de l'élément le plus interne à l'élément le plus externe) et exécute le gestionnaire pour tous les éléments le long de ce chemin qui correspondent au sélecteur.

Que signifie "exécute le gestionnaire pour tout élément" ? J'ai créé un page de test pour expérimenter le concept. Mais les deux constructions suivantes conduisent au même comportement :

$("div#target span.green").on("click", function() {
   alert($(this).attr("class") + " is clicked");
});

ou,

$("div#target").on("click", "span.green", function() {
   alert($(this).attr("class") + " is clicked");
});

Peut-être quelqu'un pourrait-il se référer à un autre exemple pour clarifier ce point ? Merci de votre compréhension.

7 votes

Pour tous les intéressés : jsperf.com/jquery-fn-on-delegate-vs-direct

1 votes

@KevinWheeler J'ai commenté votre violon ci-dessous mais ici En fait, il n'est pas correctement configuré (vous vous liez à l'élément parent, et la délégation est destinée aux enfants). Pour répondre à votre question, cela signifie que le gestionnaire délégué correspondra aux éléments nouvellement ajoutés, alors que celui qui n'est pas délégué ne le fera pas. La délégation présente l'avantage d'avoir moins d'événements accrochés au navigateur, ce qui réduit la consommation de mémoire pour l'application, mais la contrepartie est qu'elle augmente le temps de traitement d'un clic (de façon minimale). Si vous créez un jeu, ne déléguez pas.

1 votes

La "page de test" à laquelle vous faites référence ne fonctionne pas.

385voto

N3dst4 Points 2567

Cas 1 (direct) :

$("div#target span.green").on("click", function() {...});

\== Hey ! Je veux que chaque span.green à l'intérieur de div#target écoute : quand on clique sur toi, fais X.

Cas 2 (délégué) :

$("div#target").on("click", "span.green", function() {...});

\== Hey, div#target ! Lorsque l'un de vos éléments enfants qui sont "span.green" est cliqué, faites X avec lui.

En d'autres termes...

Dans le cas 1, chacune de ces travées a reçu des instructions individuelles. Si de nouvelles travées sont créées, elles n'auront pas entendu les instructions et ne répondront pas aux clics. Chaque travée est directement responsable pour ses propres événements.

Dans le cas 2, seul le conteneur a reçu l'instruction ; il est chargé de remarquer les clics au nom de ses éléments enfants. Le travail de capture des événements a été délégué . Cela signifie également que l'instruction sera exécutée pour les éléments enfants qui seront créés à l'avenir.

48 votes

C'est une excellente explication, qui a permis de clarifier une question que j'ai longtemps refusé de comprendre. Je vous remercie.

3 votes

Alors pourquoi l on() autorise deux arguments alors que cela reviendrait à utiliser click() ?

6 votes

.on() est une API générale qui peut gérer n'importe quel type d'événement, y compris plusieurs événements différents (vous pouvez mettre plusieurs noms d'événements dans cette première chaîne). .click() est juste un raccourci pour cette première forme.

6voto

nnnnnn Points 70578

La première voie, $("div#target span.green").on() lie un gestionnaire de clic directement au(x) span(s) qui correspond(ent) au sélecteur au moment où ce code est exécuté. Cela signifie que si d'autres travées sont ajoutées ultérieurement (ou si leur classe est modifiée pour correspondre), elles seront oubliées et n'auront pas de gestionnaire de clic. Cela signifie également que si vous supprimez ultérieurement la classe "verte" de l'une des travées, son gestionnaire de clic continuera à s'exécuter - jQuery ne garde pas trace de la manière dont le gestionnaire a été attribué et ne vérifie pas si le sélecteur correspond toujours.

La deuxième voie, $("div#target").on() lie un gestionnaire de clics à la (aux) div(s) qui correspond(ent) (encore une fois, il s'agit de celles qui correspondent à ce moment-là), mais lorsqu'un clic se produit quelque part dans la div, la fonction de gestion ne sera exécutée que si le clic s'est produit non seulement dans la div, mais aussi dans un élément enfant correspondant au sélecteur dans le deuxième paramètre de la fonction .on() , "span.green". De cette manière, la date de création de ces span enfants n'a pas d'importance, le fait de cliquer dessus lancera toujours le gestionnaire.

Ainsi, pour une page dont le contenu n'est pas dynamiquement ajouté ou modifié, vous ne remarquerez pas de différence entre les deux méthodes. Si vous ajoutez dynamiquement des éléments enfants supplémentaires, la seconde syntaxe signifie que vous n'avez pas à vous soucier de leur assigner des gestionnaires de clics parce que vous l'avez déjà fait une fois sur le parent.

5voto

Brynner Ferreira Points 318

L'explication de N3dst4 est parfaite. Sur cette base, nous pouvons supposer que tous les éléments enfants sont à l'intérieur du corps, et que nous ne devons donc utiliser que cela :

$('body').on('click', '.element', function(){
    alert('It works!')
});

Il fonctionne avec un événement direct ou délégué.

2 votes

Jquery déconseille d'utiliser body, car c'est plus lent, parce que le script devrait chercher tous les enfants à l'intérieur de body, ce qui devrait être beaucoup dans la plupart des cas. Il est préférable (plus rapide) d'utiliser le conteneur parent immédiat de l'élément.

1 votes

Jquery a supprimé la méthode live qui faisait la même chose que ce que vous avez montré. Cette méthode est peu performante et ne doit pas être utilisée.

0 votes

Dans les navigateurs modernes, $('body').on() délégation de .element devrait se comporter exactement de la même manière que les document.body.addEventHandler() avec un if (Event.target.className.matches(/\belement\b/)) dans le rappel. Cela peut être légèrement plus lent dans jquery à cause de $.proxy mais ne me citez pas sur ce point.

3voto

BobStein-VisiBone Points 398

En rapport avec l'OP, le concept qui m'a aidé à démêler la confusion avec cette fonctionnalité est le suivant les éléments liés doivent être les parents des éléments sélectionnés .

  • Le terme "lié" fait référence à ce qui reste de la .on .
  • Sélectionné se réfère au deuxième argument de .on() .

La délégation ne fonctionne pas comme .find(), en sélectionnant un sous-ensemble d'éléments liés. Le sélecteur ne s'applique qu'aux éléments enfants stricts.

$("span.green").on("click", ...

est très différent de

$("span").on("click", ".green", ...

En particulier, pour bénéficier des avantages auxquels @N3dst4 fait allusion avec les "éléments qui sont créés à l'avenir", l'élément lié doit être un parent permanent . Les enfants sélectionnés peuvent alors aller et venir.

EDIT

Liste de contrôle des raisons de la délégation .on ne fonctionne pas

Des raisons délicates $('.bound').on('event', '.selected', some_function) peut ne pas fonctionner :

  1. L'élément lié n'est pas permanent . Il a été créé après avoir appelé .on()
  2. L'élément sélectionné n'est pas un élément approprié enfant d'un élément lié. Il s'agit du même élément.
  3. Élément sélectionné empêché bouillonnement d'un événement à l'élément lié en appelant .stopPropagation() .

(En omettant les raisons moins délicates, comme un sélecteur mal orthographié).

2voto

fflorent Points 965

Considérez cette page :

http://jsfiddle.net/bNvhH/

J'utilise à la fois un gestionnaire d'événements direct et un gestionnaire d'événements délégué. Lorsque nous créons un autre élément span.green et que nous cliquons dessus, le gestionnaire d'événement délégué est déclenché alors que le gestionnaire d'événement direct ne l'est pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X