web-dev-qa-db-fra.com

Impossible de comprendre le paramètre useCapture dans addEventListener

J'ai lu l'article sur https://developer.mozilla.org/en/DOM/element.addEventListener mais incapable de comprendre l'attribut useCapture. Définition il y a:

Si la valeur est true, useCapture indique que l'utilisateur souhaite lancer la capture. Après avoir lancé la capture, tous les événements du type spécifié seront envoyés à l’auditeur enregistré avant d’être envoyés à tous les EventTargets situés en dessous dans l’arbre DOM. Les événements qui remontent dans l'arborescence ne déclencheront pas un écouteur désigné pour utiliser la capture.

Dans ce code, l'événement parent est déclenché avant l'enfant. Je ne suis donc pas en mesure de comprendre son comportement. L'objet document a usecapture true et l'enfant div a usecapture défini sur false et l'objet usecapture est suivi.Pourquoi la propriété de document est préférée à enfant.

function load() {
  document.addEventListener("click", function() {
    alert("parent event");
  }, true);

  document.getElementById("div1").addEventListener("click", function() {
    alert("child event");
  }, false);
}
<body onload="load()">
  <div id="div1">click me</div>
</body>
274
user26732

Les événements peuvent être activés à deux occasions: au début ("capture") et à la fin ("bulle"). Les événements sont exécutés dans l'ordre de leur définition. Dites, vous définissez 4 auditeurs d'événement:

window.addEventListener("click", function(){alert(1)}, false);
window.addEventListener("click", function(){alert(2)}, true);
window.addEventListener("click", function(){alert(3)}, false);
window.addEventListener("click", function(){alert(4)}, true);

Les boîtes d’alerte apparaîtront dans cet ordre:

  • 2 (défini en premier à l'aide de capture=true)
  • 4 (défini en deuxième à l'aide de capture=true)
  • 1 (premier événement défini avec capture=false)
  • 3 (deuxième événement défini avec capture=false)
330
Rob W

Je trouve ce diagramme très utile pour comprendre les phases de capture/cible/bulle: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html # Événements-phases

Ci-dessous, contenu extrait du lien.

Phases

L'événement est distribué en suivant un chemin d'accès depuis la racine de l'arborescence vers ce nœud cible. Il peut ensuite être géré localement au niveau du nœud cible ou des ancêtres de la cible situés plus haut dans l'arborescence. L'envoi d'événements (également appelé propagation d'événements) se déroule en trois phases et dans l'ordre suivant:

  1. La phase de capture: l'événement est envoyé aux ancêtres de la cible depuis la racine de l'arbre jusqu'au parent direct du nœud cible.
  2. La phase cible: l'événement est envoyé au nœud cible.
  3. La phase de bullage: l'événement est envoyé aux ancêtres de la cible du parent direct du nœud cible à la racine de l'arbre.

graphical representation of an event dispatched in a DOM tree using the DOM event flow

Les ancêtres de la cible sont déterminés avant l'envoi initial de l'événement. Si le nœud cible est supprimé lors de la répartition ou si un ancêtre de cible est ajouté ou supprimé, la propagation d'événement sera toujours basée sur le nœud cible et les ancêtres de la cible déterminés avant la répartition.

Certains événements peuvent ne pas nécessairement accomplir les trois phases du flux d'événements DOM, par exemple. l'événement ne peut être défini que pour une ou deux phases. Par exemple, les événements définis dans cette spécification accomplissent toujours les phases de capture et de cible, mais certains n'effectuent pas la phase de bullage ("événements de bullage" ou "événements non-bouillonnants", voir aussi l'attribut Event.bubbles).

255
lax4mike

Evénement de capture (useCapture = true) vs événement de bulle (useCapture = false)

référence MDN

  • L'événement de capture sera envoyé avant l'événement de bulle
  • L'ordre de propagation des événements est [.____].
    1. Capture du parent
    2. Capture d'enfants
    3. Capture de cible et bulle cible
      • Dans l'ordre où ils ont été enregistrés
      • Lorsque l'élément est la cible de l'événement, le paramètre useCapture n'a pas d'importance (Merci @bam et @ legend80s)
    4. Bulle enfants
    5. Bulle parent
  • stopPropagation() va arrêter le flux

use Capture flow

Démo

Résultat:

  1. Capture du parent
  2. Enfants bulle 1
  3. Capture d'enfants

    (Parce que Children est la cible, Capture et Bubble se déclenchent dans l'ordre dans lequel ils ont été enregistrés.)

  4. Enfants bulle 2
  5. Bulle parent
var parent = document.getElementById('parent'),
    children = document.getElementById('children');

children.addEventListener('click', function (e) { 
    alert('Children Bubble 1');
    // e.stopPropagation();
}, false);

children.addEventListener('click', function (e) { 
    alert('Children Capture');
    // e.stopPropagation();
}, true);

children.addEventListener('click', function (e) { 
    alert('Children Bubble 2');
    // e.stopPropagation();
}, false);

parent.addEventListener('click', function (e) { 
    alert('Parent Capture');
    // e.stopPropagation();
}, true);

parent.addEventListener('click', function (e) { 
    alert('Parent Bubble');
    // e.stopPropagation();
}, false);
<div id="parent">
    <div id="children">
        Click
    </div>
</div>
70
Steely Wing

Lorsque vous dites useCapture = true, les événements s'exécutent de haut en bas dans la phase de capture. Lorsque la valeur est false, une bulle s'affiche de bas en haut.

14
sushil bharwani

Exemple de code:

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>

Code Javascript:

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");

si les deux sont définis sur false

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);

Exécute: En cliquant sur Div. Intérieure, les alertes sont affichées sous la forme: Div 2> Div 1

Ici, le script est exécuté à partir de l'élément interne: Event Bubbling (useCapture a la valeur false)

div 1 est défini sur true et div 2 sur false

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},false);

