Невозможно понять параметр useCapture в addEventListener

Я прочитал статью в https://developer.mozilla.org/en/DOM/element.addEventListener но не в состоянии понять . Определение есть:

если true, useCapture указывает, что пользователь хочет инициировать захват. После инициирования захвата все события указанного типа будут отправлены зарегистрированному прослушивателю перед отправкой в любые EventTargets под ним в дереве DOM. События, которые бурлят вверх через дерево не вызовет прослушиватель, назначенный для использования capture.

в этом коде родительское событие запускается перед дочерним, поэтому я не могу понять его поведение.Объект Document имеет значение usecapture true, а дочерний div-значение usecapture false, после чего используется document usecapture.Итак, почему свойство document предпочтительнее дочернего.

function load() {
  document.addEventListener("click", function() {
    alert("parent event");
  }, true);

  document.getElementById("div1").addEventListener("click", function() {
    alert("child event");
  }, false);
}
<body onload="load()">
  <div id="div1">click me</div>
</body>

9 ответов


события могут быть активированы в двух случаях: в начале ("захват") и в конце ("пузырь"). События выполняются в порядке их определения. Скажем, вы определяете 4 слушателя событий:

window.addEventListener("click", function(){alert(1)}, false);
window.addEventListener("click", function(){alert(2)}, true);
window.addEventListener("click", function(){alert(3)}, false);
window.addEventListener("click", function(){alert(4)}, true);

появится окно предупреждения в следующем порядке:

  • 2 (сначала определяется с помощью capture=true)
  • 4 (определяется второй с помощью capture=true)
  • 1 (первое определенное событие с capture=false)
  • 3 (второе определенное событие с capture=false)

Я считаю, что эта диаграмма очень полезна для понимания фаз захвата / цели / пузыря: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

ниже, контент, извлеченный из ссылки.

этапы

событие отправляется по пути от корня дерева к этому целевому узлу. Затем его можно обрабатывать локально на уровне целевого узла или от предков любой цели выше в дерево. Диспетчеризация событий (также называемая распространением событий) происходит в три этапа и в следующем порядке:

  1. фаза захвата: событие отправляется предкам цели от корня дерева до прямого родителя целевого узла.
  2. целевая фаза: событие отправляется на целевой узел.
  3. пузырящаяся фаза: событие отправляется в цель предки от прямого родителя целевого узла до корня из дерево.

graphical representation of an event dispatched in a DOM tree using the DOM event flow

предки цели определяются до первоначальной отправки события. Если целевой узел удаляется во время диспетчеризации или добавляется или удаляется предок целевого объекта, распространение событий всегда будет основываться на целевом узле и предках целевого объекта, определенных до отправки.

некоторые события могут не обязательно выполнять три фазы потока событий DOM, например, событие может быть только определяется для одной или двух фаз. Например, события, определенные в этой спецификации, всегда будут выполнять фазы захвата и цели, но некоторые не будут выполнять фазу пузырьков ("пузырящиеся события" по сравнению с "не пузырящимися событиями", см. Также событие.пузыри атрибут).


захват события vs Bubble Event

  • событие захвата будет отправлено перед событием пузыря
  • порядок распространения событий
    1. Родитель Захвата
    2. Детская Захвата
    3. Дети Пузырь
    4. Родитель Пузыря

( stopPropagation() остановит поток )

                  |  A
 -----------------|--|-----------------
 | Parent         |  |                |
 |   -------------|--|-----------     |
 |   |Children    V  |          |     |
 |   ----------------------------     |
 |                                    |
 --------------------------------------

демо

var parent = document.getElementById('parent'),
    child  = document.getElementById('child');

child.addEventListener('click', function(e){ 
    console.log('Child Capture, with capture');
    // e.stopPropagation();
}, true);

child.addEventListener('click', function(e){ 
    console.log('Child Bubble');
    // e.stopPropagation();
}, false);

parent.addEventListener('click', function(e){ 
    console.log('Parent Capture, with capture');
    // e.stopPropagation();
}, true);

parent.addEventListener('click', function(e){ 
    console.log('Parent Bubble');
    // e.stopPropagation();
}, false);
<div id="parent">
    <button id="child">Click</button>
</div>

когда вы говорите useCapture = true, события выполняются сверху вниз в фазе захвата, когда false он делает пузырь снизу вверх.


пример кода:

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>

код Javascript:

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");

если для обоих установлено значение false

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);

исполняет: Onclicking внутренний Div, оповещения отображаются как: Div 2 > Div 1

здесь скрипт выполняется из внутреннего элемента: Event Bubbling (useCapture имеет значение false)

div 1 имеет значение true, а div 2-значение false

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},false);

исполняет: Onclicking внутренний Div, оповещения отображаются как: Div 1 > Div 2

