この記事では、JavaScriptのイベント処理について、実務でよく使う応用テクニックを解説します。
イベントオブジェクト、伝播の仕組み、onceオプションや動的要素へのイベント付与など、実務で知っておきたい4つのポイントを中心に紹介していきます。
解説:
イベントリスナーで渡される引数(通常 e や event)には、イベントの詳細な情報が入っています。
これを イベントオブジェクト と呼び、クリックした要素や、デフォルト動作を止めるなど、様々な操作に使えます。
クリックされた要素を取得して表示する例です:
<ul id="fruit_menu">
<li>りんご</li>
<li>みかん</li>
<li>バナナ</li>
</ul>
const menu = document.querySelector('#fruit_menu');
menu.addEventListener('click', (event) => {
const clicked = event.target; // クリックされた要素を取得
alert('「' + clicked.textContent + '」がクリックされました'); // クリックされた項目の内容を表示
});上記のように、イベントオブジェクトの event.target を使えば、押された要素そのものが取得できます。
【実行例】果物リストをクリックしてみよう
リンクやフォームなど、ブラウザが本来持っている挙動を止めたいときに使います:
<a href="https://webtech-village.jp/" id="test_link">リンク</a>
const link = document.querySelector('#test_link');
link.addEventListener('click', (event) => {
event.preventDefault(); // リンク先へ移動しない
alert('リンクは無効化されました');
});
preventDefault() を使うと、本来の動作をキャンセルできます。
フォーム送信時の確認処理や、ページ遷移を止めたいときによく使われます。
イベントオブジェクトを使うことで、次のようなことが可能になります:
これらは、フォーム・リンク・メニュー処理など実務でも非常に多用されます。ぜひ覚えておきましょう!
解説:
JavaScriptのイベントは、要素の階層を上下に伝わる性質があり、これをイベントの伝播と呼びます。
これには、2つのフェーズが存在します:
イベントリスナーは通常「バブリングフェーズ」で動作しますが、オプションを指定することでキャプチャリングにも対応できます。
クリックイベントが、内側の要素から順に親へ伝わっていく様子です。
<div id="outer">
<div id="inner">
ボタン
</div>
</div>
const outer = document.querySelector('#outer');
const inner = document.querySelector('#inner');
outer.addEventListener('click', () => {
console.log('outerがクリックされました');
});
inner.addEventListener('click', () => {
console.log('innerがクリックされました');
});【出力例(innerをクリックしたときのconsole出力)】
innerがクリックされました
outerがクリックされましたこのように、子要素(inner)で発生したイベントが親要素(outer)にも伝わっているのがバブリングです。
addEventListener の第3引数(またはオプションオブジェクト)で capture: true を指定すると、キャプチャリングフェーズで実行されます。
outer.addEventListener('click', () => {
console.log('outer(capture)');
}, { capture: true });
inner.addEventListener('click', () => {
console.log('inner(bubble)');
});【出力例(innerをクリック)】
outer(capture)
inner(bubble)このように、キャプチャリングは先に親要素でイベントが発火します。
ある要素でイベントの伝播を途中で止めたい場合は、event.stopPropagation() を使います。
inner.addEventListener('click', (e) => {
e.stopPropagation(); // これで外側には伝播しない
console.log('innerだけ処理されました');
});これにより、親要素のリスナーは実行されません。親要素のイベントとバッティングさせたくないときなどに有効です。
イベントの流れを理解することで、親子要素のイベントの干渉を避ける実装ができるようになります。
解説:
通常のイベントリスナーは何度でも実行されますが、一度だけ処理したいケースもあります。
そんなときは、{ once: true } を指定することで、イベントリスナーが1回だけ実行された後、自動で無効になる設定が可能です。
ボタンを押したとき、最初の1回だけメッセージを表示する例です:
<button id="onceBtn">1回だけ反応</button>
const onceBtn = document.querySelector('#onceBtn');
onceBtn.addEventListener('click', () => {
alert('このボタンは1回だけ反応します');
}, { once: true });上記のように { once: true } をオプションに加えると、1回実行されたあと自動的にイベントが解除されます。
イベントリスナーの解除は自動で行われるため、2回目以降はイベントがバインドされていない状態になります。
【クリック1回目】 → アラートが表示される
【クリック2回目】 → 何も起きない
自分で removeEventListener を書かなくて済むので、一度限りの確認や初回のみの処理にとても便利です。
【実行例】ボタンをクリックしてみよう(1回だけ反応します)
{ once: true } はモダンブラウザ(Chrome, Firefox, Edgeなど)では対応していますが、古いInternet Explorerではサポートされていないため注意が必要です。
古い環境もサポートしたい場合は、removeEventListener を使って手動で削除しましょう。
{ once: true } は「一度だけ処理して自動で解除したいイベント」にとても便利です。
書き忘れがちな removeEventListener を自動で省略できるので、コードの見通しも良くなります。
解説:
JavaScriptでは、あとから動的に追加された要素には、あらかじめ設定しておいたイベントリスナーが反応しないことがあります。
これを解決するのがイベントデリゲーション(委任)というテクニックです。
次のコードでは、後から追加された要素にはイベントが効きません。
// ボタンを押すとliが追加される例
const ul = document.querySelector('#myList');
const btn = document.querySelector('#addItemBtn');
btn.addEventListener('click', () => {
const li = document.createElement('li');
li.textContent = '新しい項目';
ul.appendChild(li);
});
const items = document.querySelectorAll('#myList li');
items.forEach(item => {
item.addEventListener('click', (event) => {
alert('クリックされました');
});
});
これでは querySelectorAll で取得した時点に存在する要素しか対象にならないため、あとから追加した要素にはイベントが効きません。
【実行例】リストに項目を追加してクリックしてみよう(失敗する例)
個々の要素にイベントをつける代わりに、「親要素」にイベントリスナーを設定しておき、「子要素」がクリックされた場合も親側で処理を拾う方法 を、イベントデリゲーション(委任)と呼びます。
// 親要素にリスナーを設定(イベントデリゲーション)
ul.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
alert('「' + event.target.textContent + '」がクリックされました');
}
});
event.targetを使って、クリックされた具体的な子要素(liなど)を判定しています。
※tagNameの戻り値は常に大文字(UPPERCASE)のため、'LI' のように書く必要があります。
【実行例】リストに項目を追加してクリックしてみよう(成功する例)
イベントデリゲーションを使えば、コードをシンプルに保ちながら、動的に変化するUIにも柔軟に対応できるようになります。
大規模アプリや動的なページ構成では、最重要テクニックの1つといえるでしょう。
解説:
この記事では、イベント処理に関する応用テクニックを段階的に学んできました。
改めて、ここで紹介したポイントを振り返っておきましょう。
これらはすべて、実務でも頻繁に登場するイベント操作です。
特に 伝播とデリゲーション は、動的UIやコンポーネント設計において必須の知識といえるでしょう。
イベントの流れと仕組みを理解することで、思い通りにユーザーインターフェースを制御できるようになります。
エラーの防止やコードの保守性にも大きく関わる重要なテーマです。
次は、フォーム操作・バリデーションをテーマに、イベントの応用テクニックをさらに実践的に掘り下げていきましょう。
実際の業務でもよく出てくる「ラジオボタン」「セレクトボックス」「入力チェック」などにチャレンジしていきます!