カテゴリー

  • プログラミング
  • 英語学習
  • 海外
  • キャリア
  • Kredo
Kredoオンラインキャンプ
KredoIT留学
無料カウンセリングはこちら
Kredoオンラインキャンプ体験談
KredoIT留学体験談
外貨を稼ぐ!海外フリーランス無料セミナー
未経験から即戦力ITグローバル人材 無料セミナー
Kredo Blog 英語・IT・AIで、人生の選択肢を広げる。
無料ウェビナー参加 ↗ 無料カウンセリング予約無料相談↗
MENU
EXPLORE KREDO BLOG

知りたいことから、世界が広がる。

ブログTOP ↗
留学・セブSTUDY & LIFE
留学・セブの記事をすべて読む ↗ 海外留学→海外移住→海外就職→
英語学習ENGLISH
英語学習の記事をすべて読む ↗ 英語学習法→英語フレーズ→
IT・AITECH & CREATIVITY
IT・AIの記事をすべて読む ↗ プログラミング学習→プログラミング知識→AI・テクノロジー→デザイン→
キャリアYOUR NEXT CHAPTER
キャリアの記事をすべて読む ↗ 転職情報→キャリアデザイン→
KredoOUR SCHOOL
Kredoの記事をすべて読む ↗ ニュース・キャンペーン→セブ島情報→インタビュー→
STUDENT DIARIES留学生のリアルな日記noteの体験記を読む ↗YouTube・Instagramで留学を知る ↗
記事を探す ブログTOP
留学・セブ
STUDY & LIFEセブで学ぶ。海外で暮らす。留学の準備から、現地の毎日まで。
留学・セブを知るすべての記事 ↗
海外留学費用・期間・学校選びを知る↗海外移住海外で暮らすためのヒント↗海外就職世界で働く選択肢を探す↗
FROM CEBU / note留学生の、
リアルな毎日。
写真とことばで読む留学日記日記を読む ↗
英語学習
ENGLISH英語が、世界を近くする。学び方と、今日から使える英語。
英語学習を知るすべての記事 ↗
英語学習法自分に合った学び方を見つける↗英語フレーズ会話で使える表現を読む↗
FROM CEBU / note留学生の、
リアルな毎日。
写真とことばで読む留学日記日記を読む ↗
IT・AI
TECH & CREATIVITYつくる力を、次の一歩に。プログラミングとAIをもっと身近に。
IT・AIを知るすべての記事 ↗
プログラミング学習はじめ方・学び方を知る↗プログラミング知識仕組みやスキルを深める↗AI・テクノロジーAIの活かし方と最新の話題↗デザイン伝わるものづくりのヒント↗
FROM CEBU / note留学生の、
リアルな毎日。
写真とことばで読む留学日記日記を読む ↗
キャリア
YOUR NEXT CHAPTER学びの先の、働き方。転職・海外就職・これからのキャリア。
キャリアを知るすべての記事 ↗
転職情報次の仕事へ向かう準備↗キャリアデザイン自分らしい働き方を考える↗
FROM CEBU / note留学生の、
リアルな毎日。
写真とことばで読む留学日記日記を読む ↗
Kredo
OUR SCHOOLKredoを、もっと知る。学校のこと、セブのこと、学ぶ人のこと。
Kredoを知るすべての記事 ↗
ニュース・キャンペーンKredoからのお知らせ↗セブ島情報現地の暮らしを知る↗インタビュー受講生・卒業生の声を読む↗
FROM CEBU / note留学生の、
リアルな毎日。
写真とことばで読む留学日記日記を読む ↗
留学日記 ↗

ENGLISH · IT · AI / STUDY IN CEBU

学ぶって、冒険だ。

英語・IT・AIで、人生の選択肢を広げよう。

留学の無料相談へ ↗Kredo Blogを読む →
JAPAN✈CEBU
Kredoで、講師と一緒に英語とITを学ぶ受講生
LEARN SOMETHING NEW.
セブの海を望む場所で学ぶ日常
HELLO, NEW WORLD.
  • TOP
  • プログラミング
  • Web・プログラミング(学習)
  • JavaScriptのイベント委譲とは?追加したボタンが動く仕組みを実験

JavaScriptのイベント委譲とは?追加したボタンが動く仕組みを実験

