it-swarm.it

Impossibile comprendere il parametro useCapture in addEventListener

Ho letto l'articolo su https://developer.mozilla.org/en/DOM/element.addEventListener ma non riesco a capire l'attributo useCapture. Definizione c'è:

Se vero, useCapture indica che l'utente desidera avviare l'acquisizione. Dopo aver avviato l'acquisizione, tutti gli eventi del tipo specificato verranno inviati al listener registrato prima di essere inviati a qualsiasi EventTarget sotto di esso nella struttura DOM. Gli eventi che gorgogliano verso l'alto attraverso l'albero non attiveranno un ascoltatore designato a utilizzare l'acquisizione.

In questo codice l'evento genitore si attiva prima del figlio, quindi non sono in grado di comprenderne il comportamento. L'oggetto documento ha usecapture true e il div child ha usecapture impostato su false e viene seguita usecapture del documento. Pertanto, perché la proprietà document è preferita rispetto a child.

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>
270
user26732

Gli eventi possono essere attivati ​​in due occasioni: all'inizio ("cattura") e alla fine ("bolla"). Gli eventi vengono eseguiti nell'ordine in cui sono stati definiti. Supponiamo che tu definisca 4 ascoltatori di eventi:

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);

Le caselle di avviso verranno visualizzate in questo ordine:

  • 2 (definito per primo, usando capture=true)
  • 4 (definito secondo usando capture=true)
  • 1 (primo evento definito con capture=false)
  • 3 (secondo evento definito con capture=false)
328
Rob W

Trovo che questo diagramma sia molto utile per comprendere le fasi di acquisizione/destinazione/bolla: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html # Eventi fasi

Di seguito, il contenuto estratto dal collegamento.

Fasi

L'evento viene inviato seguendo un percorso dalla radice dell'albero a questo nodo di destinazione. Può quindi essere gestito localmente a livello di nodo di destinazione o da qualsiasi antenato di destinazione più in alto nella struttura. L'invio di eventi (chiamato anche propagazione di eventi) avviene in tre fasi e nel seguente ordine:

  1. La fase di acquisizione: l'evento viene inviato agli antenati del bersaglio dalla radice dell'albero al genitore diretto del nodo bersaglio.
  2. La fase target: l'evento viene inviato al nodo target.
  3. La fase gorgogliante: l'evento viene inviato agli antenati del bersaglio dal genitore diretto del nodo bersaglio alla radice dell'albero.

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

Gli antenati del bersaglio sono determinati prima dell'invio iniziale dell'evento. Se il nodo di destinazione viene rimosso durante il dispacciamento o viene aggiunto o rimosso l'antenato di una destinazione, la propagazione dell'evento sarà sempre basata sul nodo di destinazione e gli antenati della destinazione determinati prima della spedizione.

Alcuni eventi potrebbero non necessariamente completare le tre fasi del flusso di eventi DOM, ad es. l'evento può essere definito solo per una o due fasi. Ad esempio, gli eventi definiti in questa specifica eseguiranno sempre le fasi di acquisizione e destinazione, ma alcuni non realizzeranno la fase di bubbling ("eventi di bubbling" contro "eventi non di bubbling", vedere anche l'attributo Event.bubbles).

248
lax4mike

Capture Event (useCapture = true) vs Bubble Event (useCapture = false)

Riferimento MDN

  • L'evento di acquisizione verrà inviato prima dell'evento Bubble
  • L'ordine di propagazione degli eventi è
    1. Cattura genitori
    2. Cattura bambini
    3. Target Capture e Target Bubble
      • Nell'ordine sono stati registrati
      • Quando l'elemento è la destinazione dell'evento, il parametro useCapture non ha importanza (grazie @bam e @ legend80s)
    4. Bolla per bambini
    5. Bolla dei genitori
  • stopPropagation() interromperà il flusso

use Capture flow

Dimostrazione

