JavaScriptのイベントリスナー:クリック、送信、スクロール、委譲
JavaScriptのイベントリスナー
JavaScriptのイベントリスナー:クリック、送信、スクロール | We.Inc
イベントの発火をライブログで確認し、クリック、送信、スクロール、イベント委譲、once、passive、AbortControllerでの後片付けに使えるイベント登録のパターンをコピーできます。
イベントリスナーとは、クリック、フォームの送信、スクロールなど、要素に何かが起きたときにブラウザーが呼び出す関数です。element.addEventListener(type, handler, options) で登録します。オプションのオブジェクトでonce、passive、capture、中断用のシグナルを有効にでき、後でremoveEventListenerを使えば同じ関数を再び取り外せます。
addEventListenerのオプション
- false(window、document、body上のwheelとtouchではtrue)
- preventDefaultを呼ばないと約束するので、スクロールが待たされない
- ターゲットから戻る途中ではなく、ターゲットへ下りる途中で実行する
- AbortSignalを渡す。中断するとリスナーが削除される
イベントは目で見ると理解しやすくなります。下のイベントログは、小さなテストエリアでのリスナーの呼び出しをすべて記録します。クリック、入力、送信、スクロールをして、順序、ターゲット、各オプションの効果を確かめてください。その後、実際に必要な用途のパターンをコピーしましょう。
- テストエリアの操作部品を使います。ボタンをクリックし、入力欄に入力し、フォームを送信し、ボックスをスクロールします。
- リスナーが呼ばれるたびに、イベントの種類、イベントを起こした要素、処理した要素がログに表示されます。
- onceをオンにすると1回の呼び出しでリスナーが消える様子を、委譲をオフにするとリストが項目ごとにクリックを処理する様子を確認できます。
- 下の例はどれでもコピーできます。どれもライブラリを使わない素のJavaScriptです。
- リスナーを後で削除するつもりなら、名前付きの関数を渡しましょう。インラインのアロー関数は、後から同じものとして照合できません。
- AbortControllerなら1回の中断呼び出しでリスナーのグループをまとめて削除できるので、マウントとアンマウントを繰り返すコンポーネントに向いています。
- ボタンのクリックではなくフォームの送信イベントを監視しましょう。そうすれば入力欄でEnterを押した場合も処理できます。
- 委譲したハンドラーではイベントのターゲットからclosestで祖先を探しましょう。ボタン内のアイコンをクリックしても、ちゃんとボタンが見つかります。
- フォーカスの取得と喪失のイベントはバブリングしません。代わりにfocusinとfocusoutを委譲しましょう。
よくある質問
イベント委譲とは何ですか?
すべての項目にリスナーを付ける代わりに、共通の親に1つだけ付ける方法です。ほとんどのイベントはバブリングするので、親は後から追加された項目も含め、すべての子からのクリックを受け取れます。どれがクリックされたかは、イベントのターゲットで判別します。
removeEventListenerでリスナーが削除されないのはなぜですか?
登録時に渡したものと同じ関数の参照と、同じキャプチャの設定を渡す必要があります。中身がまったく同じアロー関数でも2つあれば別の関数なので、ハンドラーは一度だけ定義し、その変数を両方に渡しましょう。
passive: true は何をしますか?
ハンドラーがpreventDefaultを呼ばないことをブラウザーに伝えます。そのため、ページはコードの終了を待たずにすぐスクロールを始められます。ウィンドウ、ドキュメント、body上のホイールとタッチのリスナーは、ブラウザーがすでにデフォルトでpassiveにしています。
targetとcurrentTargetの違いは?
前者はイベントが始まった最も内側の要素で、イベントがバブリングしても変わりません。後者は今まさにリスナーが実行されている要素で、階層ごとに変わります。
form.submit() で送信イベントは発火しますか?
いいえ。スクリプトからform.submit()を呼ぶと、送信イベントも検証も飛ばされます。送信のリスナーと組み込みのチェックを実行したいときは、form.requestSubmit()を呼びましょう。
addEventListenerとonclick、どちらを使うべきですか?
onclickプロパティは関数を1つしか保持できないため、2つ目を代入すると1つ目が置き換わります。こちらなら、独立した複数のリスナーで1つの要素を共有でき、オプションのオブジェクトにも対応しているので、デフォルトの選択として優れています。
イベントが伝わる流れ
- 発行されたイベントは3つのフェーズで移動します。キャプチャフェーズでウィンドウからターゲットへ下り、ターゲットに到達し、その後バブリングで各祖先を通って上へ戻ります。キャプチャを指定しない限り、リスナーはバブリングフェーズで実行されます。
- stopPropagationはこの移動を止めるので、祖先にはイベントが届きません。ツリーの上位にある委譲したリスナーや分析ツールが黙って動かなくなるため、使うのはまれにしましょう。
ページを遅くせずにスクロールを扱う
- スクロールイベントは、動きの1フレームの間に何度も発火することがあります。ハンドラーはごく小さく保ち、レイアウトを書き換えるのではなく位置を読み取るだけにして、見た目の更新はrequestAnimationFrameの中でまとめて行いましょう。
- 画面に入った要素を表示するような用途では、スクロールのたびに計測するより、IntersectionObserverのほうが通常は軽く済みます。MDNによると2025年12月からBaselineとなったscrollendイベントは、動きが止まったときに1回だけ発火します。
リスナーの後片付け
- ウィンドウやドキュメントのような長く存在するオブジェクト上のリスナーは、ハンドラーと、それが参照するものすべてをメモリに残し続けます。リスナーを必要としていたページの部分がなくなったら、削除しましょう。
- signalオプションを使うとすっきり片付きます。機能ごとにAbortControllerを1つ作り、そのシグナルをすべてのリスナーに渡し、終了処理で中断を1回呼び出します。
よく使うイベントの種類
よく使うイベントと、それを監視する場所
- ポインターを押して離したとき、またはボタン上でEnterかSpaceを押したとき
- する
- 訪問者の入力に合わせて入力欄の値が変わったとき
- する
- フォーカスが外れたときや選択時など、入力欄の値が確定したとき
- する
- フォームが送信されたとき。フォーム要素で発火する
- する
- focus / blur
- 要素がフォーカスを得たとき、または失ったとき
- しない
- focusin / focusout
- フォーカスの取得、喪失と同じだがバブリングする
- する
- DOMContentLoaded
- HTMLの解析が終わり、遅延スクリプトが実行されたとき。documentで監視する
- 関係なし
コピーして使えるパターン
削除できる名前付きハンドラーでのクリック
関数を変数に保持しておくことが、リスナーを削除できる理由です。
再読み込みなしでフォームの送信を処理する
preventDefaultはブラウザー自身のページ移動を止めます。どの送信ボタンが使われたかは、イベントのsubmitterでわかります。
リストでのイベント委譲
リスト上の1つのリスナーが、ページ読み込み後に追加された行も含め、すべての削除ボタンを処理します。
1フレームに1回の更新に間引いたパッシブなスクロールリスナー
passive: true でスクロールをすぐ始められ、requestAnimationFrameで処理を1フレームに1回に抑えます。
onceとAbortController
最初のリスナーは1回だけ実行されます。ほかのリスナーは、1回の中断呼び出しでまとめて削除されます。
入力欄での入力を無視するキーボードショートカット
ターゲットを確認することで、検索ボックスにスラッシュを入力している最中にショートカットが発動するのを防ぎます。
ボタンでクリック:ターゲット {target}
(once:削除済み)
クリックがテストエリアに到達({phase}フェーズ):ターゲット {target}、現在のターゲット {current}
入力:値は現在「{value}」
変更:値が確定
フォームで送信、送信元 {submitter}。既定の動作の取り消しで再読み込みを停止
スクロール(パッシブ、1フレームに1回):スクロール位置 {n}
リストで委譲されたクリック:項目 {item}
項目ごとのリスナー:{item}
ライブイベントログ
テストエリアでクリック、入力、送信、スクロールをしてみてください。リスナーの呼び出しはすべて、種類、ターゲット、現在のターゲットとともにログに書き込まれます。
リスナーのオプション
ボタンにonce
エリアにcapture
リストに委譲
クリックしてね
ここに入力
送信
委譲のリスト
リスト項目を追加
項目 {n}
スクロールボックス
スクロール行 {n}
ログ(新しい順)
ログを消去
まだイベントはありません。
無料で始める · クレジットカード不要
関連: ガイド|Webマーケティングと集客を学ぶ
製品
ご利用いただける方
機能
リソース
会社情報
サイトマップを見る