Label内包要素でクリックイベントが2回発生する

下のようにラベル内にdivがあり、そこのクリックイベントを購読しているとします。
その場合、id=SPANのテキストをクリックしたりするとDIVのイベントが2回発行します。

<label>LABEL<div id="DIV" onclick="DoSomething"><input><span id="SPAN">A<span></div></label>

理屈はこうです。
SPANのクリックがバブリングしてDIVのonclickを呼びます。(1回目)

labelまでバブリングすると、labelが内包するinputに対してクリックイベントを自動的に送ります。
inputのクリックイベントが発火し、バブリングによってDIVのonclickを呼びます。(2回目)

これに対し、inputをクリックした場合はlabelがinputに向けてクリックイベントを飛ばさないため(おそらくe.targetで判断してる)、DIVのonclickは1回しか呼ばれません。

onclickイベントはdivじゃなくてlabel要素につけた場合も同様で、input以外の内包要素をクリックした場合には2回イベントが発火します。

対処法としてはlabelで内包せずにforで指定するか、

<label for="INPUT">LABEL</label><div id="DIV" onclick="DoSomething"><input id="INPUT"><span id="SPAN">A<span></div>

もしくはe.targetを判定してstopPropagation()するかですね。
どっちでもいいですが、stopPropagationする場合にはネストさせている構造に依存して判定しなければいけなくなるのでやや煩雑です。

個人的にはforでネストを避けるほうが最終的な管理は楽な気がします。

私は自作のセレクトボックスをlabelで内包したときにこの問題が発生しました。
Input要素以外も内包するようなときは素直に分けたほうがよさそうです。

コメント