이벤트 위임과 이벤트 전파

섭승이·2024년 12월 22일

자바스크립트

목록 보기
1/4
post-thumbnail

이벤트 위임

이벤트 위임은 비슷한 방식으로 여러 요소를 다뤄야 할때 사용됩니다.
이벤트 캡쳐링과 이벤트 버블링을 이용해 구현할 수 있습니다.

먼저 이벤트 위임을 알기 위해서는 이벤트가 전파되는 과정부터 알아야 합니다.

위의 그림과 같이 웹페이지에서 클릭, 드래그와 같은 이벤트가 발생하게 되면 이벤트는 정확히 그 target에서 시작되지 않고 3번의 단계를 거치게 됩니다.

1. 이벤트 캡쳐링

최상위 조상에서부터 시작해 해당 요소까지 이벤트가 전파되는 과정

즉 이벤트가 발생하면 DOM 트리 최상위 요소인 루트 노드부터 이벤트가 발생합니다. 그리고 이벤트가 하위 요소로 전파되면서 이벤트가 발생한 요소까지 내려오게 됩니다.

2. Target 단계

이벤트가 target에 도달하면 해당 요소에 할당된 이벤트 핸들러가 동작합니다.

3. 이벤트 버블링

이벤트가 발생한 요소부터 최상위 조상까지 이벤트가 전파되는 과정

이벤트 버블링 단계는 이벤트 캡쳐링과는 반대로 이벤트가 상위 요소로 전파되는 과정입니다.

따라서 가장 최상단의 조상 요소를 만날때까지 이벤트가 전파되며 요소 각각의 할당된 핸들러가 동작합니다.


예시

<div class="grandparent">
  Grandparent
  <div class="parent">
    Parent
    <div class="child">Child</div>
  </div>
</div>

<script>
  function logEvent(event) {
    console.log(`이벤트 발생 위치: ${event.currentTarget.className}`);
  }

  // 캡처링 (true)
  document.querySelector('.grandparent').addEventListener('click', logEvent, true);
  document.querySelector('.parent').addEventListener('click', logEvent, true);

  // 버블링 (false)
  document.querySelector('.grandparent').addEventListener('click', logEvent, false);
  document.querySelector('.parent').addEventListener('click', logEvent, false);
  document.querySelector('.child').addEventListener('click', logEvent, false);
</script>

addEventListener() 의 세번째 파라미터를 true 로 설정하면 이벤트 캡처링이 발생하고, false로 설정하면 이벤트 버블링이 발생합니다. (default : false)

해당 코드에서 Child 를 클릭하게 되면 아래와 같은 결과를 얻게 된다.

맨 처음에 최상위 요소인 grandparent 의 클릭이벤트가 동작하고 child 요소까지 해당 이벤트가 전파되면서 각각의 요소에 할당된 클릭 이벤트를 핸들링 하게 됩니다. - 이벤트 캡쳐링

그 다음 child 에 할당된 핸들러가 동작한 뒤 다시 최상위 요소인 grandparent 요소까지 이벤트가 전파되면서 각각의 요소에 할당된 클릭 이벤트를 핸들링 하게 됩니다. - 이벤트 버블링


이벤트 위임 왜 사용하는 것일까?

이벤트 위임을 사용하면 요소마다 핸들러를 할당하지 않고 요소의 공통 조상에 이벤트 핸들러를 단 하나만 할당해도 여러 요소를 한꺼번에 다룰 수 있습니다.

이벤트 위임의 동작 방식은 우선 공통 조상인 Container에 이벤트 핸들러를 추가하고 컨테이너 내의 요소에서 이벤트가 발생하면 해당 이벤트는 이벤트 버블링을 통해 부모요소로 올라오게 됩니다.
만약 container까지 이벤트가 전파되면 event.target을 이용해 이벤트가 발생한 요소가 어디인지 알아내고 원하는 요소에서 이벤트가 발생했다면 이벤트를 핸들링 합니다.

예시

<div id="container">
  <button class="btn">Button 1</button>
  <button class="btn">Button 2</button>
  <button class="btn">Button 3</button>
  <div class="not-btn">버튼아님</div>
</div>

<script>
  document.getElementById('container').addEventListener('click', (event) => {
    if (event.target.className === 'btn') {
      console.log(event.target.textContent + ' 클릭됨');
    }
  });
</script>
  1. Button 1 을 클릭하게 되면 이벤트 버블링을 통해 각각의 버튼의 공통 조상인 container로 이벤트가 전파됩니다.
  2. container에 할당된 이벤트 핸들러가 동작합니다.
  3. event.target을 통해 어느 요소에서 발생한 이벤트인지 확인합니다.
  4. 이벤트를 핸들링합니다.

위의 결과는 Button 1, Button 3, Button 2, 버튼아님 버튼을 각각 눌른 뒤 나온 결과입니다.


이벤트 전파를 막아야 하는 상황과 해결책


이벤트 전파를 막아야 하는 상황

  1. 모달, 팝업 등 UI 요소에서 외부 클릭을 막고 싶을 때
  2. 드래그 앤 드롭에서 기본 동작 방지
  3. 버튼 클릭 시 중복 동작 방지
  4. 배경 클릭으로 이벤트가 잘못 처리되는 경우
  5. 이벤트 중복 실행 방지

이벤트 전파를 막는 방법

  1. event.stopPropagation()

stopPropagation()은 이벤트 전파를 중지하는 방법입니다. 즉 이벤트가 더 이상 상위 요소로 버블링되지 않거나 캡처링되지 않도록 합니다.

  1. event.preventDefault()

preventDefault()는 이벤트의 기본 동작을 막는 방법입니다. 링크를 클릭할 때 페이지가 이동하는 기본 동작을 막거나, 폼 제출을 방지할 수 있습니다.

  1. event.stopImmediatePropagation()

stopImmediatePropagation()stopPropagation()보다 더 강력한 방법으로, 이벤트 전파를 막을 뿐만 아니라 같은 요소에 등록된 다른 이벤트 리스너가 실행되는 것도 방지합니다.


마무리

이벤트 위임은 코드의 중복을 줄여주면서 코드의 가독성을 높여주고 유지보수성을 높여줍니다.

또한 이벤트 리스너의 수를 줄여주면서 메모리 사용을 줄여주는 장점을 가지고 있습니다.

따라서 이벤트 위임을 잘 활용하면서 예상치 못한 버그를 막기 위해 event.stopPropagation()event.preventDefault(), event.stopImmediatePropagation() 를 적절히 사용하는게 좋아 보입니다.


참고 자료 - https://ingg.dev/event-delegation/

profile
소통하며 성장하는 프론트엔드 개발자 이승섭입니다! 👋

0개의 댓글