Что такое всплывающее и захватывающее событие?

Ответы:

1441

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

При пузырьковании событие сначала захватывается и обрабатывается самым внутренним элементом, а затем распространяется на внешние элементы.

При захвате событие сначала захватывается самым внешним элементом и распространяется на внутренние элементы.

Захват также называется «каплей», что помогает запомнить порядок распространения:

сочиться

В прежние времена Netscape выступал за захват событий, в то время как Microsoft поощряла всплытие событий. Оба являются частью стандарта событий объектной модели документа W3C (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. source
beatgammit
7
Я знаю, что уже слишком поздно оставлять
Просто код
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
runspired
513

Описание:

quirksmode.org имеет хорошее описание этого. В двух словах (скопировано из quirksmode):

Захват событий

Когда вы используете захват событий

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

обработчик события element1 срабатывает первым, обработчик события element2 срабатывает последним.

Событие кипит

Когда вы используете всплывающее событие

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

обработчик события element2 срабатывает первым, обработчик события element1 срабатывает последним.


Что использовать?

Это зависит от того, что вы хотите сделать. Там нет лучше. Разница заключается в порядке выполнения обработчиков событий. Большую часть времени будет нормально запускать обработчики событий в фазе пузырьков, но может также потребоваться запускать их раньше.

Феликс Клинг
источник
Не происходит и то и другое: сначала захват, а затем всплывание и что такое событие отправки?
Сурадж Джейн
Графический пример здесь: javascript.info/bubbling-and-capturing
Сообщество Ans
71

Если есть два элемента, элемент 1 и элемент 2. Элемент 2 находится внутри элемента 1, и мы присоединяем обработчик событий к обоим элементам, скажем, onClick. Теперь, когда мы нажмем на элемент 2, будет выполнен eventHandler для обоих элементов. Теперь здесь вопрос в том, в каком порядке будет выполняться событие. Если событие, связанное с элементом 1, выполняется первым, это называется захватом события, а если событие, связанное с элементом 2, выполняется первым, это называется всплывающим событием. Согласно W3C, событие начнется в фазе захвата, пока не достигнет цели, вернется к элементу, а затем начнет пузыриться.

Состояния захвата и всплытия известны параметром useCapture метода addEventListener.

eventTarget.addEventListener (тип, слушатель, [, useCapture]);

По умолчанию useCapture имеет значение false. Это означает, что он находится в пузырчатой ​​фазе.

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>

Пожалуйста, попробуйте изменить true и false.

dinesh_malhotra
источник
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() для других браузеров.
gm2008
источник
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**.

Capturing

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Кондал
источник