webシステムを作る時に、よくwindow.onclickを使います。
通常、特定のElementにclickイベントをセットすればいいんですが、
クリックイベントの個数が多くなる場合や、対象のElementが頻繁に入れ替わる場合などは、windowに対してclickイベントを1つ指定すればいいので、そのやり方で対応しています。
ちょっとトリッキーなので、イベント操作になれていない方などはあまりオススメできませんが、個人的に効率的に使っています。
でも、そんなwindowクリックイベントで発生した不思議な現象が解明したので、仕様時の注意点を記します。
windowクリックイベントの書き方
まずはじめに、windowクリックイベントをどのように使っているかを説明してみますね。
<link rel='stylesheet' href='window.css'>
<div class='root'>
<input type='checkbox' id='list_toggle'>
<div class='button-a'>Button-A</div>
<div class='button-b'>Button-B</div>
<label class='button-c' for='list_toggle'>Button-C</label>
<ul class='lists'>
<li>list-1</li>
<li>list-2</li>
<li>list-3</li>
</ul>
</div>
.root > *{
display:inline-block;
width:100px;
margin:10px;
background-color:red;
color:white;
padding:10px;
vertical-align:top;
cursor:pointer;
}
#list_toggle{
display:none;
}
.root > ul{
display:none;
background-color:blue;
}
.root > ul,
.root > li{
list-style:none
}
#list_toggle:checked ~ ul{
display:inline-block;
}
Sampleとして、基本となるHTMLとCSSファイルを作ってみました。
Button-Cをクリックすると、リストが表示される、labelタグとcheckboxを使った、簡単なトグルメニュー表示の仕組みです。
この状態で、windowにクリックイベントを仕込みます。
先程のwindow.htmlに下のscriptタグを追記します。
...
<script src='window.js'></script>
そして、javascript記述です。
window.onclick = e => {
if(e.target.closest('.button-c')){
console.log('Click!!')
}
}
クリックイベントが複数発生する怪
この状態で、Button-Cが押された時に、ブラウザコンソールに「Click!!」と表示されるようにしてみました。
この程度の処理だと何の問題もないんですが、実はこの時に1回のクリックで2回のクリックイベントが発生しています。
次のコードをwindow.onclickイベントに追加してみます。
console.log('--click--')
--click--
Click!!
--click--
確かに、"--click--"が2回登場しています。
1回しかクリックしていないのに、2回・・・何故・・・????
原因解明
この事象の原因は、labelタグでした。
labelタグは、for属性に指定したid値をcheckboxを"ON / OFF"をトグルで切り替える機能というわけではなく、
checkboxのinputタグを内部でクリックするという機能です。
という事で、先程追加したconcole.log(...)を次のように変更してみました。
console.log('--click--' , e.target)
この状態でクリックすると・・・
--click--
<label class='button-c' for='list_toggle'>Button-C</label>
Click!!
--click--
<input type='checkbox' id='list_toggle'>
はい、ドン!
想定通り、labelタグをクリックした直後に、inputタグをクリックしちゃっています。
周辺調査
ちょっと横道にそれますが、labelタグにfor属性をつけない場合はどうなるのか気になるので調べてみました。
結論から言うと、上記のコードでfor属性だけを取り除けば、--click--は発生しませんでした・・・
が、label内に、input type='checkbox'というタグを入れると、同じ用にクリックイベントが複数発生しました。
試しに、buttonタグを書いてみたところ、これも複数イベント発生します。
どうやら、クリックイベントが機能する要素がlabelタグと連動する位置にある場合は、クリックイベントが合わせて発動してしまうようですね。
最後に、もう一つ気になったのが、label内に複数のbuttonがある場合は何個のイベントが発生するんでしょう?
この場合は、一番先頭のbuttonのみが、クリックイベント発生した状態でした。
labelの挙動も、先頭のクリックにしか対応していないということがわかりました。
あとがき
今回の調査で、labelタグの仕様について、少しだけ理解することができました。
こういう複数のイベントを回避するためには、クリックイベントで発動する関数などの中で、クリック対象以外の要素の場合は無視する処理を書くことで対応できそうです。
こういう仕様をちゃんと理解していないと、システム不具合が出た時に、アタフタしてしまうから、調査は重要!という事を改めて理解できた!
0 件のコメント:
コメントを投稿