イベントのバブリングとキャプチャとは何ですか?


回答:


1439

イベントのバブリングとキャプチャーは、HTML DOM APIでのイベント伝搬の2つの方法です。イベントが別のエレメント内のエレメントで発生し、両方のエレメントがそのイベントのハンドルを登録した場合です。イベント伝播モードは、要素がイベントを受け取る順序を決定します。

バブリングでは、イベントは最初に最も内側の要素によってキャプチャおよび処理され、次に外側の要素に伝達されます。

キャプチャでは、イベントは最初に最も外側の要素によってキャプチャされ、内側の要素に伝達されます。

キャプチャは「トリクル」とも呼ばれ、伝播の順序を覚えやすくなります。

トリクルダウン、バブルアップ

昔、Netscapeはイベントキャプチャを提唱し、Microsoftはイベントバブリングを促進しました。どちらもW3C Document Object Model Events標準(2000)の一部です。

IE <9はイベントバブリングのみを使用しますが、IE9 +とすべての主要なブラウザーは両方をサポートします。一方、複雑なDOMの場合、イベントバブリングパフォーマンスはわずかに低下する可能性があります。

を使用しaddEventListener(type, listener, useCapture)て、バブリングモード(デフォルト)またはキャプチャモードでイベントハンドラーを登録できます。キャプチャモデルを使用するには、3番目の引数をとして渡しますtrue

<div>
    <ul>
        <li></li>
    </ul>
</div>

上記の構造では、li要素でクリックイベントが発生したと想定しています。

キャプチャモデルでは、イベントはdiv最初に処理され(最初にのイベントハンドラーがクリックされますdiv)、次にでul、次にターゲット要素の最後で処理されますli

バブリングモデルでは、逆のことが起こります。イベントは最初にによって処理されli、次にによって処理され、ul最後にdiv要素によって処理されます。

詳細については、

以下の例では、強調表示された要素のいずれかをクリックすると、イベント伝播フローのキャプチャ段階が最初に発生し、その後にバブリング段階が続くことがわかります。

var logElement = document.getElementById('log');

function log(msg) {
    logElement.innerHTML += ('<p>' + msg + '</p>');
}

function capture() {
    log('capture: ' + this.firstChild.nodeValue.trim());
}

function bubble() {
    log('bubble: ' + this.firstChild.nodeValue.trim());
}

function clearOutput() {
    logElement.innerHTML = "";
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
    divs[i].addEventListener('click', capture, true);
    divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
    line-height: 0;
}

div {
    display:inline-block;
    padding: 5px;

    background: #fff;
    border: 1px solid #aaa;
    cursor: pointer;
}

div:hover {
    border: 1px solid #faa;
    background: #fdd;
}
<div>1
    <div>2
        <div>3
            <div>4
                <div>5</div>
            </div>
        </div>
    </div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>

JSFiddleでの別の例


41
useCaptureIE> = 9でサポートされるようになりました。ソース
beatgammit


3
triclkling同じcapturingですか?Trickling v. BubblingこのビデオトークでCrockfordが語ります-youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB周辺 1 hr 5 minutes
ケビンメレディス2014年

1
@KevinMeredith同じこと。「トリクル」では、2つのモデルの機能(トリクルダウン、バブルアップ)を覚えやすくなります。

7
上記の答えは、詳細な説明の順序に関しては正しいですが、「バブルアップ、トリクルダウン」では、トリクルが2番目に発生すると考えています。イベントは常にバブルフェーズの前にキャプチャフェーズを通過します。正しい順序はtrickle down=> onElement=>bubble up
runspired 2015

513

説明:

quirksmode.orgにはこれについての良い説明があります。一言で言えば(quirksmodeからコピー):

イベントのキャプチャ

イベントキャプチャを使用する場合

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

element1のイベントハンドラーが最初に起動し、element2のイベントハンドラーが最後に起動します。

イベントバブリング

イベントバブリングを使用する場合

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

element2のイベントハンドラーが最初に起動し、element1のイベントハンドラーが最後に起動します。


何を使う?

何をしたいかによります。これ以上のものはありません。違いは、イベントハンドラーの実行順序です。ほとんどの場合、バブリングフェーズでイベントハンドラーを起動することは問題ありませんが、それらをより早く起動する必要がある場合もあります。


