Cos'è il bubbling e l'acquisizione di eventi?


Risposte:


1441

Il bubbling e l'acquisizione di eventi sono due modi di propagazione degli eventi nell'API DOM HTML, quando si verifica un evento in un elemento all'interno di un altro elemento ed entrambi gli elementi hanno registrato un handle per quell'evento. La modalità di propagazione dell'evento determina in quale ordine gli elementi ricevono l'evento .

Con il gorgoglio, l'evento viene prima catturato e gestito dall'elemento più interno e quindi propagato agli elementi esterni.

Con l'acquisizione, l'evento viene prima catturato dall'elemento più esterno e propagato agli elementi interni.

Catturare è anche chiamato "gocciolamento", che aiuta a ricordare l'ordine di propagazione:

gocciolare, bolla

Ai vecchi tempi, Netscape sosteneva la cattura di eventi, mentre Microsoft promuoveva il gorgoglio degli eventi. Entrambi fanno parte dello standard W3C Document Object Model Events (2000).

IE <9 utilizza solo il bubbling di eventi , mentre IE9 + e tutti i principali browser supportano entrambi. D'altro canto, le prestazioni del gorgogliamento degli eventi potrebbero essere leggermente inferiori per DOM complessi.

Possiamo usare il addEventListener(type, listener, useCapture)per registrare i gestori di eventi sia in modalità bubbling (impostazione predefinita) sia in modalità acquisizione. Per utilizzare il modello di acquisizione, passare il terzo argomento come true.

Esempio

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

Nella struttura sopra, supponi che si sia verificato un evento click linell'elemento.

A catturare il modello, l'evento sarà gestito dai divprimi (gestori di eventi fare clic nella divsparerà prima), poi in ul, poi all'ultimo nell'elemento di destinazione, li.

Nel modello gorgogliante, accadrà il contrario: l'evento verrà prima gestito dall'elemento li, quindi dall'elemento ule infine divdall'elemento.

Per ulteriori informazioni, vedere

Nell'esempio seguente, se si fa clic su uno degli elementi evidenziati, si può vedere che si verifica prima la fase di acquisizione del flusso di propagazione degli eventi, seguita dalla fase di bolle.

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 altro esempio di JSFiddle .


41
useCaptureora supportato in IE> = 9. source
beatgammit

7
So che è troppo tardi per inserire un commento, ma un bell'articolo che ho trovato qui catcode.com/domcontent/events/capture.html
Solo codice

3
È triclklinglo stesso di capturing? Crockford parla di Trickling v. Bubblingquesto video: youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB in giro 1 hr 5 minutes.
Kevin Meredith,

1
@KevinMeredith Stessa cosa. "Trickling" rende solo più facile da ricordare quello che i due modelli non (trickle giù , bolla in su ).
un gatto

7
La risposta sopra è corretta per quanto riguarda l'ordine nella spiegazione dettagliata, ma ti lascia pensare che il gocciolamento si verifichi secondo con "bolle su, gocce". Gli eventi passano sempre attraverso la fase di acquisizione prima della fase a bolle. L'ordine corretto è trickle down=> onElement=>bubble up
eseguito il

513

Descrizione:

quirksmode.org ha una bella descrizione di questo. In breve (copiato dalla modalità quirks):

Cattura di eventi

Quando si utilizza l'acquisizione di eventi

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

il gestore eventi di element1 viene attivato per primo, il gestore eventi di element2 viene attivato per ultimo.

Bolle di eventi

Quando si utilizza il gorgoglio degli eventi

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

il gestore di eventi di element2 viene attivato per primo, il gestore di eventi di element1 viene attivato per ultimo.


Cosa usare?

Dipende da quello che vuoi fare. Non c'è di meglio. La differenza sta nell'ordine di esecuzione dei gestori di eventi. Il più delle volte andrà bene licenziare i gestori di eventi nella fase gorgogliante , ma può anche essere necessario licenziarli prima.


Non accade entrambi, prima catturando e poi gorgogliando, anche cos'è l'evento di spedizione?
Suraj Jain,


71

Se ci sono due elementi elemento 1 ed elemento 2. L'elemento 2 è all'interno dell'elemento 1 e associamo un gestore eventi con entrambi gli elementi, diciamo onClick. Ora, quando facciamo clic sull'elemento 2, verrà eseguito eventHandler per entrambi gli elementi. Ora qui la domanda è in quale ordine verrà eseguito l'evento. Se l'evento associato con l'elemento 1 viene eseguito per primo, viene chiamato cattura degli eventi e se l'evento associato con l'elemento 2 viene eseguito per primo, viene chiamato bubbling di eventi. Come da W3C, l'evento inizierà nella fase di acquisizione fino a quando non raggiungerà il bersaglio e tornerà all'elemento

Gli stati di acquisizione e bubbling sono conosciuti dal parametro useCapture del metodo addEventListener

eventTarget.addEventListener (tipo, ascoltatore, [, useCapture]);

Per impostazione predefinita useCapture è falso. Significa che è nella fase gorgogliante.

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>

Prova a cambiare il vero e il falso.


2
@masterxilo: nessuna necessità di Fiddle, StackOverflow ora supporta il codice incorporato (frammenti di stack) .
Dan Dascalescu il

Per quanto riguarda the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling. Ho trovato solo che addEventListener ha il parametro useCaptureche può essere impostato su true o false; e in HTML 4.0, i listener di eventi sono stati specificati come attributi di un elemento e useCapture defaults to false. Potresti collegarti a una specifica che conferma ciò che hai scritto?
surfmuggle,

25

Ho trovato questo tutorial su javascript.info per essere molto chiaro nello spiegare questo argomento. E il suo sommario di 3 punti alla fine parla davvero con i punti cruciali. Lo cito qui:

  1. Gli eventi vengono prima catturati fino al bersaglio più profondo, quindi si gonfiano. In IE <9 fanno solo bolle.
  2. Tutti gli handler lavorano su scenari gorgoglianti, addEventListenercon l'ultimo argomentotrue , che è l'unico modo per catturare l'evento sul palco di acquisizione.
  3. Il bubbling / acquisizione può essere fermato da event.cancelBubble=true(IE) o event.stopPropagation() per altri browser.

7

C'è anche la Event.eventPhaseproprietà che può dirti se l'evento è a destinazione o proviene da qualche altra parte.

Si noti che la compatibilità del browser non è stata ancora determinata. L'ho provato su Chrome (66.0.3359.181) e Firefox (59.0.3) ed è supportato lì.

Espandendo il già grande snippet dalla risposta accettata , questo è l'output che utilizza la eventPhaseproprietà

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>


5

gorgogliante

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

cattura

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.