Qu'est-ce que le bouillonnement et la capture d'événements?

Réponses:

1441

La propagation et la capture d'événements sont deux façons de propager un événement dans l'API HTML DOM, lorsqu'un événement se produit dans un élément à l'intérieur d'un autre élément et que les deux éléments ont enregistré un descripteur pour cet événement. Le mode de propagation d'événement détermine dans quel ordre les éléments reçoivent l'événement .

Avec le bouillonnement, l'événement est d'abord capturé et géré par l'élément le plus interne, puis propagé aux éléments externes.

Avec la capture, l'événement est d'abord capturé par l'élément le plus externe et propagé aux éléments internes.

La capture est également appelée "ruissellement", ce qui permet de se souvenir de l'ordre de propagation:

ruisseler, bouillonner

À l'époque, Netscape préconisait la capture d'événements, tandis que Microsoft encourageait la propagation d'événements. Les deux font partie de la norme W3C Document Object Model Events (2000).

IE <9 n'utilise que la propagation d'événements , tandis qu'IE9 + et tous les principaux navigateurs prennent en charge les deux. D'un autre côté, les performances de la propagation d'événements peuvent être légèrement inférieures pour les DOM complexes.

Nous pouvons utiliser le addEventListener(type, listener, useCapture)pour enregistrer les gestionnaires d'événements en mode de propagation (par défaut) ou de capture. Pour utiliser le modèle de capture, passez le troisième argument en tant que true.

Exemple

<div>
    <ul>
        <li></li>
    </ul>
</div>

Dans la structure ci-dessus, supposez qu'un événement de clic s'est produit dans l' liélément.

Dans la capture modèle, l'événement sera assurée par les divpremiers (clic gestionnaires d'événements dans le divsera tout d' abord le feu), puis dans le ul, puis au dernier dans l'élément cible, li.

Dans le modèle bouillonnant, l'inverse se produira: l'événement sera d'abord géré par le li, puis par le ul, et enfin par l' divélément.

Pour plus d'informations, voir

Dans l'exemple ci-dessous, si vous cliquez sur l'un des éléments en surbrillance, vous pouvez voir que la phase de capture du flux de propagation d'événement se produit en premier, suivie de la phase de propagation.

var logElement = document.getElementById('log');

function log(msg) {
    logElement.innerHTML += ('<p>' + msg + '</p>');
}

function capture() {
    log('capture: ' + this.firstChild.nodeValue.trim());
}

function bubble() {
    log('bubble: ' + this.firstChild.nodeValue.trim());
}

function clearOutput() {
    logElement.innerHTML = "";
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
    divs[i].addEventListener('click', capture, true);
    divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
    line-height: 0;
}

div {
    display:inline-block;
    padding: 5px;

    background: #fff;
    border: 1px solid #aaa;
    cursor: pointer;
}

div:hover {
    border: 1px solid #faa;
    background: #fdd;
}
<div>1
    <div>2
        <div>3
            <div>4
                <div>5</div>
            </div>
        </div>
    </div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>

Un autre exemple chez JSFiddle .

Arun P Johny
la source
41
useCapturedésormais supporté dans IE> = 9. source
beatgammit
7
Je sais qu'il est trop tard pour mettre un commentaire mais un bel article que j'ai trouvé ici catcode.com/domcontent/events/capture.html
Juste coder
3
Est-ce triclklingla même chose que capturing? Crockford en parle Trickling v. Bubblingdans cette conversation vidéo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB autour 1 hr 5 minutes.
Kevin Meredith
1
@KevinMeredith Même chose. "Trickling" permet simplement de se souvenir plus facilement de ce que font les deux modèles (goutte à goutte , bulle vers le haut ).
un chat
7
La réponse ci-dessus est correcte en ce qui concerne l'ordre dans l'explication détaillée, mais vous laisse penser que le filet se produit en second avec "bulle vers le haut, filet vers le bas". Les événements passent toujours par la phase de capture avant la phase de bulle. L'ordre correct est trickle down=> onElement=>bubble up
runspired
513

La description:

quirksmode.org en a une belle description. En un mot (copié à partir de quirksmode):

Capture d'événement

Lorsque vous utilisez la capture d'événements

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

le gestionnaire d'événements de element1 se déclenche en premier, le gestionnaire d'événements de element2 se déclenche en dernier.

Bulle d'événement

Lorsque vous utilisez le bouillonnement d'événements

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

le gestionnaire d'événements de element2 se déclenche en premier, le gestionnaire d'événements de element1 se déclenche en dernier.


Que faut-il utiliser?

Cela dépend de ce que vous voulez faire. Il n'y a rien de mieux. La différence est l'ordre d'exécution des gestionnaires d'événements. La plupart du temps, il sera bon de déclencher des gestionnaires d'événements dans la phase de propagation , mais il peut également être nécessaire de les déclencher plus tôt.

