无法理解 addEventListener 中的 useCapture 参数

发布于 2024-12-04 19:00:14 字数 990 浏览 0 评论 0原文

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

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

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

I have read article at https://developer.mozilla.org/en/DOM/element.addEventListener but unable to understand useCapture attribute. Definition there is:

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.

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.

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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

波浪屿的海角声 2024-12-11 19:00:14

事件可以在两种情况下激活:开始时(“捕获”)和结束时(“冒泡”)。

事件按照其定义的顺序执行。假设您定义了 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(首先使用 capture=true 定义)
  • 4(使用 capture= 第二个定义true)
  • 1 (第一个使用 capture=false 定义的事件)
  • 3 (第二个使用 capture=false< 定义的事件/代码>)

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:

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)
情深如许 2024-12-11 19:00:14

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

下面是从 关联。

阶段

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

  1. 捕获阶段:事件被调度到目标的祖先
    从树的根到目标节点的直接父节点。
  2. 目标阶段:事件被分派到目标节点。
  3. 冒泡阶段:事件被分派到目标的
    从目标节点的直接父节点到根节点的祖先
    树。

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

目标的祖先在初始调度之前确定事件。如果在调度期间删除了目标节点,或者添加或删除了目标的祖先,则事件传播将始终基于调度之前确定的目标节点和目标的祖先。

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

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

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.

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

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

只是在用心讲痛 2024-12-11 19:00:14

捕获事件 (useCapture = true) 与 Bubble 事件 (useCapture = false)

MDN 参考

  • 之前调度
  • 捕获事件将在 Bubble Event事件传播顺序
    1. 家长捕捉
    2. 儿童捕捉
    3. 目标捕获和目标气泡
      • 按照注册顺序
      • 当元素是事件的目标时,useCapture 参数并不重要(感谢@bam 和@legend80s)
    4. 儿童泡泡
    5. 父气泡
  • stopPropagation() 将停止流程

使用捕获流程

演示

结果:

  1. 父捕获

  2. 目标气泡 1

    (因为捕获和目标气泡会按照注册的顺序触发,所以这是先触发)

  3. 目标捕获

  4. 目标气泡2

  5. 父气泡

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

// "target" will trigger in the order of register (addEventListener()), capture / bubble don't affect the order
// #2
target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

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

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

// #1 : "parent capture" first
parent.addEventListener('click', function (e) { 
console.log('Parent Capture');
// e.stopPropagation();
}, true);

// #5 : "parent bubble" last
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>

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

MDN Reference

  • 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, useCapture parameter doesn't matter (Thanks @bam and @legend80s)
    4. Children Bubble
    5. Parent Bubble
  • stopPropagation() will stop the flow

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 this is trigger first)

  3. Target Capture

  4. Target Bubble 2

  5. Parent Bubble

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

// "target" will trigger in the order of register (addEventListener()), capture / bubble don't affect the order
// #2
target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

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

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

// #1 : "parent capture" first
parent.addEventListener('click', function (e) { 
console.log('Parent Capture');
// e.stopPropagation();
}, true);

// #5 : "parent bubble" last
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>

这个俗人 2024-12-11 19:00:14

当你说 useCapture = true 时,事件在捕获阶段从上到下执行,如果为 false,它会从下到上冒泡。

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

舞袖。长 2024-12-11 19:00:14

摘要:

DOM 规范描述于:

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

工作方式如下:

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

  1. 捕获阶段:事件从树的根(文档)分派到目标的祖先。 code>) 到目标节点的直接父节点。
  2. 目标阶段:事件被分派到目标节点。目标阶段始终位于调度事件的最深 html 元素上。
  3. 冒泡阶段:事件被分派到目标的祖先,从目标节点的直接父节点到树的根。

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

示例:

// 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。这是一个布尔值,当设置为 true 时,事件侦听器可以使用事件捕获而不是事件冒泡。

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

当我们将 useCapture 参数设置为 true 时,我们看到外部

中的事件首先被触发。这是因为该事件现在是在捕获阶段而不是冒泡阶段触发的。

Summary:

The DOM spec described in:

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 HTML element, i.e. the event.target. 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 (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 html element 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.

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 boolean which when set to true allows the event listener to use event capturing instead of event bubbling.

In our example when we set the useCapture argument to false we 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).

When we set the useCapture argument to true we 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.

疏忽 2024-12-11 19:00:14

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

It's all about event models: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow
You 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.

Hello爱情风 2024-12-11 19:00:14

代码示例:

<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,警报将显示为:
第2区> Div 1

这里的脚本是从内部元素执行的:事件冒泡(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,警报显示为:
第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,警报显示为:
第2区> Div 1

这里的脚本是从内部元素执行的:事件冒泡(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 时,警报显示为:
第1区> Div 2

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

Code example:

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

Javascript code:

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

if both are set to 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

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

div 1 is set to true and div 2 set to 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

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

div 1 is set to false and div 2 set to 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

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

div 1 is set to true and div 2 set to 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

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

疯到世界奔溃 2024-12-11 19:00:14

鉴于事件旅行的三个阶段:

  1. 捕获阶段:事件被分派到目标的祖先(从树的根到目标的直接父级)
    节点。
  2. 目标阶段:事件被分派到目标节点。
  3. 冒泡阶段:事件被分派到目标的祖先,从目标节点的直接父节点到根节点
    树。

useCapture 指示事件旅行将在哪个阶段进行:

如果trueuseCapture表示用户希望添加事件
仅用于捕获阶段的侦听器,即该事件侦听器不会
在目标阶段和冒泡阶段触发。如果为假,则
事件监听器只会在目标和冒泡期间被触发
阶段

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

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.

useCapture indicates for which phases the event travel will be on:

If true, useCapture indicates 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

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

梦巷 2024-12-11 19:00:14

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

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

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

相反,如果将两个事件处理程序的 useCapture 设置为 false(同样无论定义顺序如何),子事件处理程序将首先被触发,因为它在冒泡阶段位于父事件处理程序之前。

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.

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文