アバター画像
さおり
公開日:2026.10.06
更新日:2026.10.06
プログラミング Web・プログラミング(学習) |
追加した項目の動きをノートで整理する学習者の写真イメージ

こんにちは!Kredo Blog編集部のさおりです!

最初からあるボタンは動くのに、JavaScriptで追加したボタンだけ反応しない。直したつもりが、今度はボタンの文字を押したときだけ動かない——クリック処理を書き始めると、こんな違いに出会います。

まず分けたいのは、処理をどこに登録したか、クリックがどこで起きたか、どの要素を処理対象と判断したかの3点です。イベント委譲は、このうち登録先を親要素にまとめ、子要素で起きたイベントを受け取る方法です。

この記事では、完了ボタンが並ぶ小さな一覧で3方式を比較します。追加・文字部分のクリック・伝播停止を試せる教材と練習4問を用意しました。通常のHTML内のclickを対象に、MDNの仕様説明とChromeでの実行結果を照らし合わせて進めましょう。

記事のもくじ

  • イベント委譲は、親で子のクリックを受け取る方法
  • 追加したボタンに処理が付いていない理由
    • 個別登録でも、作るたびに登録すれば動く
  • targetとcurrentTargetを押す場所で比べる
    • target自身がボタンかどうかだけでは足りない
  • closestでボタンを探し、対象を絞る
    • HTMLとJavaScriptを対応させる
  • 3方式をローカル教材で動かして比べる
    • 毎回リセットして、1つずつ条件を変える
  • 練習:追加・子要素・伝播停止を確かめる
    • 練習1:同じボタンでも、押す場所で変わるか
    • 練習2:追加したボタンを動かす方法を2つ挙げる
    • 練習3:子で伝播を止めるとどうなるか
    • 練習4:完了させない操作を確認する
  • イベント委譲でよくある質問
    • stopPropagationとpreventDefaultは同じですか?
    • すべてのイベントを親に登録できますか?
    • documentにまとめればよいですか?
    • イベント委譲は必ず速くなりますか?

イベント委譲は、親で子のクリックを受け取る方法

文字・ボタン・親の一覧へクリックが伝わる順を表した水彩図
内側の文字からボタン、親の一覧へclickが伝わる様子です。この図は、一覧までのバブリングに注目しています。

ボタンの中に文字用のspan、その外側に一覧のulがあるとします。spanをクリックしたとき、clickイベントはボタンを経由して親のulへ伝わります。このように内側から祖先へ伝わる段階をバブリングと呼びます。

イベント委譲では、この性質を使ってulにクリック処理を登録します。親で受け取った後に「完了ボタンの操作だったか」を判定し、該当する場合だけ行の表示を変えます。親に登録しただけでは、すべてのクリックを完了操作として扱うことになりかねません。受け取る場所と、処理する対象を選ぶ条件はセットです。

図では文字→ボタン→親の一覧までを描いています。実際の経路はそこで必ず終わるわけではありません。この記事は、一覧に登録した処理まで届くかに注目します。基本の説明はMDNのイベントバブリングと委譲で確認できます。

クリック処理自体が初めてなら、先にJavaScriptサンプルコード集のボタンやFAQを動かしてみてください。ここでは、その次の「要素が増えたとき、登録方法をどう考えるか」に進みます。

追加したボタンに処理が付いていない理由

親の一覧を残して新しい項目を追加する様子を表した水彩図
同じ親を残して子を追加する構成なら、親に登録した処理で新しい項目のクリックも受け取れます。

次のコードは、実行した時点で一覧にある完了ボタンを取得し、それぞれに処理を登録します。教材の「1. 最初のボタンに個別登録」は、この方法です。completeは、渡されたボタンが属する行を完了済みにする教材内の関数です。

list.querySelectorAll('button[data-action="complete"]').forEach(button => {
  button.addEventListener('click', event => {
    complete(event.currentTarget, event);
  });
});

querySelectorAll()が返すNodeListは、その時点の結果を持つ静的な一覧です。後からボタンを作っても、この一覧に自動追加されて処理が登録されるわけではありません。教材は違いを見るため、追加時の登録を意図的に省いています。MDN:querySelectorAll()

個別登録でも、作るたびに登録すれば動く

修正方法はイベント委譲だけではありません。新しいボタンを作った直後に、そのボタンへaddEventListenerで登録する方法もあります。少数の独立したボタンなら、個別登録のほうが処理の所在を読み取りやすいこともあります。

