Невозможно понять параметр useCapture в addEventListener - PullRequest
272 голосов
/ 13 сентября 2011

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

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

В этом коде родительское событие запускается перед дочерним, поэтому я не могу понять его В объекте поведения.Документ имеется значение usecapture true, а для дочернего элемента div значение usecapture установлено в значение false, и при этом используется usecapture документа. Поэтому свойство документа предпочтительнее дочернего.

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 ]

330 голосов
/ 13 сентября 2011

События могут быть активированы в двух случаях: в начале («захват») и в конце («пузырь»).События выполняются в порядке их определения.Скажем, вы определяете 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)
250 голосов
/ 18 мая 2012

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

Ниже содержание извлечено из ссылки.

Phases

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

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

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

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

Некоторые события могут не обязательно выполнять три фазы потока событий DOM, например, событие может быть определено только для одной или двух фаз. В качестве примера, события, определенные в этой спецификации, всегда будут выполнять фазы захвата и назначения, но некоторые не будут завершать фазу пузырьков («события пузырьков» против «событий не пузырьков», см. Также атрибут Event.bubbles).

70 голосов
/ 04 марта 2014

Событие захвата (useCapture = true) по сравнению с событием пузыря (useCapture = false)

Ссылка MDN

  • Событие захвата будет отправлено перед событием пузыря
  • Порядок распространения событий:
    1. Родительский захват
    2. Детский захват
    3. Целевой захват и целевой пузырь
      • В порядке их регистрации
      • Когда элемент является целью события, параметр useCapture не имеет значения (Спасибо @bam и @ legend80s)
    4. Children Bubble
    5. Родительский пузырь
  • stopPropagation() остановит поток

use Capture flow

Демо

Результат:

  1. Родительский захват
  2. Детский пузырь 1
  3. Детский захват

    (потому что дети - это цель, поэтому захват иПузырь сработает в порядке их регистрации)

  4. Детский пузырь 2
  5. Родительский пузырь

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>
14 голосов
/ 13 сентября 2011

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

11 голосов
/ 06 августа 2014

Пример кода:

<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);

Выполнение: при нажатии Inner 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);

Выполняется: при щелчке по Inner 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);

Выполняется: при нажатии Inner Div, предупреждения отображаются как: Div 2> Div 1

Здесь скрипт выполняется из внутреннего элемента: 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);

Выполнение: при нажатии на Внутренний Div, предупреждения отображаются как: Div 1> Div 2

ЗдесьСценарий выполняется из предка / внешнего элемента: захват событий, поскольку для useCapture установлено значение true

10 голосов
/ 13 сентября 2011

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

6 голосов
/ 12 марта 2017

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

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

useCapture указывает, для каких фаз будет включено событие travel :

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

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

5 голосов
/ 25 августа 2018

Сводка:

Спецификация DOM, описанная в:

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

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

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

  1. Фаза захвата: событие отправляется предкам цели из корнядерево (document) для прямого родителя целевого узла.
  2. Целевая фаза: событие отправляется целевому узлу.Целевая фаза всегда находится на самом глубоком элементе html, для которого было отправлено событие.
  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, мы видим, что всплытие событий происходитместо.Сначала запускается событие на целевой фазе (регистрирует innerBubble), а затем с помощью всплывающего события генерируется событие в родительском элементе (регистрируется externalBubble).

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

1 голос
/ 25 января 2013

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

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

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

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

...