Qual è la differenza tra il bubbling di eventi e l'acquisizione? Quando si dovrebbe usare il bubbling contro l'acquisizione?
Qual è la differenza tra il bubbling di eventi e l'acquisizione? Quando si dovrebbe usare il bubbling contro l'acquisizione?
Risposte:
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
.
<div>
<ul>
<li></li>
</ul>
</div>
Nella struttura sopra, supponi che si sia verificato un evento click li
nell'elemento.
A catturare il modello, l'evento sarà gestito dai div
primi (gestori di eventi fare clic nella div
sparerà 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 ul
e infine div
dall'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>
useCapture
ora supportato in IE> = 9. source
triclkling
lo stesso di capturing
? Crockford parla di Trickling v. Bubbling
questo video: youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB in giro 1 hr 5 minutes
.
trickle down
=> onElement
=>bubble up
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.
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.
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 useCapture
che 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?
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:
- Gli eventi vengono prima catturati fino al bersaglio più profondo, quindi si gonfiano. In IE <9 fanno solo bolle.
- Tutti gli handler lavorano su scenari gorgoglianti,
addEventListener
con l'ultimo argomentotrue
, che è l'unico modo per catturare l'evento sul palco di acquisizione.- Il bubbling / acquisizione può essere fermato da
event.cancelBubble=true
(IE) oevent.stopPropagation()
per altri browser.
C'è anche la Event.eventPhase
proprietà 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 eventPhase
proprietà
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>