addEventListener
target.addEventListener(type, listener[, useCapture]);
addEventListener의 구문이다.
type
: 이벤트의 유형
listener
: 이벤트가 발생했을 때 실행하는 콜백함수
useCapture
: boolean
값을 받는다. 말 그대로 capturing단계의 이벤트를 캐치 하느냐 마느냐이다. default 값은 false로 bubbling 단계의 이벤트를 캐치한다.
그러면 capturing과 bubbling은 무엇일까?
W3C UIEvents specification에서 이벤트 흐름에 대해 설명해준 그림이다. 이 그림만 기억하면 버블링,캡쳐링에 대해 이해하기 어렵지 않다.
HTML에서 이벤트가 발생하면 1. 캡쳐링 단계 -> 이벤트 타켓 단계 -> 버블링 단계의 순서대로 이벤트가 전파된다.
이때useCapture
에 따라 어느 단계에 이벤트를 적용시킬지 결정해준다.
무조건 이벤트가 발생하면 window부터 시작해 target지점 까지 capturing phase를 거치고 target phase를 거친뒤 다시 bubbling phase가 window까지 발생한다.
아래 예를 보고 이해해보자.
각각의 상자를 누르면 console에 first,second,third가 출력된다.
<!DOCTYPE html>
<html lang="en" class="html">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body class="body">
<div class="first">
first
<div class="second">
second
<div class="third">third</div>
</div>
</div>
<script src="./test.js"></script>
</body>
</html>
HTML에서 이벤트가 발생되면 window부터 target까지 이벤트 캡쳐링 phase가 먼저 진행된다.
addEventListener
의 useCapture의 속성이 true로 설정된 이벤트들은 이 단계에서 콜백함수를 실행시킨다.
first.addEventListener('click', () => {
console.log('first');
});
second.addEventListener(
'click',
() => {
console.log('second');
},
true
);
third.addEventListener('click', () => {
console.log('third');
});
위의 코드를 먼저 예상해보자
결과
third를 클릭했는데 second가 먼저 출력된 것을 확인할 수 있다.
useCapture의 default값은 false로 버블링 단계에서 이벤트를 실행하게 돼 있지만, second의 useCapture를 true로 설정해준 결과이다.
캡쳐링을 보았으니 아래의 코드도 예상해보자
first.addEventListener('click', () => {
console.log('first');
});
second.addEventListener('click', () => {
console.log('second');
});
third.addEventListener('click', () => {
console.log('third');
});
결과
useCapture속성이 true
로 설정된 이벤트가 없기 때문에 아무일도 없다.이벤트를 지우는 테스트 해봤다.
const first = document.querySelector(".first");
first.removeEventListener("click", handleClick);
평소대로 위에 removeEventListener
를 이용해 event를 삭제했는데, bubbling으로 설정했을 때는 event가 삭제됐지만 캡쳐링일 때는 삭제가 안되는 것이다.
그러다 발견한 사실이 addEventListener
에서 설정한 useCapture
과 같이 아래의 예제처럼 실행해 주어야 했다.
first.removeEventListener("click", handleClick, true);
캡처링과 버블링을 통해서 이벤트 위임(Event Delegation) 을 구현 할 수 있다. 이벤트 위임은 많은 리스트가 있거나 테이블에 td가 많을 경우 유용하게 사용될 수 있다.
또한 이벤트 전파를 멈추는 방법도 알아두어야 한다.
처음에 이벤트 캡쳐링과 버블링을 잘못 이해하고 블로그 포스팅도 잘못했었다.
결국 이벤트 캡쳐링과 버블링은 HTML의 이벤트 전파 단계 캡쳐링->target->버블링 단계중 어느단계에서 이벤트를 실행시켜주는것인지 결정하는 것이었다.
잘못 이해한 상태로 김버그님의 유튜브 버블링 캡쳐링을 보는데 버블링과 캡쳐링을 제대로 이해할 수 있었다.