Exécute: En cliquant sur Div. Intérieure, les alertes sont affichées sous la forme: Div 1> Div 2

Ici, le script est exécuté à partir de l'élément ancestor/outer: Event Capturing (useCapture a été défini sur true)

div 1 est défini sur false et div 2 sur true

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},true);

Exécute: En cliquant sur Div. Intérieure, les alertes sont affichées sous la forme: Div 2> Div 1

Ici, le script est exécuté à partir de l'élément interne: Event Bubbling (useCapture a la valeur false)

div 1 est défini sur true et div 2 sur true

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);

Exécute: En cliquant sur Div. Intérieure, les alertes sont affichées sous la forme: Div 1> Div 2

Ici, le script est exécuté à partir de l'élément ancestor/outer: Event Capturing depuis que useCapture a été défini sur true

11
shadowBot

Tout est une question de modèles d'événement: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow Vous pouvez capturer un événement en phase de formation ou en capture phase. Votre choix.
Regardez http://www.quirksmode.org/js/events_order.html - vous le trouverez très utile.

10
NilColor

Sommaire:

La spécification DOM décrite dans:

https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

fonctionne de la manière suivante:

Un événement est envoyé en suivant un chemin allant de la racine (document) de l’arbre au noeud cible . Le nœud cible est l’élément HTML le plus profond, c’est-à-dire l’événement.target. L'envoi d'événements (également appelé propagation d'événements) se déroule en trois phases et dans l'ordre suivant:

  1. La phase de capture: l'événement est envoyé aux ancêtres de la cible depuis la racine de l'arbre (document) jusqu'au parent direct de la cible. nœud.
  2. La phase cible: l'événement est envoyé au noeud cible. La phase cible se situe toujours sur l'élément html le plus profond sur lequel l'événement a été déclenché.
  3. La phase de bullage: l'événement est envoyé aux ancêtres de la cible depuis le parent direct du nœud cible jusqu'à la racine de l'arbre.

Event bubbling, event capturing, event target

Exemple:

_// bubbling handlers, third argument (useCapture) false (default)
document.getElementById('outerBubble').addEventListener('click', () => {
  console.log('outerBubble');
}, false)

document.getElementById('innerBubble').addEventListener('click', () => {
  console.log('innerBubble');
}, false)


// capturing handlers, third argument (useCapture)  true
document.getElementById('outerCapture').addEventListener('click', () => {
  console.log('outerCapture');
}, true)

document.getElementById('innerCapture').addEventListener('click', () => {
  console.log('innerCapture');
}, true)_
_div:hover{
  color: red;
  cursor: pointer;
}_
_<!-- event bubbling -->
<div id="outerBubble">
  <div id="innerBubble">click me to see Bubbling</div>
</div>


<!-- event capturing -->
<div id="outerCapture">
  <div id="innerCapture">click me to see Capturing</div>
</div>_

L'exemple ci-dessus illustre vraiment la différence entre la diffusion d'événements et la capture d'événements. Lors de l'ajout des écouteurs d'événement avec addEventListener, il existe un troisième élément appelé useCapture. Ceci est un boolean qui, lorsqu'il est défini sur true, permet à l'écouteur d'événements d'utiliser la capture d'événements au lieu de la diffusion d'événements.

Dans notre exemple, lorsque nous définissons l'argument useCapture sur false, nous voyons que l'événement est propagé. Tout d'abord, l'événement de la phase cible est déclenché (logs innerBubble), puis via l'événement bullant, l'événement de l'élément parent est déclenché (logs outerBubble).

Lorsque nous définissons l’argument useCapture sur true, nous constatons que l’événement de _<div>_ extérieur est déclenché en premier. En effet, l'événement est maintenant déclenché dans la phase de capture et non dans la phase de formation de bulles.

6
Willem van der Veen

Étant donné les trois phases de l’événement , voyager :

  1. La phase de capture : l'événement est envoyé aux ancêtres de la cible depuis la racine de l'arbre jusqu'au parent direct du noeud cible.
  2. La phase cible : l'événement est envoyé au nœud cible.
  3. La phase de bullage : l'événement est envoyé aux ancêtres de la cible depuis le parent direct du noeud cible jusqu'à la racine de l'arbre.

useCapture indique pour quelles phases l'événement se déroulera :

Si true, useCapture indique que l'utilisateur souhaite ajouter l'écouteur d'événements pour la phase de capture uniquement, c'est-à-dire que cet écouteur d'événements ne sera pas déclenché. au cours de la cible et des phases de bullage. Si false, l'écouteur d'événements ne sera déclenché que pendant les phases cible et de propagation.

La source est la même que la deuxième meilleure réponse: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

6
Aurimas

L'ordre de définition n'a d'importance que si les éléments sont au même niveau. Si vous inversez l'ordre de définition dans votre code, vous obtiendrez les mêmes résultats.

Toutefois, si vous inversez le paramètre useCapture sur les deux gestionnaires d'événements, le gestionnaire d'événements enfants répond avant celui du parent. La raison en est que le gestionnaire d'événements enfants sera maintenant déclenché dans la phase de capture qui est antérieure à la phase de propagation dans laquelle le gestionnaire d'événements parent sera déclenché.

Si vous définissez useCapture sur true pour les deux gestionnaires d'événements, quel que soit l'ordre de définition, le gestionnaire d'événements parent sera déclenché en premier, car il est placé avant l'enfant dans la phase de capture.

Inversement, si vous définissez useCapture sur false pour les deux gestionnaires d'événements, là encore quel que soit l'ordre de définition, le gestionnaire d'événements enfant sera déclenché en premier car il est placé avant le parent en phase de propagation.

1
WXB13