Kredo Blogの学習記録アプリの教材は、一覧を描画するときに編集・削除ボタンへ処理を登録する構成です。「個別登録だから追加要素は動かない」と決めつけず、作成時に登録しているかをコードで確かめましょう。

一方、同じ種類の項目を繰り返し追加する一覧では、残り続ける親に処理を置くと、追加のたびに完了処理を登録する手順をまとめられます。ただし、親のul自体を別の要素へ置き換えたら、古いulの登録が新しいulへ移るわけではありません。子を追加する場合と、親を作り直す場合は分けて考えてください。

targetとcurrentTargetを押す場所で比べる

ボタン内の文字とボタン全体を分けて見る水彩図
文字のspanが発生元でも、closestで外側の完了ボタンを探せます。文字とボタンは別の要素です。

見た目では同じ「完了」ボタンでも、内側のspanをクリックすると、イベントの発生元はspanになります。今回の教材では、文字を直接クリックしたときのtargetはSPAN、ボタンをキーボードのEnterで操作したときはBUTTONになりました。

targetはイベントの発生元、currentTargetは今実行しているハンドラーが登録された要素です。親に処理を登録すると、ボタン内の文字を押してもcurrentTargetはULです。MDN:target、MDN:currentTarget

操作と登録方法 target 完了処理のcurrentTarget
文字をクリック・ボタンに個別登録 SPAN BUTTON
文字をクリック・親でclosest SPAN UL
Enterで操作・親でclosest BUTTON UL

表が画面に収まらない場合は、横にスクロールできます。

target自身がボタンかどうかだけでは足りない

教材の2番目の方式は、親に登録しながら、target自身が完了ボタンかだけを調べます。

list.addEventListener('click', event => {
  if (!(event.target instanceof Element)) return;
  if (!event.target.matches('button[data-action="complete"]')) return;
  complete(event.target, event);
});

Enter操作ではtargetがBUTTONなので通ります。しかし文字部分をクリックするとSPANのため、条件に合わずreturnします。親に届いていないのではなく、届いた後の条件判定で除外している点が重要です。教材のlistReceivedがtrueでも、完了処理の回数は増えません。

なお、currentTargetを調べるのはハンドラー実行中です。後からイベントオブジェクトを見直すとnullになることがあります。教材では、その場で要素名を文字列として記録してから画面に表示しています。

closestでボタンを探し、対象を絞る

文字部分からボタンを探すには、closest()を使います。これは自分自身から祖先へ向かって条件に合う最も近い要素を探し、見つからなければnullを返します。子要素を探すメソッドではありません。MDN:closest()

HTMLとJavaScriptを対応させる

最小例では、行をli、完了操作をdata-action=”complete”、状態の表示を.stateで示します。以下のHTMLとJavaScriptは、教材のminimal.html / minimal.jsに対応しています。JavaScriptはこのHTMLが読み込まれた後に実行してください。教材ではdefer属性で読み込んでいます。

<ul id="simple-list">
  <li>
    <button type="button" data-action="complete"><span>完了</span></button>
    <span class="state">未完了</span>
  </li>
</ul>
const list = document.querySelector('#simple-list');
list.addEventListener('click', event => {
  if (!(event.target instanceof Element)) return;
  const button = event.target.closest('button[data-action="complete"]');
  if (!button || !list.contains(button)) return;

  const row = button.closest('li');
  if (!row || row.parentElement !== list) return;
  row.querySelector('.state').textContent = '完了済み';
});

処理は、発生元がElementか確認→最も近い完了ボタンを取得→一覧内のボタンか確認→直下のliか確認→その行の表示を更新、の順です。nullのまま次の操作へ進まないよう、見つからない場合は早めにreturnします。

closest('button[data-action="complete"]')なら、同じ一覧にある「別の操作」のボタンを区別できます。containsは、見つけたボタンがこの一覧の内側にあることを確かめる条件です。さらにこの例は、対象のliが一覧の直下であることも確認しています。入れ子の別一覧まで操作したくないためです。

このコードは、各liに.stateがあるという上のHTMLを前提にしています。別のHTMLへ移すなら、クラス名・親子関係・data-actionを合わせてください。見た目が似ていても、要素の構造が違えば同じ条件で動くとは限りません。