最初にキャプチャしてからバブリングし、ディスパッチイベントとはどちらも発生しませんか?
Suraj Jain

グラフィカルな例はこちら:javascript.info/bubbling-and-capturing
Community Ans

71

要素1と要素2の2つの要素がある場合、要素2は要素1の内部にあり、両方の要素を持つイベントハンドラーをアタッチするには、onClickと言います。要素2をクリックすると、両方の要素のeventHandlerが実行されます。ここで問題は、イベントが実行される順序です。要素1に関連付けられたイベントが最初に実行される場合、それはイベントキャプチャと呼ばれ、要素2に関連付けられたイベントが最初に実行される場合、これはイベントバブリングと呼ばれます。W3Cのとおり、イベントはキャプチャフェーズで開始され、ターゲットに到達して要素に戻り、バブリングを開始します。

キャプチャとバブリングの状態は、addEventListenerメソッドのuseCaptureパラメータで認識されます。

eventTarget.addEventListener(type、listener、[、useCapture]);

デフォルトでは、useCaptureはfalseです。それはバブリング段階にあることを意味します。

var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");

div1.addEventListener("click", function (event) {
  alert("you clicked on div 1");
}, true);

div2.addEventListener("click", function (event) {
  alert("you clicked on div 2");
}, false);
#div1{
  background-color:red;
  padding: 24px;
}

#div2{
  background-color:green;
}
<div id="div1">
  div 1
  <div id="div2">
    div 2
  </div>
</div>

真と偽を変えて試してみてください。


2
@masterxilo:Fiddleは必要ありません。StackOverflowはインラインコード(スタックスニペット)をサポートするようになりました。
Dan Dascalescu 2014年

についてthe event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubblingaddEventListenerには、useCapturetrueまたはfalseに設定できるパラメーターがあることがわかりました 。そしてHTML 4.0で、イベントリスナーは、要素の属性として指定されたuseCapture defaults to false。あなたが書いたものを確認する仕様にリンクできますか?
surfmuggle 2016年

25

このトピックの説明では、javascript.infoのこのチュートリアルが非常に明確であることがわかりました。そして、最後の3つのポイントの要約は、本当に重要なポイントについて語っています。ここで引用します:

  1. イベントは最初に最も深いターゲットまでキャプチャされ、次にバブルアップします。IE <9では、バブルするだけです。
  2. キャプチャステージでイベントをキャッチする唯一の方法である、addEventListener最後の引数を除いて、すべてのハンドラはバブリングステージで動作 しますtrue
  3. バブリング/キャプチャはevent.cancelBubble=true(IE)またはevent.stopPropagation() 他のブラウザで停止できます。

7

Event.eventPhaseイベントがターゲットにあるのか、別の場所から来ているのかを通知できるプロパティもあります。

ブラウザの互換性はまだ決定されていないことに注意してください。Chrome(66.0.3359.181)とFirefox(59.0.3)でテストしましたが、そこでサポートされています。

受け入れられた回答からのすでに素晴らしいスニペットを拡張すると、これはeventPhaseプロパティを使用した出力です

var logElement = document.getElementById('log');

function log(msg) {
  if (logElement.innerHTML == "<p>No logs</p>")
    logElement.innerHTML = "";
  logElement.innerHTML += ('<p>' + msg + '</p>');
}

function humanizeEvent(eventPhase){
  switch(eventPhase){
    case 1: //Event.CAPTURING_PHASE
      return "Event is being propagated through the target's ancestor objects";
    case 2: //Event.AT_TARGET
      return "The event has arrived at the event's target";
    case 3: //Event.BUBBLING_PHASE
      return "The event is propagating back up through the target's ancestors in reverse order";
  }
}
function capture(e) {
  log('capture: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

function bubble(e) {
  log('bubble: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
  divs[i].addEventListener('click', capture, true);
  divs[i].addEventListener('click', bubble, false);
}
p {
  line-height: 0;
}

div {
  display:inline-block;
  padding: 5px;

  background: #fff;
  border: 1px solid #aaa;
  cursor: pointer;
}

div:hover {
  border: 1px solid #faa;
  background: #fdd;
}
<div>1
  <div>2
    <div>3
      <div>4
        <div>5</div>
      </div>
    </div>
  </div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>


5

バブリング

  Event propagate to the upto root element is **BUBBLING**.

捕獲

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.