아이템 이벤트 핸들러를 등록하는 부분을 코멘트 처리해두고 저장하고 실행해보면 리스트가 아니라 아이템 영역을 클릭했는데도 리스트와 콘텐트 이벤트 핸들러가 동작.
어떤 하나의 요소에 이벤트가 발생하게 되면 이 요소에 할당된 이벤트 핸들러가 동작하고 거기서 끝이 아니라 이어서 같은 타입의 이벤트에 한해서 부모 요소의 핸들러도 동작하게 되는 것. 그렇게 가장 최상단의 윈도우 객체를 만날 때까지 이 과정이 반복되면서 요소 각각의 할당된 모든 이벤트 핸들러가 동작하는 원리.
const content = document.querySelector('#content'); const title = document.querySelector('#title'); const list = document.querySelector('#list'); const items = document.querySelectorAll('.item'); content.addEventListener('click', function(e) { console.log('content Event'); console.log(e.currentTarget); }); title.addEventListener('click', function(e) { console.log('title Event'); console.log(e.currentTarget); }); list.addEventListener('click', function(e) { console.log('list Event'); console.log(e.currentTarget); }); for (let item of items) { item.addEventListener('click', function(e) { console.log('item Event'); console.log(e.currentTarget); e.stopPropagation();//버블링 멈추게 함-->아이템에서는 버블링이 안일어남. }); }
위 예시처럼 아이템 부분에서 이벤트 버블링을 막아 버리게 되면 바로 위에 있는 리스트 뿐만 아니라 모든 부모 요소의 입장에서 아이템 영역만큼의 이벤트를 발생시킬 범위가 사라져버리게 되는 것. 예를 들어 페이지 전체에 걸쳐서 어떤 이벤트를 만들고 싶은 경우에는 결국 document나 body같은 구간이 존재하게 되면 당연히 클릭했을 때 버블링이 막혀 버리기 때문에 그 부분만 우리가 원하는 이벤트 결과를 얻지 못한다.
- 캡처링 단계: 이벤트가 하위 요소로 전파되는 단계
- 타깃 단계: 이벤트가 실제 타깃 요소에 전달되는 단계
- 버블링 단계: 이벤트가 상위 요소로 전파되는 단계
버블링 단계는 이미 지난 시간에 배웠죠? 타깃 단계는 이벤트 객체의 target 프로퍼티가 되는 요소에 등록되어있던 이벤트 핸들러가 동작하는 단계인데, 쉽게 생각해서 가장 처음 이벤트 핸들러가 동작하게 되는 순간이라고 생각하시면 됩니다.
자, 그럼 이제 캡쳐링에 대해서 좀 더 알아볼까요?
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <title>JS with Codeit</title> </head> <body> <div id="content"> <h1 id="title">오늘 할 일</h1> <ol id="list"> <li class="item">자바스크립트 공부</li> <li class="item">독서</li> </ol> </div> <script src="index.js"></script> </body> </html>
이벤트가 발생하면
가장 먼저 window 객체에서부터 target 까지 이벤트 전파가 일어납니다. (캡쳐링 단계)
그리고 나서 타깃에 도달하면 타깃에 등록된 이벤트 핸들러가 동작하고, (타깃 단계)
이후 다시 window 객체로 이벤트가 전파됩니다. (버블링 단계)
이런 과정을 통해 각 요소에 할당된 이벤트 핸들러가 호출되는데요.
캡쳐링 단계에서 이벤트를 발생시켜야 하는 일은 매우 드문 경우입니다. 보통 타깃 단계에서 target에 등록된 이벤트 핸들러가 있으면 해당 이벤트 핸들러가 먼저 동작한 이 후에 버블링 단계에서 각 부모 요소에 등록된 이벤트 핸들러가 있으면 그 때 해당 이벤트 핸들러가 동작하는 것이 일반적인데요.
하지만 상황에 따라서는 캡쳐링 단계에서 부모 요소의 이벤트 핸들러를 동작시켜야 할 수도 있겠죠? 캡쳐링 단계에서 이벤트 핸들러를 동작시키려면, addEventListener에 세번째 프로퍼티에 true 또는 { capture:true }를 전달하면 됩니다.