回答:
イベントのバブリングとキャプチャーは、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>
useCapture
IE> = 9でサポートされるようになりました。ソース
triclkling
同じcapturing
ですか?Trickling v. Bubbling
このビデオトークでCrockfordが語ります-youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB周辺 1 hr 5 minutes
trickle down
=> onElement
=>bubble up
説明:
quirksmode.orgにはこれについての良い説明があります。一言で言えば(quirksmodeからコピー):
イベントのキャプチャ
イベントキャプチャを使用する場合
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
element1のイベントハンドラーが最初に起動し、element2のイベントハンドラーが最後に起動します。
イベントバブリング
イベントバブリングを使用する場合
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
element2のイベントハンドラーが最初に起動し、element1のイベントハンドラーが最後に起動します。
何を使う?
何をしたいかによります。これ以上のものはありません。違いは、イベントハンドラーの実行順序です。ほとんどの場合、バブリングフェーズでイベントハンドラーを起動することは問題ありませんが、それらをより早く起動する必要がある場合もあります。
要素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>
真と偽を変えて試してみてください。
the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling
。addEventListenerには、useCapture
trueまたはfalseに設定できるパラメーターがあることがわかりました 。そしてHTML 4.0で、イベントリスナーは、要素の属性として指定されたとuseCapture defaults to false
。あなたが書いたものを確認する仕様にリンクできますか?
このトピックの説明では、javascript.infoのこのチュートリアルが非常に明確であることがわかりました。そして、最後の3つのポイントの要約は、本当に重要なポイントについて語っています。ここで引用します:
- イベントは最初に最も深いターゲットまでキャプチャされ、次にバブルアップします。IE <9では、バブルするだけです。
- キャプチャステージでイベントをキャッチする唯一の方法である、
addEventListener
最後の引数を除いて、すべてのハンドラはバブリングステージで動作 しますtrue
。- バブリング/キャプチャは
event.cancelBubble=true
(IE)またはevent.stopPropagation()
他のブラウザで停止できます。
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>