🫧

JavaScriptのCapturing&Bubblingについて

2023/06/25に公開

これは何?

JavaScriptのイベントに関連したコンセプト、Capturing・Bubblingについてざっくりまとめてみました。

(個人開発している最中にtargetcurrentTargetの違いがあやふやになり調べ物してたのですが、ついでなので関連していそうなCapturingとBubblingというコンセプトについてもまとめてみました、というものです)

References

以下調べるにあたって参考にした動画を記載しておきます。
(👇の動画がかなり網羅的で良いのでまた記憶が怪しくなってきた時の参考に)

Web Dev Simplified

https://www.youtube.com/watch?v=XF1_MlZ5l6M&t=703s

Capturing & Bubbling

  • ユーザーがDOMのどこかをクリックしたり、マウスをホバーさせたりするようなinteractionは総称してeventと呼ばれている

    • こうしたeventに応じて何かアクションを起こしたい場合、event handlerと呼ばれるような関数を作成しそれをaddEventListnerとかで発火するように実装したりする
  • で、どのeventも発生すると以下2つのフェーズを経て上記addEventListenerで登録した処理を実行していく

Capturing & Bubbling diagram

  1. Capturing:DOMの外側からイベントが起こった対象のelementに向かって処理を実行していくフェーズ
  2. Bubbling:- イベントが起こった対象のelementからDOMの外側に向かって処理を実行していくフェーズ
  • デフォルトだとaddEventListenerは、2番目の引数として渡された関数をBubblingフェーズで発火させる設定になっている

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

sample.addEventListener("click", () => {
	console.log("clicked!");
});

// 3番目の引数が省略されているだけで実際はcaptureの設定がオフ = Bubblingで発火させる設定になっている
// sample.addEventListener("click", () => {
//	 console.log("clicked!");
// }, { capture: false });

以下わかりやすいようにデモを作ってみました。
このデモだと真ん中のson にあたるdivをクリックするとson にaddEveneListenerで登録した処理に続いてdad, granpa の処理も走ります。

これはこの時以下のような順序で処理が走っているのが理由。

  1. クリックをされた対象のelement son に向かってDOMの外側からCapturingのフェーズが発生
  2. granpa, dad にもaddEventListenerで処理が登録されているけど、いずれもデフォルトではcapure: falseのためCapturingフェーズでは素通り
  3. イベントの対象であるson に到達し、今度はsonから外側にむけて処理が走っていくBubblingフェーズに
  4. ここで初めてson に登録された処理がはしる
  5. そして最初は素通りしたdad, granpaの処理もこの外側に向かってBubble upしていく過程で実行されていく

中身のコードはこちら


const granpa = document.getElementById("granpa") as HTMLElement;
const dad = document.getElementById("dad") as HTMLElement;
const son = document.getElementById("son") as HTMLElement;

granpa.addEventListener("click", () => {
  console.log("Granpa!");
});

dad.addEventListener("click", () => {
  console.log("Dad!");
});

son.addEventListener("click", () => {
  console.log("Son!");
});

次にCapturingでもちゃんと処理を走らせることがわかるデモを以下に作成。
こちらのデモではgranpadadsonそれぞれにCapturingのフェーズでも発火する処理をaddEventListenerでくっつけてあるため、sonをクリックすると以下のような順番で処理が走ります。

Granpa  capture! 
Dad capture! 
Son capture! 
Son bubble! 
Dad bubble! 
Granpa bubble! 
granpa.addEventListener(
  "click",
  () => {
    console.log("Granpa  capture!");
  },
  { capture: true }
);

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

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

granpa.addEventListener("click", () => {
  console.log("Granpa bubble!");
});

dad.addEventListener("click", () => {
  console.log("Dad bubble!");
});

son.addEventListener("click", () => {
  console.log("Son bubble!");
});

以上かなりざっくりとですがCapturingとBubblingについてのメモでした!

Discussion