[JavaScript講座] イベントとブラウザAPI

当ページのリンクには広告が含まれています。
目次

イベントとは何か

イベント定義

「ブラウザ内で起こった何か(ユーザー操作・読み込み完了など)」をJavaScript が通知として受け取るための仕組み

代表例:

  • ユーザー操作
    • click, dblclick, mousedown, mouseup
    • keydown, keyup, input, change
    • submit(フォーム送信)
  • ドキュメントやリソースの状態変化
    • load, DOMContentLoaded, error
  • スクロールやサイズ変更
    • scroll, resize
  • その他
    • hashchange, popstate(URL変化)
    • focus, blur など

JS から見ると、「イベントが起きたときに呼ばれる関数(イベントリスナ)」を登録しておき、
ブラウザが適切なタイミングで実行してくれる、という形になります。

イベントリスナの基本:addEventListener

基本形

構文:

target.addEventListener(type, listener, options?);
  • target:イベントを受け取る対象(Element, window, document など)
  • type:イベント名("click", "input" など)
  • listener:イベント発生時に呼ばれる関数((event) => { ... }
  • options(省略可):オプション(capture, once, passive など)

例:

const button = document.querySelector("#myButton");

button.addEventListener("click", () => {
  console.log("ボタンがクリックされました");
});

重要ポイント:

  • HTMLに onclick="..." と書く「インラインイベント」は、基本的に避ける(保守性・セキュリティ的に弱い)
  • JS側で addEventListener を使うのが現代的な標準

リスナの削除:removeEventListener

function handleClick() {
  console.log("クリック!");
}

button.addEventListener("click", handleClick);

// 後で解除
button.removeEventListener("click", handleClick);
  • 同じ関数オブジェクトを渡さないと解除できません
  • 無名関数(() => {})を直接渡すと、あとから解除しにくい

once オプション(一度だけ実行)

button.addEventListener(
  "click",
  () => {
    console.log("最初の1回だけ反応");
  },
  { once: true }
);
  • { once: true } を指定すると、1回実行されたあと自動で remove される
  • 「1回だけの確認ダイアログ」や「初期化処理」などに便利

イベントオブジェクトと this / target / currentTarget

イベントオブジェクト event

リスナには、ブラウザから イベントの情報を持ったオブジェクト が渡されます。

button.addEventListener("click", (event) => {
  console.log(event.type); // "click"
  console.log(event.target); // 実際にクリックされた要素
});

click イベントの場合に代表的なプロパティ:

  • event.type:イベントの種類(”click” など)
  • event.target:イベントの発生元(実際にクリックされた要素)
  • event.currentTarget:このリスナが紐付いている要素
  • マウス系:clientX, clientY, button など
  • キー系:key, code, altKey, ctrlKey, shiftKey など

targetcurrentTarget の違い

<ul id="list">
  <li>アイテム1</li>
  <li>アイテム2</li>
</ul>
const list = document.querySelector("#list");

list.addEventListener("click", (event) => {
  console.log("target:", event.target);         // 実際にクリックされた<li>など
  console.log("currentTarget:", event.currentTarget); // このリスナが付いている<ul>
});
  • target:イベントを最初に発生させた要素
  • currentTarget:どの要素のリスナがいま実行中か

後述するイベント伝播を理解すると、この違いがよりクリアになります。

this の意味(function vs アロー関数)

通常の function で書いたとき:

button.addEventListener("click", function (event) {
  console.log(this === event.currentTarget); // true
});
  • 非strictな古めの挙動もありますが、イベントハンドラ内の this
    基本的には event.currentTarget を指す、と覚えておいてOKです。

アロー関数の場合:

button.addEventListener("click", (event) => {
  console.log(this); // 外側のthisをキャプチャする(通常undefined)
});
  • アロー関数は this を自前で持たない(レキシカルthis)
  • イベントハンドラで this を使いたいなら、function構文の方が分かりやすいことがありますが、
    普段は event.currentTarget を参照すれば十分です。

イベント伝播:キャプチャリングとバブリング

3段階の伝播

DOMイベントは、1回のイベントで次のような流れで伝わります:

  1. キャプチャフェーズ
    windowdocument → … → 親要素 → … → 目的の要素まで下りてくる
  2. ターゲットフェーズ
    目的の要素そのもの
  3. バブリングフェーズ
    目的の要素から、親 → さらに親 → … → documentwindow と上に上がっていく

多くの場合、開発で意識するのは バブリング です。

デフォルトは「バブリングフェーズで発火」

parent.addEventListener("click", handler);
child.addEventListener("click", handler);

通常は、子要素がクリックされると:

  1. まず子要素の click リスナ
  2. それから親要素の click リスナ
  3. さらに上の親… という順に呼ばれる(バブリング)

capture オプションでキャプチャフェーズを使う

parent.addEventListener(
  "click",
  (event) => {
    console.log("キャプチャ phase");
  },
  { capture: true }
);
  • { capture: true } を指定すると、キャプチャフェーズで実行される
  • addEventListener(type, listener, true) と書く古い書き方もあります

たとえば:

parent.addEventListener(
  "click",
  () => console.log("parent capture"),
  { capture: true }
);

child.addEventListener("click", () => console.log("child bubble"));
parent.addEventListener("click", () => console.log("parent bubble"));

子をクリックしたときの順序:

parent capture
child bubble
parent bubble

event.stopPropagation() / stopImmediatePropagation()

  • event.stopPropagation()
    → これ以上、上位(または下位)の要素へイベントを伝播させない
child.addEventListener("click", (event) => {
  event.stopPropagation();
  console.log("child only");
});

parent.addEventListener("click", () => {
  console.log("parent"); // 呼ばれない
});
  • event.stopImmediatePropagation()
    → 同じ要素に複数リスナがある場合でも、残りのリスナも実行させない

なるべく濫用は避けて、「本当にここで止めないとまずい」ケースに限定するのがよいです。

デフォルトアクションと preventDefault

多くのイベントには「ブラウザ側の標準動作(デフォルトアクション)」があります。

  • <a href="..."> のクリック → ページ遷移
  • <form> の submit → フォーム送信(ページリロード)
  • input type="checkbox" のクリック → チェックON/OFF

これをキャンセルしたいときに使うのが event.preventDefault()

フォーム送信をJSで制御する例

<form id="loginForm">
  <input name="user" />
  <button type="submit">送信</button>
</form>
const form = document.querySelector("#loginForm");

form.addEventListener("submit", (event) => {
  event.preventDefault(); // 標準の送信(ページリロード)を止める
  console.log("ここでAJAX送信などを行う");
});

リンクのクリックを無効化する例

const link = document.querySelector("#dangerLink");

link.addEventListener("click", (event) => {
  event.preventDefault();
  console.log("本当は遷移させたくない");
});

代表的なイベント種別

よく使うイベントだけ、特徴をざっくり整理しておきます。

マウス・ポインタ

  • click:クリック完了時(基本これを使えば良い場面が多い)
  • dblclick:ダブルクリック
  • mousedown / mouseup:ボタン押下・解放
  • mousemove:マウス移動(高頻度なので処理は軽く)
  • mouseenter / mouseleave:要素の境界をまたいだ時(バブリングしない)
  • mouseover / mouseout:子要素にも反応(バブリングする)

キーボード

input.addEventListener("keydown", (event) => {
  console.log(event.key);  // "a", "Enter", "Escape" など
  console.log(event.code); // "KeyA", "Enter" など物理キーに対応
});
  • keydown:キーが押された瞬間
  • keyup:キーが離された瞬間
  • keypress:古いイベント(今は keydown / keyup 前提でOK)

フォーム・入力系

  • input:入力値が変わったタイミング(ほぼリアルタイム)
  • change:入力が確定したタイミング(blur や Enterなど)
  • submit:フォーム送信ボタン or Enter で送信される直前
const input = document.querySelector("#name");

input.addEventListener("input", (e) => {
  console.log("入力中:", e.target.value);
});

input.addEventListener("change", (e) => {
  console.log("確定:", e.target.value);
});

ドキュメント読み込み系

  • DOMContentLoaded:HTMLがパースし終わり、DOM構造が使えるようになったとき
  • load:画像なども含めた全てのリソース読み込み完了
document.addEventListener("DOMContentLoaded", () => {
  console.log("DOM 構築完了、ここで初期化してOK");
});

タイマーとアニメーション:setTimeout / setInterval / requestAnimationFrame

これらは「イベントと実行モデル」の延長として押さえておきたいブラウザAPIです。

setTimeout / setInterval

const id = setTimeout(() => {
  console.log("1秒後に1回だけ");
}, 1000);

// 途中でキャンセル
clearTimeout(id);
const id2 = setInterval(() => {
  console.log("1秒ごとに繰り返し");
}, 1000);

// 止める
clearInterval(id2);
  • タイマー満了=「タスクキューにコールバックが積まれる」
  • setInterval は「積み残し」が出やすいので、
    コマ落ちしないアニメーションには後述の requestAnimationFrame が向いています。

requestAnimationFrame(描画に同期したコールバック)

function loop(timestamp) {
  // timestamp: ページロードからのミリ秒(高精度)
  console.log("frame:", timestamp);

  requestAnimationFrame(loop); // 次のフレームも予約
}

requestAnimationFrame(loop);
  • ブラウザの再描画タイミング(通常は60fps前後)に合わせて呼ばれる
  • スクロール・アニメーション・ゲームなど、滑らかな描画 が必要な時に使う

代表的なブラウザAPI

「これから詳しく学ぶときの見取り図」として、よく使うWeb APIを整理します。

ネットワーク系

  • fetch(url, options)
    • HTTPリクエストを送るモダンAPI(Promiseベース)
    • response.json(), response.text() などで結果を取り出す
      -(古い)XMLHttpRequest

ストレージ・状態管理

  • localStorage
    • ブラウザに永続的なキー値ストレージ(文字列のみ)
    • タブを閉じても残る
  • sessionStorage
    • タブ(セッション)単位のストレージ
    • タブを閉じると消える
localStorage.setItem("username", "Taro");
const name = localStorage.getItem("username");
localStorage.removeItem("username");

ウィンドウ・ナビゲーション

  • location
    • 現在のURL(location.href, location.pathname など)
    • location.href = "..." で遷移
  • history
    • 戻る・進む(history.back(), history.forward()
    • SPA で pushState / replaceState を使うことも多い
  • navigator
    • ユーザーエージェント・言語・オンライン状態など

その他 ざっくり

  • Canvas API<canvas> の2D描画)
  • Web Audio API(音声処理)
  • Geolocation API(位置情報:HTTPSのみ)
  • WebSocket(双方向通信)
  • IntersectionObserver(要素がビューポートに入ったかどうか)

全部を一気に覚える必要はなく、「こういうジャンルがある」とだけ押さえておけば十分です。


<<前へ(DOM操作の基礎)

>>次へ(Node.jsの基本)

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次