DOM Event がどのように発火するのか
上記のページで Chrome Dev Tool を開きコンソールで以下のコードをコピペして実行して、画面をクリックしてみてください。
以下のコードでは window
body
div#MAIN0
にそれぞれクリックイベントをバインドし、console.log
でメッセージを吐き出しています。
メッセージがどういう順番で出力されれるかわかるでしょうか?
document.getElementById('MAIN0').addEventListener('click', function(e){ console.log('MAIN0 clicked'); }, false);
window.addEventListener('click', function(e){ console.log('window clicked'); }, false);
document.getElementsByTagName("body")[0].addEventListener('click', function(e){ console.log('body clicked'); }, true);
答えは・・・
body clicked
MAIN0 clicked
window clicked
こうなります。
addEventListener
では第三引数の Boolean がキャプチャのフラグになっていて、true
にするとキャプチャされて実行順序が変化しています。整理すると以下のようなフローになります。
- キャプチャーフェーズでルートの Window からイベントが発火したターゲットまでをたどり、キャプチャされているイベントを発火
- ターゲットのイベントを発火
- 伝播フェーズでターゲットからルートまでを遡り、バインドされているイベント発火
それでは次のコードはどうでしょうか。
document.getElementById('MAIN0').addEventListener('click', function(e){ console.log('MAIN0 clicked'); }, false);
window.addEventListener('click', function(e){ console.log('window clicked'); }, false);
document.getElementsByTagName("body")[0].addEventListener('click', function(e){ console.log('body clicked'); e.stopPropagation(); }, true);
答えは・・・
body clicked
-
body
でクリックイベントがキャプチャされstopPropagation()
で伝播が停止しているので、それ以上のイベントフローが停止します。
ちなみに jQuery だとこのようになります。
$('#MAIN0').on('click', function(e){ console.log('MAIN0 clicked'); });
$(window).on('click', function(e){ console.log('window licked'); });
$('body').on('click', function(e){ console.log('bodyclicked'); });
キャプチャフラグは jQuery では false で固定なので使えません。
ネイティブでしか使う機会がありませんが覚えておきたいですね。
W3C の図版が非常にわかりやすいので引用しておきます。
Graphical representation of an event dispatched in a DOM tree using the DOM event flow