Что такое событие пузырится и захватывает?

в чем разница между пузырями событий и захватом? Из двух, какая модель быстрее и лучше использовать?

5 ответов


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

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

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

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

стекают вниз, пузырь вверх

в старые времена Netscape выступал за захват событий, в то время как Microsoft продвигала событие пузырясь. Оба являются частью W3C События Объектной Модели Документа стандартные (2000).

IE только пузырящееся событие, тогда как IE9+ и все основные браузеры поддерживают оба. С другой стороны,производительность пузырьков событий может быть немного ниже для сложных DOMs.

мы можем использовать addEventListener(type, listener, useCapture) для регистрации обработчиков событий в режиме bubbling (по умолчанию) или захвата. Чтобы использовать модель захвата, передайте третий аргумент как true.

пример

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

в приведенной выше структуре предположим, что событие click произошло в li элемент.

в модели захвата событие будет обрабатываться div во-первых (нажмите обработчики событий в div сначала выстрелит), затем в ul, затем в последнем элементе target,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());
}

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>
<section id="log"></section>

другой пример в JSFiddle.


описание:

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

захват событие

при использовании захвата событий

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

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

пузырящееся событие

при использовании события клокоча

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

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


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

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


Если есть два элемента-элемент 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.


и учебник по javascript.info чтобы быть очень ясным в объяснении этой темы. И его 3-очковое резюме в конце действительно говорит о важнейших моментах. Цитирую здесь:

  1. события сначала захватываются до самой глубокой цели, а затем пузырь вверх. В Т. е.
  2. все обработчики работают на клокоча этапе за исключением addEventListener с последним аргументом true, который является единственным способом поймать событие на захват сцены.
  3. пузыриться / захватывать может быть остановлено событием.cancelBubble=true (IE) или событие.это происходит() для других браузеров.

есть еще 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>