Co to jest bulgotanie i przechwytywanie zdarzeń?


Odpowiedzi:


1439

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.

Przykład

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

Załóżmy, że w powyższej strukturze zdarzenie kliknięcia wystąpiło w lielemencie.

W uchwycenie modelu, wydarzenie będzie obsługiwane przez divpierwszych (obsługi zdarzeń kliknij w divbł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 divelement.

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>

Kolejny przykład w JSFiddle .


41
useCaptureteraz obsługiwane w IE> = 9. source
beatgammit

7
Wiem, że jest za późno, aby dodać komentarz, ale fajny artykuł znalazłem tutaj catcode.com/domcontent/events/capture.html
prostu kod

3
Czy to triclklingto samo co capturing? Crockforda opowiada o Trickling v. Bubblingtej rozmowie wideo - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB wokół 1 hr 5 minutes.
Kevin Meredith,

1
@KevinMeredith To samo. „Trickling” po prostu ułatwia zapamiętanie, co robią oba modele (zjeżdżanie w dół , bąbelkowanie w górę ).
kot

7
Powyższa odpowiedź jest poprawna w odniesieniu do kolejności w szczegółowym wyjaśnieniu, ale pozwala sądzić, że struga pojawia się na drugim miejscu po „bańce w górę, strużce w dół”. Wydarzenia zawsze przechodzą fazę przechwytywania przed fazą bubble. Prawidłowa kolejność to trickle down=> onElement=>bubble up
runspired

513

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.


Czy nie zdarza się jedno, najpierw wychwytywanie, a następnie bulgotanie, a także czym jest zdarzenie wysyłki?
Suraj Jain,

przykład graficzny znajduje się tutaj: javascript.info/bubbling-and-capturing
Społeczność Odpowiedź

71

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.


2
@masterxilo: nie ma potrzeby Fiddle, StackOverflow obsługuje teraz kod wbudowany (fragmenty stosu) .
Dan Dascalescu

Jeżeli chodzi 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, useCapturektó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ś?
surfmuggle

25

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:

  1. Wydarzenia są najpierw przechwytywane do najgłębszego celu, a następnie zwiększane. W IE <9 tylko bańki.
  2. Wszystkie procedury obsługi działają na scenie propagacji, addEventListenerz wyjątkiem ostatniego argumentu true, który jest jedynym sposobem na złapanie zdarzenia na scenie przechwytywania.
  3. Bąbelkowanie / przechwytywanie może zostać zatrzymane przez event.cancelBubble=true(IE) lub event.stopPropagation() w innych przeglądarkach.

7

Istnieje również Event.eventPhasewł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 eventPhasewł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>


5

Bulgotanie

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

Przechwytywanie

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.