Risultato:

  1. Cattura genitori
  2. Bolla per bambini 1
  3. Cattura bambini

    (Poiché Children è target, quindi Capture e Bubble si innescheranno nell'ordine in cui sono stati registrati)

  4. Bolla per bambini 2
  5. Bolla dei genitori
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

Quando dici useCapture = true, gli eventi vengono eseguiti dall'alto verso il basso nella fase di acquisizione quando falso fa una bolla dal basso verso l'alto.

14
sushil bharwani

Esempio di codice:

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

Codice Javascript:

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

se entrambi sono impostati su false

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

Esegue: Onclicking Inner Div, gli avvisi vengono visualizzati come: Div 2> Div 1

Qui lo script viene eseguito dall'elemento interno: Event Bubbling (useCapture è stato impostato su false)

div 1 è impostato su true e div 2 impostato su false

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

Esegue: Onclicking Inner Div, gli avvisi vengono visualizzati come: Div 1> Div 2

Qui lo script viene eseguito dall'antenato/elemento esterno: Event Capturing (useCapture è stato impostato su true)

div 1 è impostato su false e div 2 impostato su true

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

Esegue: Onclicking Inner Div, gli avvisi vengono visualizzati come: Div 2> Div 1

Qui lo script viene eseguito dall'elemento interno: Event Bubbling (useCapture è stato impostato su false)

div 1 è impostato su true e div 2 impostato su true

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

Esegue: Onclicking Inner Div, gli avvisi vengono visualizzati come: Div 1> Div 2

Qui lo script viene eseguito dall'antenato/elemento esterno: Event Capturing poiché useCapture è stato impostato su true

11
shadowBot

Si tratta di modelli di eventi: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow Puoi catturare un evento in fase di bolle o in cattura fase. La tua scelta.
Dai un'occhiata a http://www.quirksmode.org/js/events_order.html - lo troverai molto utile.

10
NilColor

Date le tre fasi dell'evento viaggio :

  1. La fase di acquisizione : l'evento viene inviato agli antenati del bersaglio dalla radice dell'albero al genitore diretto del nodo bersaglio.
  2. La fase target : l'evento viene inviato al nodo target.
  3. La fase gorgogliante : l'evento viene inviato agli antenati del bersaglio dal genitore diretto del nodo bersaglio alla radice dell'albero.

useCapture indica per quali fasi l'evento viaggio sarà attivo:

Se true, useCapture indica che l'utente desidera aggiungere il listener di eventi solo per la fase di acquisizione, ovvero questo listener di eventi non verrà attivato durante la destinazione e fasi gorgoglianti. Se false, il listener di eventi verrà attivato solo durante le fasi target e bubbling

La fonte è la stessa della seconda migliore risposta: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

6
Aurimas

Sommario:

Le specifiche DOM descritte in:

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

funziona nel modo seguente:

Un evento viene inviato seguendo un percorso dalla radice (document) dell'albero al nodo di destinazione . Il nodo di destinazione è l'elemento HTML più profondo, ovvero event.target. L'invio di eventi (chiamato anche propagazione di eventi) avviene in tre fasi e nel seguente ordine:

  1. La fase di acquisizione: l'evento viene inviato agli antenati del target dalla radice dell'albero (document) al genitore diretto del nodo target.
  2. La fase target: l'evento viene inviato al nodo target. La fase target è sempre sull'elemento html più profondo su cui è stato eseguito il distacco dell'evento.
  3. La fase gorgogliante: l'evento viene inviato agli antenati del bersaglio dal genitore diretto del nodo bersaglio alla radice dell'albero.

Event bubbling, event capturing, event target

Esempio:

// 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'esempio sopra illustra davvero la differenza tra il gorgoglio degli eventi e la cattura degli eventi. Quando si aggiungono i listener di eventi con addEventListener, esiste un terzo elemento chiamato useCapture. Questo è boolean che, se impostato su true, consente al listener di eventi di utilizzare la cattura degli eventi anziché il bubbling degli eventi.

Nel nostro esempio quando impostiamo l'argomento useCapture su false, vediamo che avviene il bubbling di eventi. Innanzitutto viene generato l'evento nella fase target (registri innerBubble), quindi tramite l'evento gorgogliante viene generato l'evento nell'elemento padre (registri outerBubble).

Quando impostiamo l'argomento useCapture su true, vediamo che l'evento nel <div> esterno viene generato per primo. Questo perché l'evento viene ora generato nella fase di acquisizione e non nella fase di bubbling.

5

L'ordine di definizione è importante solo se gli articoli sono allo stesso livello. Se inverti l'ordine di definizione nel tuo codice otterrai gli stessi risultati.

Tuttavia, se si inverte l'impostazione useCapture sui due gestori di eventi, il gestore di eventi figlio risponde prima di quello del padre. La ragione di ciò è che il gestore di eventi figlio verrà ora attivato nella fase di acquisizione che è precedente alla fase di bubbling in cui verrà attivato il gestore di eventi padre.

Se si imposta useCapture su true per entrambi i gestori di eventi, indipendentemente dall'ordine di definizione, il gestore di eventi padre verrà attivato per primo perché precede il figlio nella fase di acquisizione.

Al contrario, se si imposta useCapture su false per entrambi i gestori di eventi, sempre a prescindere dall'ordine di definizione, il gestore di eventi figlio verrà attivato per primo perché precede il genitore nella fase di bubbling.

1
WXB13