버블링&캡처링
버블링Bubbling이란?
특정 요소를 선택했을 때, 그 요소 뿐만이 아니라 상위 요소들의 이벤트 리스너도 작동하는 것을 말한다.
<div>
<p>
<a>이동하기<a/>
<p/>
<div/>
//JS
const divEl = document.querySelector("div")
const pEl = document.querySelector("p")
const aEl = document.querySelector("a")
divEl.addEventListener("click", ()=> console.log("div"))
pEl.addEventListener("click", ()=> console.log("p"))
aEl.addEventListener("click", ()=> console.log("a"))
//클릭 시
//a
//p
//div
한 요소에 이벤트가 발생하면, 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작합니다. 가장 최상단의 조상 요소를 만날 때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작합니다.
위의 예시에서의 이벤트 발생 순서:
1. a요소의 이벤트 발생
2. p요소의 이벤트 발생
3. div요소의 이벤트 발생
event.target
부모 요소의 핸들러는 이벤트가 정확히 어디서 발생했는지 등에 대한 자세한 정보를 얻을 수 있다.
이벤트가 발생한 가장 안쪽의 요소는 타깃(target) 요소라고 불리고, event.target을 사용해 접근할 수 있다.
event.target과 this(=event.currentTarget)는 다음과 같은 차이점이 있습니다.
- event.target은 실제 이벤트가 시작된 ‘타깃’ 요소입니다. 버블링이 진행되어도 변하지 않습니다.
- this는 ‘현재’ 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조합니다.
만약 위 예시에서 divEl의 핸들러에서 event.target을 참조하면 실제 이벤트가 발생한 a가 참조된다는걸 알 수 있다.
그러나 event.currentTarget 혹은 this를 사용하면 자신의 이벤트를 참조한다. (this = event.currentTarget)
this(event.currentTarget) – <div> 요소에 있는 핸들러가 동작했기 때문에 <div> 요소를 가리킵니다.
event.target – 폼 안쪽에 실제 클릭한 요소를 가리킵니다.
메서드를 사용한 이벤트 전파 방지
이벤트 버블링은 타깃 이벤트에서 시작해서 <html> 요소를 거쳐 document 객체를 만날 때까지 각 노드에서 모두 발생합니다. 몇몇 이벤트는 window 객체까지 거슬러 올라가기도 합니다. 이 때도 모든 핸들러가 호출됩니다.
그런데 핸들러에게 이벤트를 완전히 처리하고 난 후 버블링을 중단하도록 명령할 수도 있습니다.
이벤트 객체의 메서드인 event.stopPropagation()를 사용하면 됩니다.
<body onclick="alert(`버블링은 여기까지 도달하지 못합니다.`)">
<button onclick="event.stopPropagation()">클릭해 주세요.</button>
</body>
on이벤트 속성들은 모두 html attribute였구나...
캡처링
이벤트 캡쳐는 이벤트 버블링과 반대 방향으로 진행되는 이벤트 전파 방식입니다.
앞서 살펴봤던 예제를 div → p → a 순으로 console.log를 발생시키려면 어떻게 구현해야 할까? (상위 -> 하위)
답은 캡처링을 사용하면 된다. 많이 사용하진 않는다고 한다.
el.addEventListener(..., {capture: true})
// 아니면, 아래 같이 {capture: true} 대신, true를 써줘도 됩니다.
el.addEventListener(..., true)
이벤트 전파 흐름
표준 DOM 이벤트에서 정의한 이벤트 흐름엔 다음 3가지 단계가 있다.
- 캡처링 단계 : 이벤트가 하위 요소로 전파되는 단계
- 타깃 단계 : 이벤트가 실제 타깃 요소에 전달되는 단계
- 버블링 단계 : 이벤트가 상위 요소로 전파되는 단계