Javascript 无法理解 addEventListener 中的 useCapture 参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7398290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 02:08:15  来源:igfitidea点击:

Unable to understand useCapture parameter in addEventListener

javascriptdomdom-events

提问by user26732

I have read article at https://developer.mozilla.org/en/DOM/element.addEventListenerbut unable to understand useCaptureattribute. Definition there is:

我已阅读https://developer.mozilla.org/en/DOM/element.addEventListener 上的文章,但无法理解useCapture属性。定义有:

If true, useCapture indicates that the user wishes to initiate capture. After initiating capture, all events of the specified type will be dispatched to the registered listener before being dispatched to any EventTargets beneath it in the DOM tree. Events which are bubbling upward through the tree will not trigger a listener designated to use capture.

如果为 true,则 useCapture 表示用户希望启动捕获。启动捕获后,指定类型的所有事件将被分派到注册的侦听器,然后再分派到 DOM 树中它下面的任何 EventTarget。通过树向上冒泡的事件不会触发指定使用捕获的侦听器。

In this code parent event triggers before child,so I am not able to understand its behavior.Document object has usecapture true and child div has usecapture set false and document usecapture is followed.So why document property is preferred over child.

在这段代码中,父事件在子事件之前触发,所以我无法理解它的行为。文档对象的 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>

回答by Rob W

Events can be activated at two occasions: At the beginning ("capture"), and at the end ("bubble"). Events are executed in the order of how they're defined. Say, you define 4 event listeners:

事件可以在两种情况下激活:开始时(“捕获”)和结束时(“泡沫”)。事件按照定义的顺序执行。假设您定义了 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);

The log messages will appear in this order:

日志消息将按以下顺序显示:

  • 2(defined first, using capture=true)
  • 4(defined second using capture=true)
  • 1(first defined event with capture=false)
  • 3(second defined event with capture=false)
  • 2(首先定义,使用capture=true
  • 4(定义第二个使用capture=true
  • 1(第一个用 定义的事件capture=false
  • 3(第二个定义的事件与capture=false

回答by lax4mike

I find this diagram is very useful for understanding the capture/target/bubble phases: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

我发现这个图对于理解捕获/目标/气泡阶段非常有用:http: //www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

Below, content extracted from the link.

下面,从链接中提取的内容。

Phases

阶段

The event is dispatched following a path from the root of the tree to this target node. It can then be handled locally at the target node level or from any target's ancestors higher in the tree. The event dispatching (also called event propagation) occurs in three phases and the following order:

该事件按照从树的根到此目标节点的路径进行调度。然后可以在目标节点级别或从树中更高的任何目标的祖先进行本地处理。事件分派(也称为事件传播)分三个阶段和以下顺序发生:

  1. The capture phase: the event is dispatched to the target's ancestors from the root of the tree to the direct parent of the target node.
  2. The target phase: the event is dispatched to the target node.
  3. The bubbling phase: the event is dispatched to the target's ancestors from the direct parent of the target node to the root of the tree.
  1. 捕获阶段:从树的根到目标节点的直接父节点,将事件分派给目标的祖先。
  2. 目标阶段:将事件分派到目标节点。
  3. 冒泡阶段:从目标节点的直接父节点到树的根节点,将事件分派给目标的祖先。

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

使用 DOM 事件流在 DOM 树中调度的事件的图形表示

The target's ancestors are determined before the initial dispatch of the event. If the target node is removed during the dispatching, or a target's ancestor is added or removed, the event propagation will always be based on the target node and the target's ancestors determined before the dispatch.

目标的祖先是在事件的初始分派之前确定的。如果在调度过程中移除了目标节点,或者添加或移除了目标的祖先,则事件传播将始终基于目标节点和调度之前确定的目标的祖先。

Some events may not necessarily accomplish the three phases of the DOM event flow, e.g. the event could only be defined for one or two phases. As an example, events defined in this specification will always accomplish the capture and target phases but some will not accomplish the bubbling phase ("bubbling events" versus "non-bubbling events", see also the Event.bubbles attribute).

有些事件可能不一定完成DOM 事件流的三个阶段,例如,事件只能定义为一个或两个阶段。例如,本规范中定义的事件将始终完成捕获和目标阶段,但有些不会完成冒泡阶段(“冒泡事件”与“非冒泡事件”,另见 Event.bubbles 属性)。

回答by Steely Wing

Capture Event (useCapture = true) vs Bubble Event (useCapture = false)

捕获事件 ( useCapture = true) 与气泡事件 ( useCapture = false)

MDN Reference

MDN 参考

  • Capture Event will be dispatch before Bubble Event
  • Event propagation order is
    1. Parent Capture
    2. Children Capture
    3. Target Capture and Target Bubble
      • In the order they were registered
      • When the element is the target of the event, useCaptureparameter doesn't matter (Thanks @bam and @legend80s)
    4. Children Bubble
    5. Parent Bubble
  • stopPropagation()will stop the flow
  • 捕获事件将在气泡事件之前调度
  • 事件传播顺序是
    1. 父捕获
    2. 儿童捕捉
    3. 目标捕获和目标气泡
      • 按照他们注册的顺序
      • 当元素是事件的目标时,useCapture参数无关紧要(感谢@bam 和@legend80s)
    4. 儿童泡泡
    5. 父母泡泡
  • stopPropagation()将停止流动

use Capture flow

使用捕获流

Demo

演示

Result:

结果:

  1. Parent Capture
  2. Target Bubble 1

    (Because Capture and Bubble of Target will trigger in the order they were registered, so Bubble event is trigger before Capture event)

  3. Target Capture

  4. Target Bubble 2
  5. Parent Bubble
  1. 父捕获
  2. 目标泡泡 1

    (因为Capture和Bubble of Target会按照注册的顺序触发,所以Bubble事件在Capture事件之前触发)

  3. 目标捕获

  4. 目标泡泡 2
  5. 父母泡泡

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

target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

target.addEventListener('click', function (e) { 
console.log('Target Capture');
// e.stopPropagation();
}, true);

target.addEventListener('click', function (e) { 
console.log('Target Bubble 2');
// e.stopPropagation();
}, false);

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

parent.addEventListener('click', function (e) { 
console.log('Parent Bubble');
// e.stopPropagation();
}, false);
<div id="parent">
    <button id="target" style="padding: 1em 0.8em;">
        Trigger event
    </button>
</div>

回答by sushil bharwani

When you say useCapture = true the Events execute top to down in the capture phase when false it does a bubble bottom to top.

当您说 useCapture = true 时,事件在捕获阶段从上到下执行,当为 false 时,它​​会从下到上进行气泡。

回答by NilColor

It's all about event models: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flowYou can catch event in bubbling phase or in capturing phase. Your choice.
Take a look at http://www.quirksmode.org/js/events_order.html- you'll find it very useful.

这都是关于事件模型的:http: //www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow您可以在冒泡阶段或捕获阶段捕获事件。你的选择。
看看http://www.quirksmode.org/js/events_order.html- 你会发现它非常有用。

回答by shadowBot

Code example:

代码示例:

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

Javascript code:

Javascript代码:

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

if both are set to false

如果两者都设置为 false

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

Executes: Onclicking Inner Div, alerts are displayed as: Div 2 > Div 1

执行:单击 Inner Div,警报显示为:Div 2 > Div 1

Here the script is executed from the inner element: Event Bubbling (useCapture has been set to false)

这里的脚本是从内部元素执行的:事件冒泡(useCapture 已设置为 false)

div 1 is set to true and div 2 set to false

div 1 设置为 true,div 2 设置为 false

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

Executes: Onclicking Inner Div, alerts are displayed as: Div 1 > Div 2

执行:单击 Inner Div,警报显示为:Div 1 > Div 2

Here the script is executed from the ancestor / outer element: Event Capturing (useCapture has been set to true)

这里的脚本是从祖先/外部元素执行的:事件捕获(useCapture 已设置为 true)

div 1 is set to false and div 2 set to true

div 1 设置为 false,div 2 设置为 true

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

Executes: Onclicking Inner Div, alerts are displayed as: Div 2 > Div 1

执行:单击 Inner Div,警报显示为:Div 2 > Div 1

Here the script is executed from the inner element: Event Bubbling (useCapture has been set to false)

这里的脚本是从内部元素执行的:事件冒泡(useCapture 已设置为 false)

div 1 is set to true and div 2 set to true

div 1 设置为 true,div 2 设置为 true

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

Executes: Onclicking Inner Div, alerts are displayed as: Div 1 > Div 2

执行:单击 Inner Div,警报显示为:Div 1 > Div 2

Here the script is executed from the ancestor / outer element: Event Capturing since useCapture has been set to true

这里的脚本是从祖先/外部元素执行的: Event Capturing since useCapture has set to true

回答by Willem van der Veen

Summary:

概括:

The DOMspec described in:

DOM规范中描述:

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

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

works the following manner:

工作方式如下:

An event is dispatched following a path from the root (document) of the tree to the target node. The target node is the most deep HTMLelement, i.e. the event.target. The event dispatching (also called event propagation) occurs in three phases and the following order:

沿着从document树的根 ( ) 到目标节点的路径调度事件。目标节点是最深的HTML元素,即 event.target。事件分派(也称为事件传播)分三个阶段和以下顺序发生:

  1. The capture phase:the event is dispatched to the target's ancestors from the root of the tree (document) to the direct parent of the target node.
  2. The target phase:the event is dispatched to the target node. Target phase is always on the deepest htmlelement on which the event was dispachted.
  3. The bubbling phase:the event is dispatched to the target's ancestors from the direct parent of the target node to the root of the tree.
  1. 捕获阶段:将事件从树的根(document)到目标节点的直接父节点分派给目标的祖先。
  2. 目标阶段:将事件分派到目标节点。目标阶段总是在html事件被调度的最深的元素上。
  3. 冒泡阶段:从目标节点的直接父节点到树的根节点,将事件分派给目标的祖先。

Event bubbling, event capturing, event target

事件冒泡、事件捕获、事件目标

Example:

例子:

// 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>

The above example really illustrates the difference between event bubbling and event capturing. When adding the event listeners with addEventListener, there is a third element called useCapture. This a booleanwhich when set to trueallows the event listener to use event capturing instead of event bubbling.

上面的例子确实说明了事件冒泡和事件捕获之间的区别。添加带有 的事件侦听器时addEventListener,有第三个元素称为 useCapture。boolean当设置true为时,此 a允许事件侦听器使用事件捕获而不是事件冒泡。

In our example when we set the useCapture argument to falsewe see that event bubbling takes place. First the event at the target phase is fired (logs innerBubble), and then via event bubbling the event in the parent element is fired (logs outerBubble).

在我们的示例中,当我们将 useCapture 参数设置为时,false我们会看到事件冒泡发生。首先触发目标阶段的事件(记录innerBubble),然后通过事件冒泡触发父元素中的事件(记录outerBubble)。

When we set the useCapture argument to truewe see that the event in the outer <div>is fired first. This is because the event is now fired in the capturing phase and not the bubbling phase.

当我们将 useCapture 参数设置为 时,true我们会看到外部事件<div>首先被触发。这是因为事件现在在捕获阶段而不是冒泡阶段被触发。

回答by Aurimas

Given the three phases of event travel:

鉴于活动旅行的三个阶段:

  1. The capture phase: the event is dispatched to the target's ancestors from the root of the tree to the direct parent of the target node.
  2. The target phase: the event is dispatched to the target node.
  3. The bubbling phase: the event is dispatched to the target's ancestors from the direct parent of the target node to the root of the tree.
  1. 捕获阶段:事件被分派到目标的祖先从树的根部到目标节点的直接父。
  2. 目标阶段:事件被分派到目标节点。
  3. 冒泡阶段:事件从目标节点到树的根的直接父派遣到目标的祖先。

useCaptureindicates for which phases the event travelwill be on:

useCapture指示活动旅行将在哪些阶段进行:

If true, useCaptureindicates that the user wishes to add the event listener for the capture phase only, i.e. this event listener will not be triggered during the target and bubbling phases. If false, the event listener will only be triggered during the target and bubbling phases

如果trueuseCapture表示用户希望只为捕获阶段添加事件监听器,即在目标和冒泡阶段不会触发此事件监听器。如果false,事件监听器只会在目标和冒泡阶段被触发

Source is the same as the second best answer: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

来源与第二个最佳答案相同:https: //www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

回答by WXB13

The order of definition only matters if the items are at the same level. If you reverse the order of definition in your code you will get the same results.

定义顺序仅在项目处于同一级别时才重要。如果您颠倒代码中的定义顺序,您将获得相同的结果。

However, if you reverse the useCapture setting on the two event handlers, the child event handler responds before that of the parent. The reason for this is that the child event handler will now be triggered in the capture phase which is prior to the bubbling phase in which the parent event handler will be triggered.

但是,如果您反转两个事件处理程序的 useCapture 设置,则子事件处理程序会先于父事件处理程序做出响应。这样做的原因是现在将在捕获阶段触发子事件处理程序,该阶段在将触发父事件处理程序的冒泡阶段之前。

If you set useCapture to true for both event handlers--regardless of order of definition--the parent event handler will be triggered first because it comes before the child in the capturing phase.

如果您将两个事件处理程序的 useCapture 设置为 true - 无论定义顺序如何 - 将首先触发父事件处理程序,因为它在捕获阶段出现在子事件处理程序之前。

Conversely, if you set useCapture to false for both event handlers--again regardless of order of definition--the child event handler will be triggered first because it comes before the parent in the bubbling phase.

相反,如果您将两个事件处理程序的 useCapture 设置为 false —— 再次不管定义的顺序 —— 将首先触发子事件处理程序,因为它在冒泡阶段出现在父事件之前。