здесь скрипт выполняется из предка / внешнего элемента: захват события (useCapture имеет значение true)

div 1 имеет значение false, а div 2-true

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},true);

исполняет: Onclicking внутренний Div, оповещения отображаются как: Div 2 > Div 1

здесь скрипт выполняется из внутреннего элемента: Event Bubbling (useCapture имеет значение false)

div 1 имеет значение true, а div 2-Значение правда

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);

исполняет: Onclicking внутренний Div, оповещения отображаются как: Div 1 > Div 2

здесь скрипт выполняется из элемента ancestor / outer: захват события, так как useCapture имеет значение true


все о моделях событие: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow Вы можете поймать событие в фазе пузырьков или в фазе захвата. Ваш выбор.
Взгляните на http://www.quirksmode.org/js/events_order.html - вы найдете его очень полезным.


учитывая три фазы события путешествия:

  1. на фазы захвата: событие отправляется предкам цели от корня дерева до прямого родителя цели узел.
  2. на целевой фазы: событие отправляется на целевой узел.
  3. на пузырящейся фазы: событие отправляется предкам цели от прямого родителя объекта целевой узел к корню дерево.

useCapture указывает, для каких фаз событие путешествия будет:

Если true, usecapture присвоено указывает, что пользователь желает добавить событие прослушиватель только для фазы захвата, т. е. этот прослушиватель событий не будет запускаться во время фазы мишени и пузырьков. Если false, в прослушиватель событий будет срабатывать только во время цели и пузырьков фазы

источник такой же, как второй лучший ответ: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases


резюме:

на DOM спецификаций, описанных в:

https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

работает следующим образом:

событие отправляется по пути от корня (document) от дерева до целевом узле. Целевой узел является самым глубоким HTML элемент, т. е. событие.цель. Диспетчеризация событий (также называемое Событие распространение) происходит в три фазы и в следующем порядке:

  1. фаза захвата: событие отправляется предкам цели из корня дерева (document) для прямого родителя целевого узла.
  2. цель этапа: событие отправляется на целевой узел. Целевая фаза всегда находится на самом глубоком html элемент, на котором событие было dispachted.
  3. пузырящаяся фаза: событие отправляется предкам цели от прямого родителя целевого узла к корню дерева.

Event bubbling, event capturing, event target

пример:

// bubbling handlers, third argument (useCapture) false (default)
document.getElementById('outerBubble').addEventListener('click', () => {
  console.log('outerBubble');
}, false)

document.getElementById('innerBubble').addEventListener('click', () => {
  console.log('innerBubble');
}, false)


// capturing handlers, third argument (useCapture)  true
document.getElementById('outerCapture').addEventListener('click', () => {
  console.log('outerCapture');
}, true)

document.getElementById('innerCapture').addEventListener('click', () => {
  console.log('innerCapture');
}, true)
div:hover{
  color: red;
  cursor: pointer;
}
<!-- event bubbling -->
<div id="outerBubble">
  <div id="innerBubble">click me to see Bubbling</div>
</div>


<!-- event capturing -->
<div id="outerCapture">
  <div id="innerCapture">click me to see Capturing</div>
</div>

приведенный выше пример действительно иллюстрирует разницу между пузырями событий и захватом событий. При добавлении прослушивателей событий с addEventListener, есть третий элемент, называемый useCapture. Это boolean который при установке в true позволяет прослушивателю событий использовать захват событий вместо пузырьков событий.

в нашем примере, когда мы устанавливаем аргумент useCapture в false мы видим, что бурление происходит. Сначала запускается событие на целевой фазе (logs innerBubble), а затем через событие bubbling запускается событие в родительском элементе (logs outerBubble).

когда мы устанавливаем аргумент useCapture в true мы видим, что события во внешнем <div> is выстрелил первым. Это связано с тем, что событие теперь запускается в фазе захвата, а не в фазе пузырьков.


порядок определения имеет значение, только если элементы находятся на одном уровне. Если вы изменить порядок в коде вы получите те же результаты.

однако, если вы отмените параметр useCapture для двух обработчиков событий, обработчик дочерних событий ответит раньше, чем родительский. Причина этого заключается в том, что обработчик дочерних событий теперь будет запускаться на этапе захвата, который предшествует фазе пузырьков, в которой будет Родительский обработчик событий вызванный.

Если вы установите useCapture в true для обоих обработчиков событий-независимо от порядка определения-Родительский обработчик событий будет запущен первым, потому что он приходит до ребенка в фазе захвата.

и наоборот, если вы установите useCapture в false для обоих обработчиков событий-опять же, независимо от порядка определения-обработчик дочерних событий будет запущен первым, потому что он приходит до родителя в фазе пузырьков.