Jaka jest różnica między propagacją zdarzeń a przechwytywaniem? Kiedy należy używać bulgotania zamiast chwytania?
Jaka jest różnica między propagacją zdarzeń a przechwytywaniem? Kiedy należy używać bulgotania zamiast chwytania?
Odpowiedzi:
Tworzenie i przechwytywanie zdarzeń to dwa sposoby propagacji zdarzeń w interfejsie API HTML DOM, gdy zdarzenie występuje w elemencie w innym elemencie, a oba elementy zarejestrowały uchwyt dla tego zdarzenia. Tryb propagacji zdarzeń określa, w jakiej kolejności elementy odbierają zdarzenie .
Dzięki propagacji zdarzenie jest najpierw przechwytywane i obsługiwane przez najbardziej wewnętrzny element, a następnie propagowane do elementów zewnętrznych.
W przypadku przechwytywania zdarzenie jest najpierw przechwytywane przez najbardziej zewnętrzny element i propagowane do elementów wewnętrznych.
Przechwytywanie jest również nazywane „zraszaniem”, co pomaga zapamiętać kolejność propagacji:
spłynąć, podskoczyć
W dawnych czasach Netscape opowiadał się za przechwytywaniem zdarzeń, podczas gdy Microsoft promował propagowanie zdarzeń. Oba są częścią standardu W3C Document Object Model Events (2000).
IE <9 używa tylko propagacji zdarzeń , podczas gdy IE9 + i wszystkie główne przeglądarki obsługują oba. Z drugiej strony wydajność propagacji zdarzeń może być nieco niższa w przypadku złożonych DOM.
Możemy użyć addEventListener(type, listener, useCapture)
do zarejestrowania programów obsługi zdarzeń w trybie propagacji (domyślnie) lub przechwytywania. Aby użyć modelu przechwytywania, przekaż trzeci argument jako true
.
<div>
<ul>
<li></li>
</ul>
</div>
Załóżmy, że w powyższej strukturze zdarzenie kliknięcia wystąpiło w li
elemencie.
W uchwycenie modelu, wydarzenie będzie obsługiwane przez div
pierwszych (obsługi zdarzeń kliknij w div
błyśnie pierwsza), a następnie w ul
, a następnie w ostatniej w elemencie docelowym li
.
W modelu z bąbelkami stanie się odwrotnie: zdarzenie będzie najpierw obsługiwane przez li
, a następnie przez ul
, a na końcu przez div
element.
Aby uzyskać więcej informacji, zobacz
W poniższym przykładzie kliknięcie dowolnego z wyróżnionych elementów powoduje, że najpierw następuje faza przechwytywania przepływu propagacji zdarzeń, a następnie faza propagacji.
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
teraz obsługiwane w IE> = 9. source
triclkling
to samo co capturing
? Crockforda opowiada o Trickling v. Bubbling
tej rozmowie wideo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB wokół 1 hr 5 minutes
.
trickle down
=> onElement
=>bubble up
Opis:
quirksmode.org ma ładny opis tego. W skrócie (skopiowane z quirksmode):
Przechwytywanie zdarzeń
Gdy używasz przechwytywania zdarzeń
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
moduł obsługi zdarzeń elementu 1 uruchamia się jako pierwszy, moduł obsługi zdarzeń elementu 2 jest uruchamiany jako ostatni.
Bulgotanie zdarzeń
Gdy używasz propagacji zdarzeń
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
moduł obsługi zdarzeń elementu 2 uruchamia się jako pierwszy, moduł obsługi zdarzeń elementu 1 uruchamia się jako ostatni.
Czego używać?
To zależy od tego, co chcesz zrobić. Nie ma nic lepszego. Różnica polega na kolejności wykonywania procedur obsługi zdarzeń. Przez większość czasu będzie dobrze strzelać do programów obsługi zdarzeń w fazie bulgotania, ale może być również konieczne wcześniejsze ich zwolnienie.
Jeśli są dwa elementy, element 1 i element 2. Element 2 znajduje się wewnątrz elementu 1 i dołączamy moduł obsługi zdarzeń z oboma elementami, powiedzmy onClick. Teraz, gdy klikniemy element 2, wówczas zostanie wykonany eventHandler dla obu elementów. Teraz pytanie brzmi, w jakiej kolejności wydarzenie zostanie wykonane. Jeśli zdarzenie dołączone do elementu 1 wykonuje się jako pierwsze, nazywa się to przechwytywaniem zdarzenia, a jeśli zdarzenie dołączone do elementu 2 wykonuje się jako pierwsze, nazywane jest to propagowaniem zdarzeń. Zgodnie z W3C zdarzenie rozpocznie się w fazie przechwytywania, dopóki nie osiągnie celu, wraca do elementu, a następnie zaczyna bulgotać
Stany przechwytywania i propagacji są znane z parametru useCapture metody addEventListener
eventTarget.addEventListener (typ, detektor, [, useCapture]);
Domyślnie useCapture ma wartość false. Oznacza to, że jest w fazie bulgotania.
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>
Spróbuj zmienić prawdę i fałsz.
the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling
. Znalazłem tylko, że addEventListener ma parametr, useCapture
który można ustawić na true lub false; aw HTML 4.0 detektory zdarzeń zostały określone jako atrybuty elementu i useCapture defaults to false
. Czy możesz link do specyfikacji, która potwierdza to, co napisałeś?
Znalazłem ten samouczek na javascript.info, który bardzo jasno wyjaśnia ten temat. A jego 3-punktowe podsumowanie na końcu naprawdę mówi o kluczowych punktach. Cytuję to tutaj:
- Wydarzenia są najpierw przechwytywane do najgłębszego celu, a następnie zwiększane. W IE <9 tylko bańki.
- Wszystkie procedury obsługi działają na scenie propagacji,
addEventListener
z wyjątkiem ostatniego argumentutrue
, który jest jedynym sposobem na złapanie zdarzenia na scenie przechwytywania.- Bąbelkowanie / przechwytywanie może zostać zatrzymane przez
event.cancelBubble=true
(IE) lubevent.stopPropagation()
w innych przeglądarkach.
Istnieje również Event.eventPhase
właściwość, która może ci powiedzieć, czy wydarzenie jest docelowe lub pochodzi z innego miejsca.
Pamiętaj, że zgodność przeglądarki nie jest jeszcze ustalona. Testowałem go na Chrome (66.0.3359.181) i Firefox (59.0.3) i jest tam obsługiwany.
Po rozwinięciu i tak już świetnego fragmentu z zaakceptowanej odpowiedzi jest to wynik wykorzystujący eventPhase
właściwość
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>