EventTargetとは
EventTargetはイベントのターゲットとなるオブジェクトです。 イベントリスナーの登録や削除を行えます。
EventTargetのメソッド
addEventListener - イベントリスナの登録
addEventListenerの第1引数にイベントの名称、 第2引数にイベント発生時に実行する関数を指定する事でイベントの登録が行なえます。
例えば、クリックのイベントは以下のように登録できます。 buttonAをクリックするとdiv要素のクリックイベントも呼び出されます。
<div id="outer">
<div id="inner">
<button id="buttonA">A</button>
</div>
</div>
document.getElementById('outer').addEventListener('click',function(){console.log('outer');});
document.getElementById('inner').addEventListener('click',function(){console.log('inner');});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA');});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');});
//buttonAをクリックする => buttonA buttonA2 inner outer
第3引数としてbooleanを指定可能で、上記はfalseを指定した以下と同様です。
document.getElementById('outer').addEventListener('click',function(){console.log('outer');},false);
document.getElementById('inner').addEventListener('click',function(){console.log('inner');},false);
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA');},false);
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');},false);
//buttonAをクリックする => buttonA buttonA2 inner outer
第3引数としてtrueを指定すると、実行の順序が逆になります。
document.getElementById('outer').addEventListener('click',function(){console.log('outer');},true);
document.getElementById('inner').addEventListener('click',function(){console.log('inner');},true);
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA');},true);
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');},true);
//buttonAをクリックする => outer inner buttonA buttonA2
イベントリスナーが登録されていると、イベント発生元となった要素を含む親の要素でもそのイベントが実行されます。 そのイベントの実行順序が3つ目の引数で制御できるようになっています。
イベントの伝播はwindowオブジェクトからイベント発生元まで下位へ辿っていくキャプチャーフェーズと、 イベント発生元から上位要素へと辿っていくバブリングフェーズがあります。 つまり、「ouuter -> inner -> buttonA -> inner -> outer」の順序でイベントが伝播し、 前半がキャプチャーフェーズ、後半がバブリングフェーズとなっています。 引数をtrueとするとキャプチャーフェーズでイベントが実行されるため順序が逆となったというわけです。
もちろん混在も可能で、次のようにすると「outer -> buttonA -> inner」と実行がされます。
document.getElementById('outer').addEventListener('click',function(){console.log('outer');},true);
document.getElementById('inner').addEventListener('click',function(){console.log('inner');},false);
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA');});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');});
//buttonAをクリックする => outer buttonA buttonA2 inner
イベントの伝播はstopPropagation()で止める事ができます。
document.getElementById('outer').addEventListener('click',function(){console.log('outer');});
document.getElementById('inner').addEventListener('click',function(e){console.log('inner');e.stopPropagation();});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA');});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');});
//buttonAをクリックする => buttonA buttonA2 inner
ただし、stopPropagation()だと同じ要素に登録したリスナーの実行は止められません。
document.getElementById('outer').addEventListener('click',function(){console.log('outer');});
document.getElementById('inner').addEventListener('click',function(){console.log('inner');});
document.getElementById('buttonA').addEventListener('click',function(e){console.log('buttonA');e.stopPropagation();});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');});
//buttonAをクリックする => buttonA buttonA2
同じ要素のリスナーも含め、イベントの実行を止めるには、stopImmediatePropagation()を使います。
document.getElementById('outer').addEventListener('click',function(){console.log('outer');});
document.getElementById('inner').addEventListener('click',function(){console.log('inner');});
document.getElementById('buttonA').addEventListener('click',function(e){console.log('buttonA');e.stopPropagation();});
document.getElementById('buttonA').addEventListener('click',function(){console.log('buttonA2');});
//buttonAをクリックする => buttonA
既定の動作、例えばチェックボックスクリック時のチェックを止めたい場合はpreventDefault()で処理を停止できます。
<label><input id="check" type="checkbox" />Check</label>
document.getElementById('check').addEventListener('click',function(e){e.preventDefault();});
addEventListenerの第3引数には、より複雑なオブジェクトをオプションとして指定する事もできます。
document.getElementById('outer').addEventListener('click',function(e){console.log('outer');e.preventDefault();},{
capture : true , once : true, passive :false,
});
document.getElementById('inner').addEventListener('click',function(e){console.log('inner');e.preventDefault();},{
capture : true , once : true, passive :true,
});
document.getElementById('buttonA').addEventListener('click',function(e){console.log('buttonA');e.preventDefault();},{
capture : true , once : false, passive :false,
});
//buttonAをクリックする(1回目) => outer inner (警告) buttonA
//buttonAをクリックする(2回目) => buttonA
「capture」は第3引数にbooleanを指定したときと同じものです。trueの場合にバブリングフェーズでのイベント実行が行われます。 「once」はtrueの場合、イベントの実行を1回行うとリスナは削除されます。 「passive」はtrueの場合、preventDefault()がリスナで呼ばれるとコンソールに警告が出力されます。
removeEventListener - イベントリスナの削除
removeEventListenerを使うと、指定したイベントからリスナを削除できます。
<div id="outer">
<div id="inner">
<button id="buttonA">A</button>
</div>
</div>
const clickListener1 = function(){console.log('buttonA1');};
const clickListener2 = function(){console.log('buttonA2');};
document.getElementById('buttonA').addEventListener('click',clickListener1);
document.getElementById('buttonA').addEventListener('click',clickListener2);
document.getElementById('buttonA').removeEventListener('click',clickListener1);
//buttonAをクリックする => buttonA2
第2引数を指定すると、キャプチャーフェーズで実行されるリスナであるかが一致する場合にだけ削除が行われます。
const clickListener1 = function(){console.log('buttonA1');};
const clickListener2 = function(){console.log('buttonA2');};
document.getElementById('buttonA').addEventListener('click',clickListener1,false);
document.getElementById('buttonA').addEventListener('click',clickListener2,true);
document.getElementById('buttonA').removeEventListener('click',clickListener1,false);
document.getElementById('buttonA').removeEventListener('click',clickListener2,false);
//buttonAをクリックする => buttonA2