Почему при обработке событий JavaScript уровня DOM 2 цель сначала получает всплывающую информацию, а затем захват?

Насколько я понимаю, обработка событий DOM Level 2 работает в следующем порядке:

  1. захват от верхнего HTML-элемента до цели
  2. сама цель
  3. всплывающее всплывающее окно до верхнего HTML-элемента

пример находится по адресу: https://jsfiddle.net/uwe5dmxw/
(я включу код в конец этого вопроса)

Но если я нажму на «дочерний» элемент (потомок самого низкого уровня) в текущем Google Chrome, Firefox, Safari и даже в IE 11, я получу последовательный результат в следующем порядке:

  1. Захват HTML
  2. ТЕЛО захват
  3. Родительский захват
  4. цель пузырящаяся
  5. захват цели
  6. Родитель пузырится
  7. ТЕЛО пузырится
  8. HTML всплывающее окно

То есть порядок «захвата цели» и «пузырька цели» обратный.

Насколько я понял, хотя упомянутое событие DOM уровня 2 достигает цели только один раз, но большинство браузеров реализуют его как достижение цели дважды, один раз во время захвата события и один раз во время всплытия события. Но дело в том, почему "захват цели" и "бульканье цели" поменяны местами?


Код: (но только демо, без необходимости смотреть не надо)

<div id="hi">
  hello
  <div id="child">
    child
  </div>
</div>

JavaScript:

var parentElement = document.getElementById("hi"),
  childElement = document.getElementById("child"),
  htmlElement = document.getElementsByTagName("html")[0],
  bodyElement = document.getElementsByTagName("body")[0];

// ------------------ Bubble --------------------

htmlElement.addEventListener("click", function() {
  console.log("<html> clicked " + new Date().getTime(), this);
});

bodyElement.addEventListener("click", function() {
  console.log("<body> clicked " + new Date().getTime(), this);
});

parentElement.addEventListener("click", function() {
  console.log("Parent clicked " + new Date().getTime(), this);
});

childElement.addEventListener("click", function() {
  console.log("Child clicked at " + new Date().getTime(), this);
});

// ------------------ Use Capture --------------------

htmlElement.addEventListener("click", function() {
  console.log("<html> (useCapture) clicked " + new Date().getTime(), this);
}, true);

bodyElement.addEventListener("click", function() {
  console.log("<body> (useCapture) clicked " + new Date().getTime(), this);
}, true);

parentElement.addEventListener("click", function() {
  console.log("Parent (useCapture) clicked " + new Date().getTime(), this);
}, true);

childElement.addEventListener("click", function() {
  console.log("Child (useCapture) clicked at " + new Date().getTime(), this);
}, true);

person nonopolarity    schedule 23.01.2016    source источник


Ответы (1)


Когда событие происходит в объекте с несколькими обработчиками событий, обработчики событий запускаются в том порядке, в котором они были прикреплены. Вы не видите отдельного события на child. Вы видите одно и то же событие (событие click), которое отправляется обоим обработчикам событий, но отправляется в том порядке, в котором обработчики событий были присоединены.

Если вы измените порядок, в котором назначаются обработчики событий, вы увидите, что обработчики событий также изменяют порядок, в котором они вызываются. Событие находится «в цели», не всплывает и не захватывается, поэтому вызываются оба.

Если вы зарегистрируете e.eventPhase для каждого из двух целевых обработчиков событий, вы увидите, что он регистрирует значение 2, что означает, что он находится «в цели» (не всплывает и не захватывает). Дополнительную информацию о e.eventPhase см. в документе на MDN.

person jfriend00    schedule 23.01.2016
comment
интересно... по сути, флаг useCapture игнорируется. Он просто рассматривает это как фазу без пузырьков и захвата, но как фазу достижения цели. - person nonopolarity; 23.01.2016
comment
@太極者無極而生 — Похоже, что когда событие достигает цели, вызываются оба типа обработчиков событий (с захватом и без захвата) в том порядке, в котором были назначены обработчики событий. На цели нет события с пометкой захвата. - person jfriend00; 23.01.2016
comment
это правда... useCapture не игнорируется... потому что в то время, когда вы выполняете addEventListener(), нельзя сказать, является ли этот элемент целью, пока что-то не произойдет с ним или с его потомком - person nonopolarity; 23.01.2016