Felix Kling
la source
N'arrive-t-il pas tous les deux, d'abord la capture puis le bouillonnement, qu'est-ce qu'un événement de répartition?
Suraj Jain
un exemple graphique est ici: javascript.info/bubbling-and-capturing
Community Ans
71

S'il y a deux éléments, l'élément 1 et l'élément 2. L'élément 2 est à l'intérieur de l'élément 1 et nous attachons un gestionnaire d'événements avec les deux éléments, disons onClick. Maintenant, lorsque nous cliquons sur l'élément 2, eventHandler pour les deux éléments sera exécuté. Maintenant, la question est de savoir dans quel ordre l'événement s'exécutera. Si l'événement attaché à l'élément 1 s'exécute en premier, il est appelé capture d'événement et si l'événement attaché à l'élément 2 s'exécute en premier, cela s'appelle la propagation d'événement. Selon le W3C, l'événement commencera dans la phase de capture jusqu'à ce qu'il atteigne la cible revient à l'élément, puis il commence à bouillonner

Les états de capture et de propagation sont connus par le paramètre useCapture de la méthode addEventListener

eventTarget.addEventListener (type, écouteur, [, useCapture]);

Par défaut, useCapture est faux. Cela signifie qu'il est en phase bouillonnante.

var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");

div1.addEventListener("click", function (event) {
  alert("you clicked on div 1");
}, true);

div2.addEventListener("click", function (event) {
  alert("you clicked on div 2");
}, false);
#div1{
  background-color:red;
  padding: 24px;
}

#div2{
  background-color:green;
}
<div id="div1">
  div 1
  <div id="div2">
    div 2
  </div>
</div>

Veuillez essayer de changer vrai et faux.

dinesh_malhotra
la source
2
@masterxilo: pas besoin de Fiddle, StackOverflow prend désormais en charge le code en ligne (extraits de pile) .
Dan Dascalescu
Concernant the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling. J'ai seulement trouvé que addEventListener a le paramètre useCapturequi peut être défini sur true ou false; et en HTML 4.0, les écouteurs d'événement étaient spécifiés comme attributs d'un élément et useCapture defaults to false. Pourriez-vous créer un lien vers une spécification qui confirme ce que vous avez écrit?
surfmuggle
25

J'ai trouvé ce tutoriel sur javascript.info très clair pour expliquer ce sujet. Et son résumé en 3 points à la fin parle vraiment des points cruciaux. Je le cite ici:

  1. Les événements sont d'abord capturés jusqu'à la cible la plus profonde, puis bouillonnent. Dans IE <9, ils ne font que bouillonner.
  2. Tous les gestionnaires travaillent sur les exemptions d'étape bouillonnantes addEventListeneravec le dernier argument true, qui est le seul moyen d'attraper l'événement lors de la capture de l'étape.
  3. Le bullage / capture peut être arrêté par event.cancelBubble=true(IE) ou event.stopPropagation() pour d'autres navigateurs.
gm2008
la source
7

Il y a aussi le Event.eventPhase propriété qui peut vous dire si l'événement est sur la cible ou vient d'ailleurs.

Notez que la compatibilité du navigateur n'est pas encore déterminée. Je l'ai testé sur Chrome (66.0.3359.181) et Firefox (59.0.3) et il y est pris en charge.

Développer sur l' extrait déjà grand de la réponse acceptée , c'est la sortie en utilisant la eventPhasepropriété

var logElement = document.getElementById('log');

function log(msg) {
  if (logElement.innerHTML == "<p>No logs</p>")
    logElement.innerHTML = "";
  logElement.innerHTML += ('<p>' + msg + '</p>');
}

function humanizeEvent(eventPhase){
  switch(eventPhase){
    case 1: //Event.CAPTURING_PHASE
      return "Event is being propagated through the target's ancestor objects";
    case 2: //Event.AT_TARGET
      return "The event has arrived at the event's target";
    case 3: //Event.BUBBLING_PHASE
      return "The event is propagating back up through the target's ancestors in reverse order";
  }
}
function capture(e) {
  log('capture: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

function bubble(e) {
  log('bubble: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
  divs[i].addEventListener('click', capture, true);
  divs[i].addEventListener('click', bubble, false);
}
p {
  line-height: 0;
}

div {
  display:inline-block;
  padding: 5px;

  background: #fff;
  border: 1px solid #aaa;
  cursor: pointer;
}

div:hover {
  border: 1px solid #faa;
  background: #fdd;
}
<div>1
  <div>2
    <div>3
      <div>4
        <div>5</div>
      </div>
    </div>
  </div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>

Adelin
la source
5

Bouillonnant

  Event propagate to the upto root element is **BUBBLING**.

Capture

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Kondal
la source