[Javascript] Event propagation: useCapture for addEventListener
What gets logged when clicking button?
<div id="outer">
<div id="inner">
<button id="btn">Click me!</button>
</div>
</div>
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
const button = document.getElementById("btn");
outer.addEventListener("click", () => console.log("A"), true);
outer.addEventListener("click", () => console.log("B"));
inner.addEventListener("click", () => console.log("C"), true);
inner.addEventListener("click", (e) => {
console.log("D");
e.stopPropagation();
console.log("E");
});
button.addEventListener("click", () => console.log("F"));
button.addEventListener("click", () => console.log("G"), true);
There are three phrases during event propagation:
- Capturing: Event goes down from top to bottom of the DOM tree, you don't get access to
event.target
- Targeting: When event reach the target element, it is targeting
- Bubbling: Then event goes up through the tree, is bubbling, you get access to
event.target
outer.addEventListener("click", () => console.log("B")); // this event only get trigger in bubbling
outer.addEventListener("click", () => console.log("A"), true); // this evnet fire during capturing
That's why A -> C -> G
will be logged first during capturing phrase.
Then F
is targeting
D -> E
is bubbling, since we call stopPropagation
, `B` won't be logged.
Answer: A -> C -> G -> F -> D -> E
stopPropagation
vs stopImmediatePropagation
outer.addEventListener("click", () => console.log("A"), true);
outer.addEventListener("click", () => console.log("B"));
inner.addEventListener("click", () => console.log("C"), true);
inner.addEventListener("click", (e) => {
console.log("D");
e.stopPropagation();
console.log("E");
});
inner.addEventListener("click", () => console.log("C2")); // <-- new
button.addEventListener("click", () => console.log("F"));
button.addEventListener("click", () => console.log("G"), true);
A -> C -> G -> F -> D -> E -> C2
outer.addEventListener("click", () => console.log("A"), true);
outer.addEventListener("click", () => console.log("B"));
inner.addEventListener("click", () => console.log("C"), true);
inner.addEventListener("click", (e) => {
console.log("D");
e.stopImmediatePropagation();
console.log("E");
});
inner.addEventListener("click", () => console.log("C2")); // <-- new
button.addEventListener("click", () => console.log("F"));
button.addEventListener("click", () => console.log("G"), true);
A -> C -> G -> F -> D -> E
stopImmediatePropagation
will stop the rest listeners event to be triggered, since C2
is registered after, it won't be triggered.