Javascriptの基本:イベントプロパゲーション(イベントバブリング)

イベントプロパゲーション(event propagation)という性質がある。英語を直訳すると「イベントの伝播」。バブリング(bubbling)ということもある。
これを、一言で言うと、

DOM階層の下位で発生したイベントが、上位に伝播していく

こととなる。


論より証拠なので、サンプルを作ってみる(FireFoxで有効なサンプルなので注意)。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>Event Sample</TITLE>
<style type="text/css"> 
#div1 {
width:200px;
height:200px;
background-color:lightgreen;
}

#div2 {
width:100px;
height:100px;
background-color:yellow;
}

</style>

<script type="text/javascript">//<![CDATA[

var test = function(_str){
	alert("test"+_str);
}

// ]]>
</script>
</HEAD>

<BODY>
	<div id="div1" onclick='test("1")'> // --- (1)
		<div id="div2" onclick='test("2")'> // --- (2)
		</div>
	</div>
	
	<br>

	<table border="1" onclick='test("3")'> // --- (4)
		<tr onclick='test("4")'> // --- (5)
			<td onclick='test("5")'> // --- (6)
				test
			</td>
		</tr>
	</table>
	
</BODY>
</HTML>

この中には、以下の2つのDOM構造がある。

  • (1) <== (2)
  • (4) <== (5) <== (6)

画面は以下。


ここで、(2)の領域(黄色)をクリックすると、

  • test2 ==> test1 --- (a)

とアラートがあがり、table中の「test」をクリックすると、

  • test5 => test4 ==> test3 --- (b)

とアラートがあがる。要するに、onClickイベントがDOM構造を沿って上ってくる(バブリングという呼び名はここからきている)。

この性質を知っていると、

イベントのハンドリングが全て同じなら、DOMの最上位にイベントハンドラーを仕込めばよい。

ということがわかる。たとえば、tableの各tdタグにイベントハンドラーを記述するのは、とても手間のかかる作業だが、ハンドラーが同一であれば、tableタグに記述すればよい。


このようなイベントの伝播が起こってしまうと都合の悪いことがしばしばある。
その場合には、「イベントオブジェクトに伝播の停止を指示する」ことで伝播を停止するが、ブラウザーによって実装が異なっている。

以下は、FireFoxの例。こうすると、(a)、(b)の伝播は途中で停止される。

<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>Event Sample</TITLE>
<style type="text/css"> 
#div1 {
width:200px;
height:200px;
background-color:lightgreen;
}

#div2 {
width:100px;
height:100px;
background-color:yellow;
}

</style>

<script type="text/javascript">//<![CDATA[
var testStopPropagation = function(_evt,_str){
	alert("test"+_str);
	_evt.stopPropagation(); // --- (1) イベントの伝播を止める
}

// ]]>
</script>
</HEAD>

<BODY>
        <!--// eventはイベントオブジェクトを表す予約語 -->
	<div id="div1" onclick='testStopPropagation(event,"1")'> 
		<div id="div2" onclick='testStopPropagation(event,"2")'>
		</div>
	</div>
	
	<br>
	<table border="1" onclick='testStopPropagation(event,"3")'>
		<tr onclick='testStopPropagation(event,"4")'>
			<td onclick='testStopPropagation(event,"5")'>
				test
			</td>
		</tr>
	</table>
	
</BODY>
</HTML>