1. 캡처링과 버블링
[실험하면서 보게 될 현상]

이벤트의 흐름을 간략하게 표시해주셨다.
일단 그런가보다 하고 넘어가자.
1-1. 캡처링
[ 실험할 html 코드 ]
<html>
<head>
<style>
html {
border: 5px solid red;
padding: 30px;
}
body {
border: 5px solid green;
padding: 30px;
}
fieldset {
border: 5px solid blue;
padding: 30px;
}
input {
border: 5px solid black;
padding: 30px;
}
</style>
</head>
<body>
<fieldset>
<legend>event propagation</legend>
<input type="button" id="target" value="target" />
</fieldset>
<script>
function handler(event) {
var phases = ["capturing", "target", "bubbling"];
console.log(
event.target.nodeName,
this.nodeName,
phases[event.eventPhase - 1]
);
}
document
.getElementById("target")
.addEventListener("click", handler, true);
document
.querySelector("fieldset")
.addEventListener("click", handler, true);
document
.querySelector("body")
.addEventListener("click", handler, true);
document
.querySelector("html")
.addEventListener("click", handler, true);
</script>
</body>
</html>

⚪ 제일 안쪽 input 태그를 하나 눌렀을 뿐인데 그 input태그를 감싸고 있는 태그들의 이벤트 리스너들까지 전부 나오는 모습을 볼 수 있다. 이 때 순서를 잘 보자. 바깥쪽에서 안쪽으로, 즉, 부모로부터 자식방향으로 호출되는 방식을 ✔캡쳐링이라고 부른다.
INPUT HTML capturing
INPUT BODY capturing
INPUT FIELDSET capturing
INPUT INPUT target
1-2. 버블링
⚪ 반대로 각 요소의 ✔ addEventListener 의 인자를 false로 바꾼다면 어떻게 되는지 보자.
// document
// .getElementById("target")
// .addEventListener("click", handler, true);
// document
// .querySelector("fieldset")
// .addEventListener("click", handler, true);
// document
// .querySelector("body")
// .addEventListener("click", handler, true);
// document
// .querySelector("html")
// .addEventListener("click", handler, true);
document
.getElementById("target")
.addEventListener("click", handler, false);
document
.querySelector("fieldset")
.addEventListener("click", handler, false);
document
.querySelector("body")
.addEventListener("click", handler, false);
document
.querySelector("html")
.addEventListener("click", handler, false);

거꾸로 안쪽부터 바깥쪽으로 콘솔을 찍는 모습을 볼 수 있다.
🎈 addEventListener 의 세 번째 요소의 역할을 정확히 알게 되었다.
.addEventListener("click", handler, false);
세 번째 인자로 불린 형태의 값을 받는 addEventListener. 정확하게 말하자면 Use Capturing Option 이다.
✔ 세 번째 인자로 true를 주게 되면 캡처링이 발생한다. 제일 안쪽 요소를 클릭해도 그 안쪽 요소를 감싸고 있는 상위 태그가 이벤트 리스너가 있다면 그 상위 태그의 이벤트 리스너부터 실행한다는 뜻이다. 만약에 설치한 이벤트 핸들러가 캡쳐링 방식으로 작동하기를 원한다면 true 값을 세 번째 인자로 넣어주면 된다. 반대로 버블링 방식으로 동작하기를 원한다면 false를 세 번째 인자로 주면 된다. 기본값은 false 이기 때문에 인자를 주지 않는 경우에도 버블링 방식으로 작동한다.
즉, 인자가 없다면 알아서 안쪽부터 바깥쪽방향으로 이벤트 핸들러가 작동한다.
💥 주의 사항
버블링은 모든 브라우저가 지원해서 맘놓고 써도 되지만, 캡처링은 과거의 브라우저에서는 지원하지 않는 경우가 많이 있음. 웬만하면 캡처링을 쓰지 않는 것이 좋다.
+ 위에서 설명 못한 밑의 코드 두 줄에 대해서 설명
var phases = ["capturing", "target", "bubbling"];
phases[event.eventPhase - 1]
캡쳐링 와중에 호출된 것이 있다면 eventPhase는 1이라는 값을 갖게 됨.
그리고 만약에 버블링 와중에 호출된 것이라면 3이라는 값을 갖게 됨.
또한 가장 하위 자식 요소에 설치되어 있는 이벤트 핸들러라고 한다면 eventPhase 값은 1을 갖게 됨.
1-3. 이벤트 전파 중간에 막기
🎈 이벤트 전파 중간에 막기: event.stopPropagation()
영어로 propagation은 '전파' 라는 뜻이다.
마지막으로 이벤트 전파를 막는 방법을 보도록 하자.
<script>
function handler(event) {
var phases = ["capturing", "target", "bubbling"];
console.log(
event.target.nodeName,
this.nodeName,
phases[event.eventPhase - 1]
);
}
function stopHandler(event) {
var phases = ["capturing", "target", "bubbling"];
console.log(
event.target.nodeName,
this.nodeName,
phases[event.eventPhase - 1]
);
event.stopPropagation();
}
document
.getElementById("target")
.addEventListener("click", handler, false);
document
.querySelector("fieldset")
.addEventListener("click", handler, false);
document
.querySelector("body")
.addEventListener("click", stopHandler, false);
document
.querySelector("html")
.addEventListener("click", handler, false);
</script>
실행결과

INPUT INPUT target
INPUT FIELDSET bubbling
INPUT BODY bubbling
이벤트 전파 방식은 버블링 방식을 사용하였고 중간에 event.stopPropagation() 을 호출함으로써 이벤트 전파를 막아 html은 찍히지 않은 모습을 볼 수 있다!!