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


290

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>

回答:


350

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

49
実行の順序がされて保証されませんno specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget。私はすべてのブラウザをテストしたわけではないので、すべて同じ方法で実装する可能性があります。ただし、キャプチャイベントは、非キャプチャイベントの前に実行されます。
beatgammit 2013

47
実行の順序は@tjameson DOM2仕様の後継、で保証DOM3イベント:「実装は現在のターゲットのかを決定しなければならない候補イベントリスナーをこれが自分の中で現在のターゲットに登録されているすべてのイベントリスナーのリストでなければなりません。登録の順番。」
Rob W

1
これは基本的にはイベントの順序と関係があります
slier

1
@slier、はい、同じイベントの複数のハンドラーが実行される順序。
JMD 2015

6
これは私の知る限り以来、受け入れ答えである理由は考えていない、複数、隣接するイベントハンドラの実行順序を規定についてキャプチャとバブリング繁殖行動について協議をしていない
georaldc

272

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

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

フェーズ

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

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

DOMイベントフローを使用してDOMツリーでディスパッチされたイベントのグラフィック表現

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

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


1
とても素敵な図!
Alex

1
ターゲットノードの子はどうですか?彼らはいつイベントを受け取りますか?
Aurimas

の子であるので、ツリーのルートは実際にWindowではなく、です。documentdocumentWindow
stackjlei 2017

この図は非常に役立ちました。ありがとうございました !
Thomas An

1
「なぜ」を含む「何」を説明するすべてのリソースが欲しいです。いつものようにもっとググるように。
aaaaaa 2018年

80

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

MDNリファレンス

  • キャプチャイベントは、バブルイベントの前にディスパッチされます
  • イベントの伝播順序は
    1. 親の捕獲
    2. 子供の捕獲
    3. ターゲットキャプチャとターゲットバブル
      • 登録した順に
      • 要素がイベントのターゲットである場合、useCaptureパラメーターは関係ありません(@bamと@ legend80sに感謝)
    4. 子供のバブル
    5. 親バブル
  • stopPropagation() 流れを止めます

キャプチャフローを使用する

デモ

結果:

  1. 親の捕獲
  2. ターゲットバブル1

    (キャプチャとターゲットのバブルは登録された順序でトリガーされるため、キャプチャイベントの前にバブルイベントがトリガーされるため)

  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>


1
例に誤りがあります:子イベントを次の順序で宣言しました:1.子のキャプチャ2.子のバブル重要です!Childがイベントのターゲットになる場合でも、リスナーは同じ順序で呼び出されます。MDNのメモを参照してください:要素がイベントのターゲットである場合、「useCapture」パラメーターは問題ではありません。(developer.mozilla.org/en-US/docs/Web/API/EventTarget/...
BAM

1
:イベントターゲットに接続されたイベントリスナーの場合、イベントはキャプチャ段階とバブリング段階ではなく、ターゲット段階にあります。developer.mozilla.org/en-US/docs/Web/API/EventTarget/…Events in the target phase will trigger all listeners on an element in the order they were registered, regardless of the useCapture parameter.から。したがって、「Children Capture」と「Children Bubble」のフェーズはありません。
legend80s

そして、それは、例を実行すると、「子のキャプチャ」の前に「子のバブル1」が生成される理由を説明しています。
Gershom

18

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


11

イベントモデルのすべて:http : //www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow イベントは、バブリングフェーズまたはキャプチャフェーズでキャッチできます。あなたの選択。
見てくださいhttp://www.quirksmode.org/js/events_order.htmlを -あなたはそれが非常に便利見つけることができます。


1
w3へのリンクは、Google検索と同じかそれよりも役に立たないので、何も理解できません。
Muhammad Umer 2013

3
ええ、そのw3リンクは膨大な量の単語ですが、反対に、quirksmodeサイトへの2番目のリンクはトピックを非常によく簡潔に説明しています。
Stano 2013

11

コード例:

<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

ここでは、スクリプトは内部要素から実行されます:イベントバブリング(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

ここでは、スクリプトは内部要素から実行されます:イベントバブリング(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に設定されているため、イベントのキャプチャ


1
この文脈での「より大」シェブロンの意味は何ですか?
2540625

9

概要:

以下に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. バブリング段階:イベントは、ターゲットノードの直接の親からツリーのルートまで、ターゲットの祖先にディスパッチされます。

イベントバブリング、イベントキャプチャ、イベントターゲット

例:

// 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と、イベントバブリングが発生することがわかります。まず、ターゲットフェーズのイベントが発生し(logs innerBubble)、次に、イベントバブリングによって親要素のイベントが発生します(logs outerBubble)。

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


7

イベントの3つの段階を考える

  1. キャプチャ段階:イベントは、ツリーのルートからターゲットノードの直接の親に目標の祖先に派遣されます。
  2. ターゲット相:イベントがターゲット・ノードに送出されます。
  3. バブリング段階:イベントがターゲットノードの直接の親からツリーのルートにターゲットの祖先に派遣されます。

useCaptureイベントが移動するフェーズを示しますが。

の場合trueuseCaptureは、ユーザーがキャプチャ段階でのみイベントリスナーを追加することを望んでいることを示します。つまり、このイベントリスナーは、ターゲット段階とバブリング段階ではトリガーされません。の場合false、イベントリスナーはターゲット段階とバブリング段階でのみトリガーされます

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


2

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.