[JavaScript] 이벤트 버블링과 캡처링

김진용·2023년 2월 10일

자바스크립트

목록 보기
3/6

공부하게 된 이유

이번에 프론트엔드 면접 기회를 얻게 되었는데, 기술 질문으로 이벤트 버블링과 캡처링에 대해 물어보았다

처음 들어보는 개념이었기 때문에 이번 기회를 삼아 공부해보려고 한다

시작하기 전에

먼저 예시를 살펴보자

<div onclick="alert('div 태그에 할당한 이벤트 핸들러')">
   <span><code>span</code>태그를 클릭했을 때<code>div</code>태그는?</span>
</div>

이렇게 코드가 구성되어 있다면, 화면에 출력되는 텍스트를 클릭했을 때 alert 창이 뜨는 것을 확인할 수 있다.

프로젝트 했을 때에도 이런 식으로 버튼이나 링크 안에 다른 태그가 있도록 구성한 적이 있었다

분명히 div 태그에 이벤트가 설정되어 있는데 왜 span 태그의 항목을 클릭했을 때에도 이 이벤트가 실행되는 걸까?

이벤트 버블링(bubbling)이란

원리는 아주 간단하다

한 요소에 이벤트가 발생하면, 그 요소에 할당된 이벤트가 실행되고 부모 요소에 할당된 이벤트가 실행된다
이 과정을 최상단의 요소로 올라갈 때까지 반복하는 것이 이벤트 버블링이다

거품이 일어나는 것처럼 보인다는 의미에서 버블링이라는 이름이 붙게 되었다

여기에 event.currentTarget에 대한 설명이 있는데 이 코드를 이용했다

위 링크에서 알 수 있듯이 클릭한 태그와 현재 동작하는 이벤트의 태그가 다르다는 것을 알 수 있다

event.target 을 사용하면 클릭한 태그의 정보를 알 수 있고, event.currentTarget 을 사용하면 현재 동작하는 이벤트의 태그를 알 수 있다

버블링을 멈추는 방법

event.stopPropagation() 을 이용하면 버블링을 막을 수 있다

<div onclick="alert('여기까지는 버블링이 올라오지 않습니다')">
  <div onclick="event.stopPropagation()">
    <div onclick="alert('여기까지는 버블링이 올라옵니다')">
      <button>클릭!</button>
    </div>
  </div>
</div>

이렇게 코드를 작성하고 버튼을 클릭하면 "여기까지는 버블링이 올라옵니다" 만 출력되는 것을 확인할 수 있다

이렇게 event.stopPropagaion() 을 이용하면 버블링에 의해 부모 요소까지 올라가는 것을 막을 수 있게 된다

하지만 일반적으로 버블링 동작을 막을 필요는 없다고 한다. 버블링을 막아야 한다면 커스텀 이벤트를 사용하는게 더 낫다고 한다

설계 단계에서 꼭 막아야 하는 상황이 발생하는 것을 제외하면 막지 않는 것이 좋을 것 같다

이벤트 캡처링(capturing)이란

이벤트 캡처링은 버블링과 반대라고 생각하면 된다

부모 요소의 이벤트를 실행한 뒤 자식 요소의 이벤트를 실행하는 동작이라고 생각하면 된다

그림과 같은 방식으로 아래 요소에 이벤트가 전파되는 것처럼 동작하게 된다

즉, div 태그의 이벤트가 발생한 이후 span 태그의 이벤트가 발생하는 순서로 진행된다는 것이다

addEventListener()capture 옵션을 true 로 설정했을 때 캡처링이 이루어지게 된다

그래서 캡처링 이벤트를 지우기 위해서 removeEventListener() 를 사용하면, 마찬가지로 세 번째 인자로 true 를 넘겨줘야 한다

element.addEventListener('click', () => alert('캡처링'), true);
element.addEventListener('click', () => alert('캡처링'), {capture: true});

위 코드처럼 세 번째 인자로 true 를 넘겨주면 된다

이해를 위해서 박스 형태로 또 만들어 보았다

아래 박스 형태의 실습 코드는 여기에서 코드를 확인할 수 있습니다

  element.addEventListener('click', (event) => alert(`캡처링 : ${element.tagName}`), true);
  element.addEventListener('click', (event) => alert(`버블링 : ${element.tagName}`));

이렇게 구성했을 때 p 영역을 클릭하게 되면 6개의 알림이 뜬다

캡처링 : div > 캡처링 : span > 캡처링 : p > 버블링 : p > 버블링 : span > 버블링 : div 순으로 화면에 출력되는 것을 확인할 수 있다

이벤트 흐름에 의해서 이런 순서로 출력이 진행되는데, 캡처링 단계 > 타깃 단계 > 버블링 단계의 순서로 이루어지기 때문이다

현재 이벤트가 어떤 흐름에서 발생했는지 알 수 있게 해주는 것은 event.eventPhase 라는 프로퍼티를 이용하면 된다고 한다

공부에 참고한 자료

profile
개발자가 되기 위해 꿈틀대고 있습니다.

0개의 댓글