이벤트 캡쳐링과 이벤트 버블링을 활용하면 강력한 이벤트 핸들링 패턴인 이벤트 위임(Event delegation)을 구현 할 수 있다.
이벤트 위임은 비슷한 방식으로 여러 요소를다뤄야 할 때 사용된다. 이벤트 위임을 사용하면 요소마다 핸들러를 할당하지 않고, 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다룰 수 있게된다.
공통 조상에 할당한 핸들러에서 event.target
을 이용하면 실제 어디서 이벤트가 발생했는지 알 수 있다.
이벤트 버블링과 이벤트 캡쳐링의 예제를 보면서 차이에 대해 알아보자.
특정 엘리먼트에 이벤트가 발생하면 해당 이벤트가 엘리먼트의 조상들에게 까지 전달되는 현상이다.
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
const divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
위 그림에 이해를 돕기 위한 예시 코드이다.
세 개의 <div>
태그에 모두 클릭 이벤트를 등록하고 클릭 했을 경우 콘솔에 <div>
의 class
명을 표시해주는 코드이다. 클릭했을때 콘솔에 찍힌 순서로 이벤트가 실행되는 순서를 파악 할 수 있다. 결과는
three
two
one
순서이다.
브라우저는 특정 화면 요소에 이벤트가 발생 했을 때 그 이벤트를 최상위에 있는 화면 요소까지 전파시킨다. 따라서 three
=> two
=> one
순서로 <div>
태그에 등록된 이벤트들이 실행되는 것을 확인 할 수 있다.
마찬가지로 two
클래스를 가지고 있는 두번째 태그를 클릭했다면 two
=> one
순으로 상위 태그만 표시되는 것을 확인 할 수 있을 것이다.
이와 같이 하위에서 상위 요소로 이벤트를 전파하는 방식을 이벤트 버블링이라고 한다.
이벤트 캡쳐링은 특정 엘리먼트에 이벤트가 발생 했을 경우, 이벤트가 최상단의 부모 엘리먼트로부터 전달되어져 내려오는 현상이다.
따라서 전달되는 이벤트는 부모 엘리먼트의 이벤트 핸들러를 작동시킨다.
캡쳐링을 수행하기 위해서는 이벤트 핸들러에 {capture : true}
혹은 ture
로 캡쳐링 옵션을 true
로 해주어야 한다.
디폴트는 false
이므로 별다른 옵션을 설정하지 않는다면 캡쳐링은 일어나지 않는다.
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false입니다.
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
위 그림에 이해를 돕기 위한 예시 코드이다.
addEventListener()
API에서 옵션 객체에 capture : true
를 설정해주면 된다.
그러면 해당 이벤트를 감지하기 위해 이벤트 버블링과 반대 방향으로 탐색한다.
따라서, 이 전과 동일하게 <div class = "three"></div>
를 클릭해도, 아래와 같은 결과가 나오게 된다.
one
two
three
function logEvent(event) {
event.stopPropagation();
}
위와 같은 방식으로 이벤트가 전파되는 것을 임의로 막을 수 있다.
이벤트 버블링의 경우에는 클릭한 요소의 이벤트만 발생시키고 상위 요소로 이벤트를 전달하는 것을 방해한다.
이벤트 캡쳐링의 경우 클릭한 요소의 최상위 요소의 이벤트만 동작시키고 하위 요소들로의 이벤트 전달을 방해한다.
위와 같이 stopPropagation()
API를 활용한다면 앞의 이벤트 버블링과 캡쳐링의 예제에서 사용한 코드 기준으로 three
와 one
이 찍힐 것이다.
// 이벤트 버블링 예제
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
event.stopPropagation();
console.log(event.currentTarget.className); // three
}
// 이벤트 캡쳐 예제
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
capture: true // default 값은 false입니다.
});
});
function logEvent(event) {
event.stopPropagation();
console.log(event.currentTarget.className); // one
}