기술 면접을 대비해 개념을 🍰 한입 크기로 잘라 정리합니다.
깃허브가 궁금하다면 놀러오세요!
👉 깃허브 보러가기 (Since 2023.05.10 ~ )
표준 DOM 이벤트에서 정의한 이벤트 흐름의 3단계는 다음과 같습니다.
따라서 <td>
를 클릭하면
이벤트 버블링
은 한 요소에 이벤트가 발생해 요소에 할당된 핸들러가 동작하면 → 이어 부모 요소의 핸들러가 동작하고 → 가장 최상단에 위치한 부모요소를 만날때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작하는 것을 의미합니다.
이벤트가 제일 깊은 곳에 있는 요소부터 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품, 즉 버블과 닮아 이벤트 버블링이라고 부릅니다.
FORM > DIV > P
형태로 중첩된 구조가 있고, 각 요소에 핸들러가 할당되어 있다.<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
가장 안쪽의 <p>
요소를 클릭하면,
<p>
에 할당된 onclick 핸들러가 동작하고<div>
에 할당된 onclick 핸들러가 동작합니다.<form>
에 할당된 onclick 핸들러가 동작합니다.document
객체를 만날 때까지, 각 요소에 할당된 onclick 핸들러가 동작합니다.💡
document
객체란?
- DOM 트리 최상단 객체를 말합니다.
💡 모든 이벤트는 버블링 될까 ?
focus
이벤트와 같이 몇몇 이벤트를 제외한 대부분의 이벤트는 버블링된다.
원하는 요소에서만 이벤트를 발생하게 하고 싶다면, event.stopPropagation()
를 통해 버블링을 중단할 수 있습니다. 이를 사용하면 클릭한 타깃의 이벤만 발생하고 상위 요소로 이벤트가 전파되는 것을 막아줍니다.
<form onclick="alert('버블링은 여기까지 도달하지 못합니다")">FORM
<div onclick="event.stopPropagation()">클릭해주세요.</div>
</form>
💡 한 요소의 이벤트 핸들러가 두개라면?
한 요소의 특정 이벤트를 처리하는 핸들러가 여러개라면,event.stopPropagation()
를 통해 하나의 핸들러의 버블링을 멈추더라도 나머지 핸들러는 여전히 동작합니다.즉,
event.stopPropagation()
는 상위로 일어나는 버블링은 막아주지만, 같은 요소에 할당된 다른 핸들러들이 동작하는 건 막지 못합니다.따라서 상위로 일어나는 버블링을 중단하고, 같은 요소에 할당된 다른 핸들러의 동작도 막으려면
event.stopImmediatePropagation()
를 사용하면 된다. 이 메서드를 사용하면 해당 요소에 할당된 이벤트를 처리하는 모든 핸들러의 동작이 중단된다.
❓ 이벤트 버블링 중단, 올바른가?
A. 버블링은 매우 유용하므로, 버블링을 꼭 멈춰야 하는 상황이 아니라면 버블링을 막지 않는 것이 좋다.
event.stopPropagation()
을 사용한 영역은 ‘죽은 영역(Dead Zone)’이 되어버리기 때문입니다.- 불가피하게 버블링을 막아야한다면, 해당 메서드 대신 커스텀 이벤드 등을 사용해 이벤트 버블링을 통제하는 것이 권장됩니다.
이벤트가 발생한 가장 안쪽 요소는 타깃(target)요소 라고 불리고, event.target
을 사용해 접근할 수 있다.
event.target
: 실제 이벤트가 시작된 ‘타깃’요소를 말하며, 버블링이 진행되어도 타깃 요소는 변하지 않습니다.this(=event.currentTarget)
: ‘현재’ 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조합니다.위 구조에서 <p>
요소의 onClick 이벤트 핸들러를 동작시킨다면,
event.target
: 실제 클릭한 요소인 <p>
요소this(=event.currentTarget)
: <form>
요소에 있는 핸들러가 동작했기 때문에 <form>
요소를 가리킨다.캡처링은 버블링과 반대로 최상위 태그에서 해당 태그를 찾아 내려가는 현상을 말합니다
addEventListener
의 옵션 객체에 { capture: true }
또는 true
를 설정해 캡쳐링 구현할 수 있습니다.<div class="DIV3">DIV3</div>
를 클릭하면 최상위 부모요소부터 탐색해 내려오기 때문에 콘솔에 DIV1 → DIV2 → DIV3이 순서대로 찍히게 됩니다.
<body>
<div class="DIV1">
DIV1
<div class="DIV2">
DIV2
<div class="DIV3">DIV3</div>
</div>
</div>
</body>
const divs = document.querySelectorAll("div");
const clickEvent = (e) => {
console.log(e.currentTarget.className);
};
divs.forEach((div) => {
div.addEventListener("click", clickEvent, { capture: true });
});
이벤트 버블링
은 한 요소에 이벤트가 발생해 요소에 할당된 핸들러가 동작하면 → 이어 부모 요소의 핸들러가 동작하고, → 가장 최상단에 위치한 부모요소를 만날때까지 이 과정이 반복되면서 요소 각각에 할당된 핸들러가 동작하는 것을 의미합니다.
이벤트가 제일 깊은 곳에 있는 요소부터 시작해 부모 요소를 거슬러 올라가며 발생하는 모양이 마치 물속 거품, 즉 버블과 닮아 이벤트 버블링이라고 부릅니다.
📎 참고문서