3方式をローカル教材で動かして比べる

イベント委譲の比較教材をダウンロード(ZIP)

ZIPには比較画面、本文の最小例、24ケースの期待値、練習と解答、記録用CSVを入れています。アカウント登録や追加パッケージは不要です。Node.jsが使える環境で、展開したフォルダーをターミナルで開き、次のコマンドを実行してください。

node server.mjs 8775

ブラウザでhttp://127.0.0.1:8775/を開きます。終了はターミナルでCtrl+Cです。同じポートが使われていたら、8776など別の番号で起動し、URLの番号も合わせます。JavaScriptモジュールを使うため、HTMLのダブルクリックではなくローカルHTTPで開いてください。環境の準備はJavaScriptの開発環境と実行方法を参照できます。

毎回リセットして、1つずつ条件を変える

  1. 「比較する方式」で1・2・3のどれかを選ぶ。方式を変えると初期化されます。
  2. 最初のボタンの文字「完了」をクリックし、targetと完了処理の回数を見る。
  3. リセットして「項目を1つ追加」を押し、新しい項目の文字をクリックする。
  4. リセット後、Tabでボタンを選んでEnterを押す。文字クリックとの違いを見る。
  5. 最後に伝播停止をオンにし、親まで届くかを比べる。

以下は2026年10月6日にmacOSのChromeで確認した結果です。各行はリセット後の独立した操作で、伝播停止は最後の行だけオンです。「動く」は完了処理が1回実行されることを表します。

操作 最初に個別登録 親でtargetのみ 親でclosest
最初のボタンをEnter 動く 動く 動く
最初のボタンの文字 動く 動かない 動く
追加したボタンをEnter 動かない 動く 動く
追加したボタンの文字 動かない 動かない 動く
「別の操作」をEnter 対象外 対象外 対象外
行の「項目1」をクリック 対象外 対象外 対象外
一覧外のボタンをEnter 対象外 対象外 対象外
伝播停止+最初のボタンをEnter 動く 動かない 動かない

表が画面に収まらない場合は、横にスクロールできます。

3方式×8操作の24ケースを確認しています。別ブラウザや実機スマートフォンの検証結果ではありません。また、教材はページ内の観察にもリスナーを使っています。表示される回数は完了処理の実行回数であり、リスナー総数や速度の測定値ではありません。完了済みのボタンをもう一度操作しても、処理回数は増えます。

listReceivedがfalseなら親までの伝播、trueなのに処理が0回なら対象判定や登録方法、という順に確認すると、原因を絞れます。actionCurrentTargetがnullなのは、この教材で完了処理が動かなかったという意味です。

練習:追加・子要素・伝播停止を確かめる

練習1:同じボタンでも、押す場所で変わるか

3方式それぞれで、最初のボタンの文字をクリックしてください。次にリセットし、TabとEnterで操作します。targetがどう変わり、どの方式だけ結果が変わるかを記録しましょう。

解答のポイント:targetのみを判定する方式ではSPANを除外します。closestを使う方式ではSPANからBUTTONを探せるため、どちらの操作でも完了処理が動きます。

練習2:追加したボタンを動かす方法を2つ挙げる

「最初のボタンに個別登録」で項目を追加し、反応しないことを確かめてください。イベント委譲以外の直し方も考えます。

解答のポイント:新しいボタンを作るたびに個別登録する方法と、残る親に登録して対象を絞る方法があります。すでにあるボタンまで無条件に繰り返し登録すると、別の関数を重ねて登録して処理が複数回動く原因になるため、登録のタイミングを決めておきます。

練習3:子で伝播を止めるとどうなるか

「親でclosest」を選び、伝播停止をオンにして最初のボタンをEnterで操作します。listReceivedと処理回数を見た後、オフに戻して同じボタンを試してください。

解答のポイント:オンでは子ボタンのstopPropagation()によって親のバブリング段階へ届かず、オフでは届きます。closestの条件を変えても、そもそも親の処理が呼ばれない状態は直りません。

練習4:完了させない操作を確認する

「親でclosest」のまま「別の操作」、行の項目名、一覧外のボタンを操作してください。完了処理が増えない理由を、それぞれ説明してみましょう。

