이벤트 캡쳐링(Capturing)과 버블링(Bubbling)의 이해

자바스크립트는 이벤트가 발생하면 이벤트가 발생한 노드(Event Target)를 찾기 위해 DOM 트리를 탐색을 합니다.

탐색 과정은 도큐먼트 루트, 또는 가장 바깥쪽 노드에서부터 이벤트가 트리거 된 타겟 노드까지 내려가는 탐색 방식과, 반대 방향으로 다시 올라오는 탐색 방식으로 구분합니다.

타겟 노드까지 내려가는 탐색 방식을 이벤트 캡쳐링(Event Capturing), 반대 방향으로 올라오는 탐색 방식을 이벤트 버블링(Event Bubbling) 이라고 합니다.

이렇게 이벤트가 이벤트 타겟 까지 도달하기 위해 퍼져나가는 것을 이벤트 전파(Event Propagation) 라고 합니다.

자바스크립트의 이벤트 리스너 등록 및 처리는 기본적으로 버블링 과정을 통해 이벤트가 전파됩니다.

캡쳐링 과정으로 이벤트를 전파하고 싶은 경우 이벤트 리스너 등록시 capture 옵션을 true로 켜주면 됩니다.

target.addEventListener('이벤트', 콜백함수, {capture: true});

target.addEventListener('이벤트', 콜백함수, true);

와 같이 옵션을 지정하면 이벤트 캡쳐링 방식으로 이벤트를 전파합니다.

이벤트 전파를 원하지 않을 경우

event.stopPropagation();

메서드를 타겟 엘리먼트의 이벤트 리스너 콜백 함수에서 호출하면 됩니다.

버블링으로 상위 요소로 이벤트를 전파하는 방식으로 구현할 때 상위 요소에 같은 이벤트를 처리하는 이벤트 리스너가 등록되어 있는 경우, 원하는 이벤트 처리와는 관련이 없는 콜백 함수가 실행될 수 있습니다.

이런 경우 stopPropagation() 으로 이벤트 전파를 막아 상위 요소의 이벤트 콜백이 실행되는 것을 막아줄 수 있습니다.

이벤트 캡쳐링 버블링 비교

아래와 같은 HTML 페이지에서 "아이템*" 목록 아이템을 클릭했을 때 이벤트가 어떻게 전파되는지 확인할 수 있습니다.

<body>  <div>    <ul>      <li><span>아이템1</span></li>      <li><span>아이템2</span></li>      <li><span>아이템3</span></li>    </ul>  </div></body>

캡쳐링과 버블링은 다음과 같은 방향으로 전파됩니다.

function eventPropagation(useCapture) {    document.querySelector('body').addEventListener('click', function() {console.log("body");}, useCapture);    document.querySelector('div').addEventListener('click', function() {console.log("div");}, useCapture);    document.querySelector('ul').addEventListener('click', function() {console.log("ul");}, useCapture);    document.querySelector('li').addEventListener('click', function() {console.log("li");}, useCapture);    document.querySelectorAll('span').forEach(        function(item){item.addEventListener('click', function(e) {console.log("target");}, useCapture);}    );}eventPropagation(true);//eventPropagation(false);

"eventPropagation(true);" 를 호출하면 이벤트 캡쳐링이 되면서 최상위 도큐먼트 루트에서 하위 요소로 이벤트가 전파되고, "eventPropagation(false);" 를 호출하면 맨밑 타겟 <span> 태그에서 위로 이벤트가 버블링 됩니다.

이벤트 캡쳐링과 버블링을 이해하면 이벤트 처리를 위한 이벤트 리스너 등록 작업을 단순화 할 수 있습니다.

여러개의 연달아 이어진 요소에 같은 이벤트 리스너를 적용해야 할 경우, 버블링된 상위 요소에 하나의 이벤트 리스너만 적용해 반복되는 이벤트 처리를 단순화할 수 있습니다.