无法理解addEventListener中的useCapture参数

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

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

在这段代码中,父事件在子事件之前触发,所以我无法理解它 的行为。文档对象的usecapcapture设置为true,子div的usecapcapture设置为false,文档usecapcapture紧随其后。

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>

117150 次浏览

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

事件可以在两种情况下被激活:在开始(“捕获”)和在结束(“气泡”)。 事件按照它们的定义顺序执行。比如,你定义了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定义的第二个事件)

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

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

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

阶段

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

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

使用DOM事件流在DOM树中分派的事件的图形表示形式

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

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

定义的顺序只在项目处于同一级别时才起作用。如果你在你的代码中颠倒定义的顺序,你会得到相同的结果。

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

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

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

捕获事件(useCapture = true) vs泡沫事件(useCapture = false)

MDN Reference

  • Capture Event将在Bubble Event之前分派
  • 事件传播顺序为
    1. 父母捕获
    2. 孩子捕捉
    3. 目标捕获和目标气泡
      • 按登记的顺序
      • 当元素是事件的目标时,useCapture参数不重要(谢谢@bam和@legend80s)
    4. 孩子泡沫
    5. 父母泡沫
  • stopPropagation()将停止流

use Capture flow

演示

结果:

  1. < p >父捕获

  2. 目标气泡

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

  3. < p >目标捕获

  4. 目标气泡

  5. < p >父泡沫

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>

代码示例:

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

这里脚本是从内部元素执行的:

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

这里脚本是从祖先/外部元素执行的:

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 1

这里脚本是从内部元素执行的:

Div 1设置为true, Div 2设置为true

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

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

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

给定事件旅行的三个阶段:

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

useCapture表示事件旅行将在哪个阶段上:

如果trueuseCapture表示用户希望添加事件 监听器仅用于捕获阶段,即此事件监听器不会 在目标和冒泡阶段触发。如果false,则 事件监听器只会在目标和冒泡期间被触发 阶段< / p >

Source与第二个最佳答案相同: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元素,即event.target。事件分派(也称为事件传播)发生在三个阶段,顺序如下:

  1. 捕获阶段:事件从树的根(document)分派到目标节点的直接父节点。
  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。这是一个boolean,当设置为true时,允许事件侦听器使用事件捕获而不是事件冒泡。

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

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