Невозможно понять параметр useCapture в addEventListener
Я прочитал статью в https://developer.mozilla.org/en/DOM/element.addEventListener, но не смог понять атрибут useCapture
. Определение есть:
Если true, useCapture указывает, что пользователь хочет инициировать захват. После начала захвата все события указанного типа будут отправлены зарегистрированному прослушивателю перед отправкой на любые EventTargets под ним в дереве DOM. События, которые пузырятся вверх через дерево, не будут вызывать слушателя, назначенного для использования захвата.
В этом родительском событии кода триггеры перед дочерним, поэтому я не могу понять его
поведение. Объект документа имеет usecapture true, а дочерний div имеет значение usecapture set false, а documentecapture - follow.So, почему свойство 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>
Ответы
Ответ 1
События могут быть активированы в двух случаях: в начале ("захват") и в конце ("пузырь").
События выполняются в порядке их определения. Скажем, вы определяете 4 слушателя событий:
window.addEventListener("click", function(){console.log(1)}, false);
window.addEventListener("click", function(){console.log(2)}, true);
window.addEventListener("click", function(){console.log(3)}, false);
window.addEventListener("click", function(){console.log(4)}, true);
Ответ 2
Я нахожу, что эта диаграмма очень полезна для понимания фаз захвата/цели/пузырька:
http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases
Ниже, содержимое, извлеченное из ссылки.
Phases
Событие отправляется по пути от корня дерева к этой цели node. Затем его можно обрабатывать локально на целевом уровне node или от любых целевых предков, выше в дереве. Рассылка событий (также называемая размножением событий) происходит в три этапа и следующий порядок:
- Фаза захвата: событие отправляется целевым предкам
от корня дерева до прямого родителя целевой node.
- Целевая фаза: событие отправляется в цель node.
- Фаза барботирования: событие отправляется в цель
предков от прямого родителя мишени node до корня
дерево.
![graphical representation of an event dispatched in a DOM tree using the DOM event flow]()
Целевые предки определяются перед начальной отправкой события. Если целевой объект node удаляется во время диспетчеризации или добавляется или удаляется целевой предок, распространение события всегда будет основываться на целевом node и целевых предках, определенных перед отправкой.
Некоторые события могут не обязательно выполнять три фазы потока событий DOM, например. событие может быть определено только для одной или двух фаз. В качестве примера события, определенные в этой спецификации, всегда будут выполнять фазы захвата и цели, но некоторые из них не будут выполнять этап барботирования ( "события барботирования" по сравнению с "событиями без пузырьков", см. Также атрибут Event.bubbles).
Ответ 3
Событие захвата (useCapture = true
) против события Bubble (useCapture = false
)
MDN Ссылка
- Событие захвата будет отправлено до Bubble Event.
- Порядок распространения событий
- Родительский захват
- Захват детей
- Целевой захват и целевой пузырь
- В порядке их регистрации
- Когда элемент является целью события, параметр
useCapture
не имеет значения (спасибо @bam и @legend80s)
- Детский пузырь
- Родительский пузырь
-
stopPropagation()
остановит поток
![use Capture flow]()
демонстрация
Результат:
- Родительский захват
- Детский пузырь 1
-
Захват детей
(Поскольку "Цель" - "Дети", "Захват" и "Пузырь" сработают в том порядке, в котором они были зарегистрированы).
- Детский пузырь 2
- Родительский пузырь
var parent = document.getElementById('parent'),
children = document.getElementById('children');
children.addEventListener('click', function (e) {
alert('Children Bubble 1');
// e.stopPropagation();
}, false);
children.addEventListener('click', function (e) {
alert('Children Capture');
// e.stopPropagation();
}, true);
children.addEventListener('click', function (e) {
alert('Children Bubble 2');
// e.stopPropagation();
}, false);
parent.addEventListener('click', function (e) {
alert('Parent Capture');
// e.stopPropagation();
}, true);
parent.addEventListener('click', function (e) {
alert('Parent Bubble');
// e.stopPropagation();
}, false);
<div id="parent">
<div id="children">
Click
</div>
</div>
Ответ 4
Когда вы говорите, что useCapture = true, события выполняются сверху вниз в фазе захвата, когда false, это делает верхнюю часть пузырька вверху.
Ответ 5
Пример кода:
<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 Inner Div, предупреждения отображаются как:
Div 2 > Div 1
Здесь script выполняется из внутреннего элемента: 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 Inner Div, предупреждения отображаются как:
Div 1 > Div 2
Здесь script выполняется из предка/внешнего элемента: Event Capturing (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 Inner Div, предупреждения отображаются как:
Div 2 > Div 1
Здесь script выполняется из внутреннего элемента: Event Bubbling (useCapture имеет значение false)
div 1 устанавливается в true, а div 2 - true
d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);
Выполняет: Onclicking Inner Div, предупреждения отображаются как:
Div 1 > Div 2
Здесь script выполняется из предка/внешнего элемента: Event Capturing, поскольку useCapture имеет значение true
Ответ 6
Все о моделях событий: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow
Вы можете поймать событие в фазе барботирования или в фазе захвата. Ваш выбор.
Взгляните на http://www.quirksmode.org/js/events_order.html - вы найдете его очень полезным.
Ответ 7
Учитывая три этапа событийного путешествия:
- Фаза захвата: событие отправляется целевым предкам от корня дерева до прямого родителя целевого узла.
- Целевая фаза: событие отправляется на целевой узел.
- Фаза пузырьков: событие отправляется целевым предкам от прямого родителя целевого узла к корню дерева.
useCapture
указывает, для каких фаз будет происходить перемещение события:
Если true
, useCapture указывает, что пользователь желает добавить прослушиватель событий только для фазы захвата, то есть этот прослушиватель событий не будет запущен во время целевых и пузырьковых фаз. Если false
, прослушиватель событий будет срабатывать только во время целевого и пузырькового этапов.
Источник совпадает со вторым лучшим ответом: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases
Ответ 8
Резюме:
Спецификация DOM
описана в:
https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases
работает следующим образом:
Событие отправляется по пути от корня (document
) дерева к целевому узлу. Целевой узел - это самый глубокий HTML
элемент, то есть event.target. Распределение событий (также называемое распространением событий) происходит в три этапа и в следующем порядке:
- Фаза захвата: событие отправляется целевым предкам от корня дерева (
document
) до прямого родителя целевого узла. - Целевая фаза: событие отправляется на целевой узел. Целевая фаза всегда находится на самом глубоком элементе
html
для которого было отправлено событие. - Фаза пузырьков: событие отправляется целевым предкам от прямого родителя целевого узла к корню дерева.
![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>
Ответ 9
Порядок определения имеет значение только в том случае, если элементы находятся на одном уровне. Если вы измените порядок определения в своем коде, вы получите те же результаты.
Однако, если вы измените параметр useCapture на двух обработчиках событий, обработчик дочерних событий отвечает перед родителем. Причина этого в том, что обработчик дочерних событий теперь будет запущен на этапе захвата, который предшествует фазе барботажа, в котором будет запускаться обработчик родительского события.
Если вы установите для useCapture значение true для обоих обработчиков событий - независимо от порядка определения - родительский обработчик событий будет запущен первым, потому что он приходит перед дочерним элементом на этапе захвата.
И наоборот, если вы установите useCapture в false для обоих обработчиков событий - снова независимо от порядка определения - обработчик дочерних событий будет запускаться первым, потому что он приходит перед родителем в фазе барботажа.