JavaScriptのEvent
要素のEventをアクセス
まずは簡単に例を作ります
<button id="btn">Click Me!</button>
btn.addEventListener(
"click",
function(){
console.log('123')
},
);
ブラウザのデバッグツールからEventを見るためには二つの方法があります
Element Panelから
まずは該当要素をセレクト
Side Panelから「Event Listeners」をセレクト
展開したら色々なOptionが見れます
Console Panelから
Console Panelに以下のコードを打ちます
getEventListeners(btn).click[0]
Eventが返してもらえました
addEventListenerの全てのパラメータ
これは全てのパラメータのデフォルトです
btn.addEventListener(
"click",
function(){ console.log('123')},
// options
{
once: false,
passive: false, // 一部を除く
capture: false,
},
// useCapture
false
);
- 一つ目:Event Type、型は
string
- 二つ目:Event Handler、型は
function
- 三つ目:Options、型は
object
(記入内容は上を参照) - 四つ目:Use Capture、型は
bool
三つ目と四つ目のパラメータは記入しなくてもいいです。
ちなみに、三つ目の{capture: false}
の効果は四つ目より強いです
つまり
btn.addEventListener(
"click",
function(){ ... },
{
capture: true,
},
false
);
このように、三つ目からcapture
をtrue
を定義、四つ目はfalse
を定義
三つ目の方が強いので、最終的にこのEventのuseCapture
はtrue
となります
一回きりのEvent
全てのパラメータをデフォルトのままだと
Eventは無数回にも受理されます
つまりボタンを何回クリックしても反応されます
でも、時々にはEventは一回きりに提供してほしい場合があります
そこで{once: true}
を使ってこのようなものを簡単に作れます
btn.addEventListener(
"click",
function(){ ... },
{
+ once: true,
},
false
);
これでボタンは一回クリックしたら、そのEventを捨てます
Console PanelでgetEventListeners(btn)
を見ると、空きObjectが返してきます
Event Capture
まずは簡単な例を見てください
<nav>
<ul>
<li>Home</li>
<li id="menuItem">
<div>About US ▽</div>
<ul id="menuChild" hidden>
<li>Story</li>
<li>Member</li>
<li>Shop</li>
</ul>
</li>
<li>Contact</li>
</ul>
</nav>
html, body {
margin: 0;
height: 100vh;
}
nav > ul {
background: beige;
display: flex;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
ul li {
padding: 20px;
}
ul li ul {
position: absolute;
background: antiquewhite;
}
menuItem.addEventListener(
'click',
function(e) {
menuChild.hidden = !menuChild.hidden;
console.log('menu event');
},
false
)
このように、簡単にドロップダウンを作ります
このドロップダウンには二つの特徴があります
- アイテムをクリックすると、ドロップダウンが展開します
- ドロップダウンが展開されている状態、再びアイテムをクリックすると、ドロップダウンを閉めます
そこで、既存の特徴をなくさないように、もう一つの特徴を加えたいです
- ドロップダウンが展開されている状態、画面の任意の場所をクリックすると、ドロップダウンを閉めます
そして、body
に対してクリックイベントを追加します
document.body.addEventListener(
'click',
function(e){
document.querySelector('ul li ul').hidden = true;
console.log('body event');
},
false
)
そして、問題です
「Abous US」を何回クリックしても、反応がしません
Console Panelを見てみると、以下のようにログが出ました
menu event
body event
その理由はEventが発生される順序です
「Abous US」に対して一回のクリックは
- Event Capture:
body
- Event Capture:
menuItem
- Event Bubble:
menuItem
、ログ「menu event
」が発生 - Event Bubble:
body
、ログ「body event
」が発生
発生順序は1.から4.までです
useCapture
のデフォルトはfalse
なので、Event Capture段階は何も発生しません
(もしuseCapture
をtrue
と設定する場合、ログの発生段階はEvent Captureに移します)
つまり、画面にはこんなことが発生ています
- 「Abous US」をクリックします
-
menuItem
のイベントが発生、ドロップダウンを展開します -
body
のイベントが発生、ドロップダウンを閉めます
ドロップダウンは開けてすぐに閉めます、画面には何も発生してないように見えてきます
そして、こんな不具合を防ぐために、以下のように調整します
ボタンのクリックイベントは、body
に伝わないようにします
e.stopPropagation()
を加えます
menuItem.addEventListener(
'click',
function(e) {
+ e.stopPropagation();
menuChild.hidden = !menuChild.hidden;
console.log('menu event');
},
false
)
ちなみに、ドロップダウンをクリックするとドロップを閉めてしまいますので
以下のコードを加えます
menuChild.addEventListener(
'click',
function(e) {
e.stopPropagation();
},
false,
)
そうすると動きが正常になりました
Discussion