addEventListener とは何か
addEventListener は「イベントが起きたときに実行する処理(リスナー)を登録する」ためのメソッドです。クリック、入力、スクロール、ロードなど、ブラウザやユーザーの動きを“合図”として受け取り、あなたのコードを走らせます。ここが重要です:要素や window に対して「どのイベント名で」「どの関数を」「どんな条件(オプション)」で動かすかを宣言します。宣言型にすることで、コードが読みやすく保守しやすくなります。
基本の使い方(要素+イベント名+関数)
クリックに反応させる
<button id="buy">購入</button>
<script>
const btn = document.getElementById("buy");
btn.addEventListener("click", () => {
btn.disabled = true;
btn.textContent = "購入済み";
});
</script>
HTML短い処理なら無名関数で十分です。ここが重要です:addEventListener(“click”, 関数) の形を体で覚えましょう。これがイベント処理の出発点です。
別関数を定義して登録する(後で外せる)
<input id="q" placeholder="検索">
<script>
const q = document.getElementById("q");
function onInput(e) {
console.log("入力中:", e.target.value);
}
q.addEventListener("input", onInput);
// もう要らなくなったら取り外せる
// q.removeEventListener("input", onInput);
</script>
HTMLここが重要です:取り外し(removeEventListener)したい場面では「同じ関数参照」を使う必要があります。無名関数をその場で渡すと“同一参照”がないため外せません。
イベントオブジェクト(e)を使いこなす
どの要素で何が起きたか、詳細が入っている
<form id="f">
<input id="email" type="email">
<button>送信</button>
</form>
<script>
document.getElementById("f").addEventListener("submit", (e) => {
e.preventDefault(); // 既定の送信を止める
const input = e.target.email; // form の中の要素にアクセス
console.log("送る前の値:", input.value);
});
</script>
HTMLここが重要です:e はイベントの“文脈”。preventDefault で既定動作を止め、target/currentTarget で要素を区別し、必要な情報に素早くアクセスします。
target と currentTarget の違い
<ul id="list">
<li>りんご</li>
<li>バナナ</li>
</ul>
<script>
const list = document.getElementById("list");
list.addEventListener("click", (e) => {
console.log("クリックされた具体的要素:", e.target); // 実際のクリック先
console.log("リスナーが付いている要素:", e.currentTarget); // UL
});
</script>
HTMLここが重要です:イベント委譲(親に付けて子の動きに反応)では、target を使って“どの子が操作されたか”を判定します。currentTarget は“リスナーの所有者”です。
代表的なイベントと使いどころ
入力系(input、change、composition)
<input id="age" type="number">
<script>
const age = document.getElementById("age");
age.addEventListener("input", () => console.log("タイプ中:", age.value));
age.addEventListener("change", () => console.log("確定後:", age.value));
age.addEventListener("compositionend", () => console.log("IME確定"));
</script>
HTMLここが重要です:input は“逐次”、change は“確定”。日本語入力は composition 中は未確定なので、精密な検証は compositionend 以降が安全です。
マウス/キーボード(click、keydown、keyup)
<button id="save">保存</button>
<script>
const save = document.getElementById("save");
save.addEventListener("click", onSave);
document.addEventListener("keydown", (e) => {
if (e.key === "s" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); onSave(); }
});
function onSave() { console.log("保存しました"); }
</script>
HTMLここが重要です:キーボードショートカットは key と修飾キー(ctrlKey、metaKey、shiftKey、altKey)で判定します。既定動作が重なる場合は preventDefault を忘れずに。
画面読み込み(DOMContentLoaded、load)
<script>
document.addEventListener("DOMContentLoaded", () => {
// DOM が構築された直後(画像などの読み込み完了は待たない)
});
window.addEventListener("load", () => {
// ページの全リソース読み込み完了後
});
</script>
HTMLここが重要です:DOM を操作するだけなら DOMContentLoaded が速くて十分。画像・CSS まで待つ必要がある処理は load を使います。
オプションを使いこなす(once、passive、capture)
一度だけ動かしたいなら once
<button id="once">一度だけ</button>
<script>
const btn = document.getElementById("once");
btn.addEventListener("click", () => console.log("最初の一回だけ"), { once: true });
</script>
HTMLここが重要です:初回だけの案内やチュートリアルに有効。明示的な remove 不要で後始末が楽になります。
スクロール性能を守るなら passive
window.addEventListener("scroll", () => {
// 軽い処理のみ(preventDefault はしない)
}, { passive: true });
JavaScriptここが重要です:passive: true は「このリスナーではスクロールを止めない」という宣言。ブラウザが最適化でき、スクロールのカクつきを減らします。
伝播段階の制御(capture)
document.addEventListener("click", (e) => {
console.log("キャプチャ段階");
}, { capture: true });
JavaScriptここが重要です:イベントは「キャプチャ → ターゲット → バブリング」と伝播します。特殊な要件で“先に受けたい”ときだけ capture を使い、通常は不要です。
イベント伝播の制御(stopPropagation と preventDefault)
既定動作を止める
<a id="link" href="/next">次へ</a>
<script>
document.getElementById("link").addEventListener("click", (e) => {
e.preventDefault(); // ページ遷移を止める
console.log("SPA 内で処理");
history.pushState({}, "", "/next");
});
</script>
HTMLここが重要です:リンクやフォームの“既定動作”をカスタム処理に置き換えるときの基本が preventDefault。明確な意図がある場合にのみ使用します。
上位へ伝播させない
<div id="outer">
<button id="inner">クリック</button>
</div>
<script>
outer.addEventListener("click", () => console.log("外側"));
inner.addEventListener("click", (e) => {
e.stopPropagation(); // 外側へ伝わらない
console.log("内側のみ");
});
</script>
HTMLここが重要です:イベント委譲を使っている場面で“特定の場合だけ外側を動かしたくない”ときに使います。乱用はデバッグを難しくします。
イベント委譲(後から増える要素にも効かせる)
親に一つだけリスナーを付けて、子の操作に反応
<ul id="items"></ul>
<script>
const list = document.getElementById("items");
list.addEventListener("click", (e) => {
const btn = e.target.closest(".delete");
if (!btn) return;
const row = btn.closest("li");
row?.remove();
});
// 後から追加しても動く
const li = document.createElement("li");
li.innerHTML = `りんご <button class="delete">削除</button>`;
list.appendChild(li);
</script>
HTMLここが重要です:大量の子に個別リスナーを付けるより、親でまとめて処理する方が軽く、動的追加にも強い。closest を使って“対象の塊”に辿るのがコツです。
よくある落とし穴と回避策
無名関数だと remove できない
「外したいイベント」は必ず“名前付き関数”を渡します。ここが重要です:removeEventListener は“同じ参照”が必要。関数を変数に保持して使い回します。
this ではなく e.currentTarget を使う
アロー関数では this が変わるため、ターゲット要素は e.currentTarget を使う癖をつけると混乱しません。ここが重要です:文脈依存を避けると、コードが安定します。
重い処理を直接書かない
スクロールや入力のリスナーに“重い計算”を直書きすると体感が悪化します。ここが重要です:軽量化(passive)、間引き(debounce/throttle の実装)、フラグメントへのバッチ更新で滑らかに保ちましょう。
実践例(フォーム検証、ショートカット、ロード表示)
入力をトリムしてボタンを有効化
<input id="email" type="email" required>
<button id="next" disabled>次へ</button>
<script>
const email = document.getElementById("email");
const next = document.getElementById("next");
email.addEventListener("input", () => {
const v = email.value.trim();
next.disabled = !(v && email.validity.valid);
});
</script>
HTMLここが重要です:イベントで“状態を同期”する。視覚(ボタン文言・有効/無効)と検証結果を同じロジックで制御するとズレません。
Ctrl/⌘+S で保存
<script>
function save() { console.log("保存"); }
document.addEventListener("keydown", (e) => {
if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "s") {
e.preventDefault();
save();
}
});
</script>
HTMLここが重要です:修飾キーと key を組み合わせ、既定の“ブラウザ保存”を止めてアプリ側にハンドオーバーします。
送信ボタンのローディング表示
<button id="send">送信</button>
<script>
const send = document.getElementById("send");
send.addEventListener("click", async () => {
send.disabled = true;
send.textContent = "送信中…";
try { await new Promise(r => setTimeout(r, 800)); }
finally { send.disabled = false; send.textContent = "送信"; }
});
</script>
HTMLここが重要です:イベントで開始→終了の“単一情報源”を作り、視覚と操作不可を同時に切り替えます。
まとめ
addEventListener は「イベント名・処理関数・オプション」を宣言して、UI の動きをコードに結びつける基本メソッドです。e(イベントオブジェクト)で文脈を扱い、preventDefault/stopPropagation で動作と伝播を制御。once/passive/capture で細やかなチューニング、removeEventListener で後片付け、委譲で動的要素にも対応する。重要なのは“状態を一つのロジックで同期する”こと。これを身につければ、初心者でも滑らかで壊れにくいインタラクションを作れます。

