JavaScript(jQuery)で親要素と子要素のイベントが被らないようにする

開発環境は、Windows 7 Professional(32bit)+Firefox 58.0.2(32ビット)+jQuery 3.2.1。

下記の例だと、黒い四角内をクリックすると『親要素』というアラートが表示され、赤い四角内をクリックすると『子要素』→『親要素』と2回アラートが表示されてしまう。

HTML部分

<div class="pp" style="width:300px;height:300px;border:solid 1px black;">
	<div class="pp2" style="width:100px;height:100px;border:solid 1px red;"></div>
</div>

JavaScript部分

$(function(){
	$('.pp').on('click',function(){
		alert("親要素");
	});

	$('.pp2').on('click',function(){
		alert("子要素");
	});
});

これを、黒い四角内は親要素だけ、赤い四角内は子要素だけアラートが表示されるようにするには、子要素のクリックイベント部分に、stopPropagation()を追加する。

以下の部分を修正する。

        // functionに引数を入れる
	$('.pp2').on('click',function(e){
		alert("子要素");
		e.stopPropagation(); // ここを追加
	});

f:id:k01ken:20180510212311p:plain

stopPropagation()は、子要素から親要素へのイベントのバブリング(伝播)をキャンセルする関数。このバブリングはjQueryの機能。よって、クリックしたときに、子要素は発動するが、親要素は発動しない流れになる。

これによって、子要素と親要素で違うクリックイベントを発動できる。

※注意点
子要素部分のstyleがdisplay:none;で隠れている、例えば、inputタグのtype属性をbuttonとして、それをdisplay:none;で隠して、代わりに、アイコンを表示させるような場合、イベントを発動させるためにclass属性を、そのdisplay:none;しているinputタグに設置すると、イベント発動の順番が、子要素→親要素じゃなくて、親要素→子要素になってしまい、うまくイベントを振り分けることができない。そのための対策として、inputタグを囲っているlabelタグにclass属性を指定するとうまくいく。

説明が分かりにくければ、コードで示すと、

<label><i class="icon"><input type="button" style="display:none;" class="test"></i></label>

ではなくて、

<label class="test"><i class="icon"><input type="button" style="display:none;"></i></label>

とする。

参考リンク
jQuery のバブリング、preventDefault() や stopPropagation() の使用例 | Tips Note by TAM