无法理解addEventListener中的useCapture参数

use*_*732 279 javascript dom dom-events

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

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

在这段代码中,父事件在子事件之前触发,因此我无法理解其行为.文档对象具有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);
}
Run Code Online (Sandbox Code Playgroud)
<body onload="load()">
  <div id="div1">click me</div>
</body>
Run Code Online (Sandbox Code Playgroud)

Rob*_*b W 340

事件可以在两种情况下激活:开始("捕获")和结束("泡沫").事件按照它们的定义顺序执行.比如说,你定义了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);
Run Code Online (Sandbox Code Playgroud)

警报框将按以下顺序弹出:

  • 2(首先定义,使用capture=true)
  • 4(定义第二次使用capture=true)
  • 1(首先定义的事件capture=false)
  • 3(第二个定义的事件capture=false)

  • 执行顺序[不保证](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-basic):`没有规定订单他们将收到有关EventTarget`上其他EventListeners的事件.我没有测试过所有的浏览器,所以他们可能只是碰巧以同样的方式实现它.但是,捕获事件将在非捕获事件之前完成. (49认同)
  • @tjameson执行顺序*在DOM2规范的后续版本中得到保证,[DOM3事件](http://www.w3.org/TR/DOM-Level-3-Events/#h2_dom-event-architecture) :"实现必须确定当前目标的[候选事件监听器](http://www.w3.org/TR/DOM-Level-3-Events/#glossary-candidate-event-handlers).这必须是列表已按注册顺序在当前目标上注册的所有事件监听器." (43认同)
  • 不知道为什么这是因为afaik,捕获和冒泡关于传播行为的讨论而不是关于规定多个相邻事件处理程序的执行顺序的公认答案 (4认同)
  • 所以这基本上与我猜的事件顺序有关 (2认同)
  • @slier,是的,同一事件的多个处理程序的执行顺序。 (2认同)

lax*_*ike 263

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

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

根据从树的根到此目标节点的路径调度该事件.然后可以在目标节点级别本地处理它,或者从树中较高的任何目标的祖先处理它.事件调度(也称为事件传播)分三个阶段发生,顺序如下:

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

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

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

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

  • 我只是希望所有解释“什么”的资源都包含“为什么”。像往常一样进行更多的谷歌搜索。 (2认同)

Ste*_*ing 76

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

MDN参考

  • Capture Event将在Bubble Event之前发送
  • 事件传播顺序是
    1. 父捕获
    2. 儿童捕获
    3. 目标捕获和目标泡沫
      • 按照他们的注册顺序
      • 当元素是事件的目标时,useCapture参数无关紧要(谢谢@bam和@ legend80s)
    4. 儿童泡泡
    5. 父泡泡

stopPropagation() 将停止流动

使用捕获流程

演示

结果:

  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);
Run Code Online (Sandbox Code Playgroud)
<div id="parent">
    <div id="children">
        Click
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

  • 示例中有一个错误:您按以下顺序声明了子事件: 1. child capture 2. child bubble 很重要!仅仅因为如果 Child 将成为事件的目标,则将按相同的顺序调用侦听器。请参阅 MDN 上的注释:当元素是事件 'useCapture' 参数的目标时并不重要。(https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) (2认同)
  • **注意**:对于附加到事件目标的事件监听器,事件处于目标阶段,而不是捕获和冒泡阶段。`无论 useCapture 参数如何,目标阶段中的事件将按照注册顺序触发元素上的所有侦听器。` 来自 https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/添加事件监听器。所以不存在“儿童捕获”和“儿童泡泡”阶段。 (2认同)

sus*_*ani 15

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


小智 11

代码示例:

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)

Javascript代码:

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");
Run Code Online (Sandbox Code Playgroud)

如果两者都设置为false

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);
Run Code Online (Sandbox Code Playgroud)

执行:点击内部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);
Run Code Online (Sandbox Code Playgroud)

执行:点击内部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);
Run Code Online (Sandbox Code Playgroud)

执行:点击内部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);
Run Code Online (Sandbox Code Playgroud)

执行:点击内部Div,警报显示为:Div 1> Div 2

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


Nil*_*lor 10

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

  • w3 的链接与谷歌搜索一样有用,甚至不如谷歌搜索有用,我无法理解那里的任何内容。 (4认同)
  • 是的,那个w3链接只是一大堆单词,但与之相反,第二个链接到_quirksmode_网站非常简洁地解释了这个主题. (3认同)

Aur*_*mas 7

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

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

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

如果true,useCapture指示用户希望仅为捕获阶段添加事件侦听器,即在目标和冒泡阶段期间不会触发此事件侦听器.如果false,事件监听器将仅在目标和冒泡阶段触发

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


Wil*_*een 7

摘要:

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)
Run Code Online (Sandbox Code Playgroud)
div:hover{
  color: red;
  cursor: pointer;
}
Run Code Online (Sandbox Code Playgroud)
<!-- 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>
Run Code Online (Sandbox Code Playgroud)

上面的例子真实地说明了事件冒泡和事件捕获之间的区别.添加事件侦听器时addEventListener,有一个名为useCapture的第三个元素.这个boolean设置为true允许事件监听器使用事件捕获而不是事件冒泡.

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

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