解答のポイント:別の操作はdata-actionが違い、項目名からは該当ボタンが見つからず、一覧外のボタンは一覧を通りません。動く操作に加えて、処理しない操作も確認することで条件の抜けを見つけられます。確認項目の増やし方はアプリのテスト方法とチェックリストでも紹介しています。

イベント委譲でよくある質問

stopPropagationとpreventDefaultは同じですか?

異なります。stopPropagationはイベントがさらに伝わることを止めますが、リンク移動などの既定動作をそれだけで取り消すものではありません。また、同じ要素に登録された別のハンドラーまで止めるものでもありません。そのため教材の個別登録では、子ボタンで伝播を止めても、同じボタンにある完了処理は動きます。MDN:stopPropagation()

すべてのイベントを親に登録できますか?

この記事の方法は、通常のHTML内でバブリングするclickを前提にしています。別のイベントを扱うときは、そのイベントがバブリングするかを先に確認してください。Shadow DOMやiframeをまたぐ処理は、この教材の範囲に含めていません。

documentにまとめればよいですか?

まずは、その操作を受け持つ近い親を選びましょう。今回なら一覧のulです。対象外の画面領域まで広げると、どのクリックを受け取り、どこまで判定するかが読みにくくなります。親が再描画で置き換わらないかも合わせて確認します。

イベント委譲は必ず速くなりますか?

この教材では速度やメモリを測っていません。まずは、同じ処理をどこで登録し、追加時に何をする必要があるかで選んでください。固定された少数のボタンと、動的に増える一覧では、読みやすい構成が変わります。

次に自分のコードでボタンが動かなかったら、登録先→親への到達→target→対象条件の順に見直してみてください。入力内容の正しさを確かめる処理は別の役割なので、続けて学ぶならフォームの入力チェック教材へ進めます。

英語でIT・AIを学べるKredo

英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?

当メディアを運営しているKredoは、英語×ITをオンラインで学ぶ「Kredoオンラインキャンプ」と、フィリピンのセブ島で英語とIT・AIを学ぶ「KredoIT留学」「KredoAI留学」を提供しています。これまでの卒業生は3,000名以上。卒業生の多くが、国内外のIT企業への転職、フリーランスなどへのキャリアチェンジを実現しています。これからの時代に必要な英語×IT・AIのスキルを身につけてグローバルに活躍しませんか?

\ セブ島でIT×英語を学ぶ /IT留学の無料カウンセリングを予約する
\ オンラインでIT✕英語を学ぶ / Kredoオンラインキャンプの詳細をみる >>
  • ツイート
  • シェア
  • はてな
  • ポケット
この記事を書いた人
アバター画像
さおり

小学校教員、特別支援学校教員を経て、退職後半年間フィジー留学。帰国後Kredoオンラインキャンプを3か月受講したのち、未経験でIT企業へ転職。現在はフリーランスでWebディレクターなどをしながら、Webデザインと英語を勉強中。個人でブログ運営。食べることが大好き♪

関連記事

  • フォームの入力条件をノートで整理する学習者の写真イメージ
    プログラミング Web・プログラミング(学習)

    フォームの入力チェックの作り方|HTMLとJavaScriptで空白・文字数を確認

  • fetchのエラーをノートとパソコンで調べる学習者の写真イメージ
    プログラミング Web・プログラミング(学習)

    JavaScriptのfetchエラーの調べ方|404・JSON・通信失敗を切り分ける

  • CSSが効かない原因を調べる学習者と、読み込み・指定・優先順位の見出し
    Web・プログラミング(学習)

    CSSが効かない原因の調べ方|読み込み・セレクタ・優先順位を確認

  • 明るい机でノートとパソコンを見比べながらJSONの読み込みを確認する女性の自然な写真イメージ
    Web・プログラミング(学習)

    JavaScriptのJSON.parseエラーの直し方|構文とデータの形を確認

新規CTA
KREDO JAPAN株式会社

\ SNSで留学の様子を更新中! /

  • Instagram
  • LINE
  • X
  • YouTube
©KREDO JAPAN Inc. 2024 All rights reserved.
Kredoのサービス
セブ島で学びたい方はこちら KredoIT留学
自宅で学びたい方はこちら Kredo Online 英語×アプリ開発コース
運営会社 会社概要 採用情報 お問い合わせ
利用規約 プライバシーポリシー 特定商品取引に基づく表示 資料請求