web-dev-qa-db-ja.com

addEventListenerのuseCaptureパラメーターを理解できません

https://developer.mozilla.org/en/DOM/element.addEventListener で記事を読みましたが、useCapture属性を理解できません。定義があります:

Trueの場合、useCaptureは、ユーザーがキャプチャを開始したいことを示します。キャプチャの開始後、指定されたタイプのすべてのイベントは、DOMツリーでその下のEventTargetにディスパッチされる前に、登録されたリスナーにディスパッチされます。ツリーを上方向にバブリングしているイベントは、キャプチャを使用するように指定されたリスナーをトリガーしません。

このコードでは、親イベントが子の前にトリガーされるので、その動作を理解できません。ドキュメントオブジェクトの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>
270
user26732

イベントは、開始時(「キャプチャ」)と終了時(「バブル」)の2つの場合にアクティブにできます。イベントは、定義された順序で実行されます。 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を使用)
  • 4capture=trueを使用して2番目に定義)
  • 1capture=falseで最初に定義されたイベント)
  • 3capture=falseで2番目に定義されたイベント)
328
Rob W

この図は、キャプチャ/ターゲット/バブルのフェーズを理解するのに非常に役立ちます。 http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html #Events-phases

以下は、リンクから抽出されたコンテンツです。

フェーズ

イベントは、ツリーのルートからこのターゲットノードへのパスに従ってディスパッチされます。その後、ターゲットノードレベルで、またはツリーの上位にあるターゲットの祖先からローカルに処理できます。イベントのディスパッチ(イベント伝播とも呼ばれます)は、3つのフェーズと次の順序で発生します。

  1. キャプチャフェーズ:イベントは、ツリーのルートからターゲットノードの直接の親にターゲットの祖先にディスパッチされます。
  2. ターゲットフェーズ:イベントはターゲットノードにディスパッチされます。
  3. バブリングフェーズ:イベントは、ターゲットノードの直接の親からツリーのルートまで、ターゲットの祖先にディスパッチされます。

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

ターゲットの祖先は、イベントの最初のディスパッチの前に決定されます。ディスパッチ中にターゲットノードが削除された場合、またはターゲットの祖先が追加または削除された場合、イベントの伝播は常にディスパッチ前に決定されたターゲットノードとターゲットの祖先に基づきます。

一部のイベントは、DOMイベントフローの3つのフェーズを必ずしも完了するとは限りません。イベントは1つまたは2つのフェーズに対してのみ定義できます。例として、この仕様で定義されたイベントは常にキャプチャおよびターゲットフェーズを実行しますが、一部はバブリングフェーズを実行しません(「バブリングイベント」対「非バブリングイベント」。Event.bubbles属性も参照)。

248
lax4mike

キャプチャイベント(useCapture = true)vsバブルイベント(useCapture = false

MDNリファレンス

  • キャプチャイベントは、バブルイベントの前にディスパッチされます
  • イベント伝播順序はです
    1. 親のキャプチャ
    2. 子どもたちの捕獲
    3. ターゲットキャプチャおよびターゲットバブル
      • 登録された順に
      • 要素がイベントのターゲットである場合、useCaptureパラメーターは重要ではありません(@bamおよび@ legend80sに感謝)
    4. 子供バブル
    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>
70
Steely Wing

UseCapture = trueと言うと、イベントはキャプチャフェーズで上から下に実行され、falseの場合、下から上にバブルが実行されます。

14
sushil bharwani

コード例:

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

実行:内部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);

実行:内部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);

実行:内部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に設定されているため、イベントキャプチャ

11
shadowBot

すべてはイベントモデルについてです: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow バブリング段階またはキャプチャ段階でイベントをキャッチできます。あなたの選択。
http://www.quirksmode.org/js/events_order.html をご覧ください-非常に便利です。 。

10
NilColor

イベントの3つのフェーズtravelを考えると:

  1. capture phase:イベントは、ツリーのルートからターゲットノードの直接の親にターゲットの祖先にディスパッチされます。
  2. ターゲットフェーズ:イベントはターゲットノードにディスパッチされます。
  3. バブリングフェーズ:イベントは、ターゲットノードの直接の親からツリーのルートまでターゲットの祖先にディスパッチされます。

useCaptureは、イベントtravelがオンになるフェーズを示します。

trueの場合、useCaptureは、ユーザーがキャプチャフェーズのみにイベントリスナーを追加したいことを示します。つまり、このイベントリスナーはターゲット中にトリガーされず、バブリング段階。 falseの場合、イベントリスナーはターゲット段階とバブリング段階でのみトリガーされます

ソースは2番目のベストアンサーと同じです。 https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

6
Aurimas

概要:

以下で説明されているDOM仕様:

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

次の方法で動作します。

イベントは、ツリーのルート(document)からターゲットノードへのパスに従ってディスパッチされます。ターゲットノードは、最も深いHTML要素、つまりevent.targetです。イベントのディスパッチ(イベント伝播とも呼ばれます)は、3つのフェーズと次の順序で発生します。

  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という3番目の要素があります。これはbooleanで、trueに設定すると、イベントリスナーはイベントバブリングの代わりにイベントキャプチャを使用できます。

この例では、useCapture引数をfalseに設定すると、イベントのバブリングが発生することがわかります。最初にターゲットフェーズでイベントが発生し(innerBubbleに記録)、次にイベントバブリングを介して親要素のイベントが発生します(outerBubbleに記録)。

UseCapture引数をtrueに設定すると、外側の<div>のイベントが最初に発生することがわかります。これは、イベントがバブリングフェーズではなくキャプチャフェーズで発生するためです。

5

定義の順序は、アイテムが同じレベルにある場合にのみ重要です。コード内の定義の順序を逆にすると、同じ結果が得られます。

ただし、2つのイベントハンドラーのuseCapture設定を逆にすると、子イベントハンドラーは親のイベントハンドラーの前に応答します。これは、親イベントハンドラーがトリガーされるバブリングフェーズの前のキャプチャフェーズで子イベントハンドラーがトリガーされるためです。

定義の順序に関係なく、両方のイベントハンドラーでuseCaptureをtrueに設定すると、キャプチャ段階で子の前に来るため、親イベントハンドラーが最初にトリガーされます。

逆に、両方のイベントハンドラーでuseCaptureをfalseに設定すると(定義の順序に関係なく)、子イベントハンドラーは、バブリングフェーズで親の前に来るため、最初にトリガーされます。

1
WXB13