이벤트 버블링과 캡처링에 대해 알아보기 전에 이벤트 등록에 대해 알아보자.
이벤트 등록이란 웹 애플리케이션에서 사용자의 입력을 받기 위해 필요한 기능이다.
<button>add one item</button>
var button = document.querySelector('button');
button.addEventListener('click', addItem);
function addItem(event) {
console.log(event);
}
add one item이라는 간단한 버튼을 만들어 클릭했을 때 addItem이라는 함수를 실행시키는 코드다.
addEventListener() 웹 API는 웹 개발자들이 화면에 동적인 기능을 추가하기 위해 자연스럽게 접하게 되는 기본적인 기능이다. 그런데 브라우저는 어떻게 이벤트의 발생을 감지했을까?
이벤트 버블링은 특정 화면 요소에서 이벤트가 발생했을 때 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성을 의미한다.
즉, 이벤트 버블링이란 한 요소에 이벤트가 발생하면 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작하고 최상단의 부모 요소를 만날 때까지 반복되면서 핸들러가 동작하는 현상이다.
<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);
});
div를 클릭하면 해당하는 클래스의 이름이 콘솔로 출력되는 코드이다. 자바스크립트는 기본적으로 버블링이 발생하기 때문에 <div class="div3">div3</div>
를 클릭한다면 콘솔에는 div3, div2, div1이 순서대로 출력이 될 것이다.
캡처링은 버블링과는 반대로 최상위 태그에서 해당 태그를 찾아 내려간다. 위 그림처럼 특정 이벤트가 발생했을 때 최상위 요소인 body 태그에서 해당 태그를 찾아 내려간다.
addEventListener
의 옵션 객체에 { capture: true }
또는 true 를 설정해주면 캡처링을 구현할 수 있다.
const divs = document.querySelectorAll("div");
const clickEvent = (e) => {
console.log(e.currentTarget.className);
};
divs.forEach((div) => {
div.addEventListener("click", clickEvent, { capture: true });
});
<div class="DIV3">DIV3</div>
를 클릭한다면 위에서부터 찾아 내려오기 때문에 콘솔에는 div1, div2, div3이 순서대로 찍힐 것이다.
버블링은 해당 타깃에서 document 객체를 만날 때까지 핸들러가 모두 호출되는데 코드를 작성하다보면 원하는 타깃에서만 이벤트를 발생하게 하고 싶을때가 있다.
그럴 때에는 event.stopPropagation() 을 사용하면 되는데 버블링의 경우에는 클릭한 타깃의 이벤트만 발생하고 상위 요소로 이벤트가 전파되는 것을 막을 수 있다.
const clickEvent = (e) => {
e.stopPropagation();
console.log(e.currentTarget.className);
};