🫧
JavaScriptのCapturing&Bubblingについて
これは何
JavaScriptのイベントに関連したコンセプト、Capturing・Bubblingについてざっくりまとめてみました。
(個人開発している最中にtarget
とcurrentTarget
の違いがあやふやになり調べ物してたのですが、ついでなので関連していそうなCapturingとBubblingというコンセプトについてもまとめてみました、というものです)
References
以下調べるにあたって参考にした動画を記載しておきます。
(👇の動画がかなり網羅的で良いのでまた記憶が怪しくなってきた時の参考に)
Web Dev Simplified
Capturing & Bubbling
-
ユーザーがDOMのどこかをクリックしたり、マウスをホバーさせたりするようなinteractionは総称して
event
と呼ばれている- こうした
event
に応じて何かアクションを起こしたい場合、event handlerと呼ばれるような関数を作成しそれをaddEventListner
とかで発火するように実装したりする
- こうした
-
で、どの
event
も発生すると以下2つのフェーズを経て上記addEventListener
で登録した処理を実行していく
- Capturing:DOMの外側からイベントが起こった対象のelementに向かって処理を実行していくフェーズ
- Bubbling:- イベントが起こった対象のelementからDOMの外側に向かって処理を実行していくフェーズ
- デフォルトだと
addEventListener
は、2番目の引数として渡された関数をBubblingフェーズで発火させる設定になっている
sample.addEventListener("click", () => {
console.log("clicked!");
});
// 3番目の引数が省略されているだけで実際はcaptureの設定がオフ = Bubblingで発火させる設定になっている
// sample.addEventListener("click", () => {
// console.log("clicked!");
// }, { capture: false });
以下わかりやすいようにデモを作ってみました。
このデモだと真ん中のson
にあたるdivをクリックするとson
にaddEveneListenerで登録した処理に続いてdad
, granpa
の処理も走ります。
これはこの時以下のような順序で処理が走っているのが理由。
- クリックをされた対象のelement
son
に向かってDOMの外側からCapturingのフェーズが発生 -
granpa
,dad
にもaddEventListenerで処理が登録されているけど、いずれもデフォルトではcapure: false
のためCapturingフェーズでは素通り - イベントの対象である
son
に到達し、今度はson
から外側にむけて処理が走っていくBubblingフェーズに - ここで初めて
son
に登録された処理がはしる - そして最初は素通りした
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でもちゃんと処理を走らせることがわかるデモを以下に作成。
こちらのデモではgranpa
、dad
、 son
それぞれに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