Що таке бурчання і захоплення подій?


Відповіді:


1439

Пульсування та захоплення подій - це два способи поширення події в API HTML DOM, коли подія відбувається в елементі всередині іншого елемента, і обидва елементи зареєстрували ручку для цієї події. Режим поширення події визначає, в якому порядку елементи отримують подію .

Завдяки бульбашці подія спочатку захоплюється та обробляється найпотужнішим елементом, а потім передається зовнішнім елементам.

Захоплюючи подію, спочатку захоплюється найвіддаленіший елемент і передається внутрішнім елементам.

Захоплення також називається "хитрощі", що допомагає запам'ятати порядок розповсюдження:

струсити вниз, пузирити

Ще в старі часи Netscape виступав за захоплення подій, а Microsoft сприяла бурхливості подій. Обидва є частиною стандарту W3C Document Object Model Events Events (2000).

IE <9 використовує лише бульбашку подій , тоді як IE9 + та всі основні браузери підтримують і те, і інше. З іншого боку, ефективність пульсації подій може бути дещо нижчою для складних DOM.

Ми можемо використовувати addEventListener(type, listener, useCapture)для реєстрації обробників подій в режимі барботування (за замовчуванням) або в режимі захоплення. Для використання моделі захоплення передайте третій аргумент як true.

Приклад

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

У наведеній вище структурі припустимо, що в liелементі відбулася подія клацання .

В захопленні моделі, ця подія буде оброблятися з допомогою divперших (обробники подій клацніть в divзгорить першим), то в ul, то на останньому в цільовому елементі, li.

У моделі міхура відбудеться навпаки: подія спочатку буде оброблятися елементом li, потім - і ul, нарешті, divелементом.

Для отримання додаткової інформації див

У наведеному нижче прикладі, якщо натиснути будь-який із виділених елементів, ви побачите, що фаза захоплення потоку розповсюдження події відбувається спочатку, а потім фаза барботування.

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>

Ще один приклад JSFiddle .


41
useCaptureтепер підтримується в IE> = 9. Джерело
beatgammit

7
Я знаю, що занадто пізно, щоб залишити коментар, але приємну статтю я знайшов тут catcode.com/domcontent/events/capture.html
Просто код

3
Це triclklingте саме, що capturing? Про це Крокфорд розповідає Trickling v. Bubblingу цій відео-розмові - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB навколо 1 hr 5 minutes.
Кевін Мередіт

1
@KevinMeredith Те саме. «Крапельний» просто робить його легше запам'ятати , що ці дві моделі робити (просочування вниз , пляшечку вгору ).
кішка

7
Відповідь, наведена вище, правильна щодо порядку в детальному поясненні, але залишає вас думати, що струмка виникає вдруге з "бульбашкою вгору, струмком вниз". Події завжди проходять через фазу захоплення перед фазою міхура. Правильний порядок trickle down=> onElement=>bubble up
проходить

513

Опис:

quirksmode.org має хороший опис цього. Коротко кажучи (скопійовано з quirksmode):

Захоплення події

Коли ви використовуєте захоплення подій

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

спочатку спрацьовує обробник події element1, останній обробник події елемента2.

Подія кипіла

Під час використання подій

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

спочатку запускається обробник події елемента2, обробляється подія елементу1.


Що використовувати?

Це залежить від того, що ви хочете зробити. Немає кращого. Різниця - це порядок виконання обробників подій. Більшу частину часу буде добре запускати обробників подій у фазі бурхливості, але також може знадобитися звільнити їх раніше.


Чи не відбувається так: спочатку захоплення, а потім булькання, а також що таке відправлення?
Сурай Джайн


71

Якщо є два елементи, елемент 1 і елемент 2. Елемент 2 знаходиться всередині елемента 1 і ми приєднуємо обробник подій з обома елементами, дозволяє сказати onClick. Тепер, коли ми натискаємо на елемент 2, тоді буде виконано eventHandler для обох елементів. Тепер тут питання в якому порядку буде виконуватися подія. Якщо подія, приєднана до елемента 1, виконується спочатку, це називається захопленням події, а якщо подія, приєднана до елемента 2, виконується спочатку, це називається перебоєм подій. Відповідно до W3C подія розпочнеться у фазі захоплення, поки не досягне цілі, повернеться до елемента, а потім почне кипіти

Стани захоплення та барботування відомі параметром useCapture методу addEventListener

eventTarget.addEventListener (тип, слухач, [, useCapture]);

За замовчуванням useCapture є помилковим. Це означає, що він перебуває у фазі бульбашки.

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>

Будь ласка, спробуйте змінити істинне і хибне.


2
@masterxilo: немає необхідності у Fiddle, StackOverflow тепер підтримує вбудований код (фрагменти стека) .
Дан Даскалеску

Що стосується the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling. Я лише виявив, що в addEventListener є параметр, useCaptureякий можна встановити на true або false; а в HTML 4.0 слухачі подій були вказані як атрибути елемента та useCapture defaults to false. Чи можете ви зв’язатись із специфікацією, яка підтверджує те, що ви написали?
прибій

25

Я знайшов цей підручник на javascript.info дуже зрозумілим у поясненні цієї теми. І його підсумок з 3-х балами наприкінці справді говорить про вирішальні моменти. Я цитую його тут:

  1. Події спочатку фіксуються до глибокої цілі, а потім піднімаються. У IE <9 вони лише бульбашки.
  2. Усі обробники працюють на вибухових стадіях винятків addEventListenerз останнім аргументом true, що є єдиним способом зловити подію на захопленні.
  3. Бублінг / захоплення можна зупинити event.cancelBubble=true(IE) або event.stopPropagation() для інших браузерів.

7

Також є Event.eventPhaseмайно, яке може повідомити вам, чи подія є цільовою чи походить з іншого місця.

Зауважте, що сумісність браузера ще не визначена. Я протестував його на Chrome (66.0.3359.181) та Firefox (59.0.3), і він там підтримується.

Розширюючись на вже чудовий фрагмент із прийнятої відповіді , це вихід з використанням eventPhaseвластивості

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

Булінг

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

Захоплення

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.