이벤트 버블링, 캡처링 - 2

버블링 이벤트 실무 예제와 이벤트 위임에 대해서 알아봅니다.


들어가며

지난 이벤트 버블링, 캡처링 1편에 이어서 이번 2편에서는 실무 예제와 이벤트 위임에 대해서 설명합니다.

실무에서 흔히 만날수 있는 이벤트 버블링

jsfiddle에 예제가 하나 있습니다.

이 예제의 올바른 동작은

  1. Display video 버튼을 클릭하면 viewBox가 나타납니다.
  2. 동영상을 클릭하면 동영상이 재생 됩니다.
  3. 빨간색 영역을 클릭하면 viewBox가 닫힙니다.

올바르게 동작하나요?

동영상을 재생하기 위해 동영상을 클릭하면 재생은 되지만 화면이 사라집니다.

무엇이 문제일까요?

위 예제에서 이벤트가 어떻게 작동하는지 그림을 한번 그려보겠습니다.

img1
  1. Display video 버튼을 클릭하면 viewBox가 나타납니다.
  2. 동영상을 재생시키기 위해 video를 클릭합니다.
  3. window에서부터 시작한 이벤트가 video까지 전파됩니다.(캡쳐링)
  4. video에 할당된 video.play() 코드를 실행합니다.
  5. 버블링으로 window까지 이벤트가 전파됩니다.
  6. 전파되는 도중에 viewBox에 할당된 이벤트를 만나서 이 이벤트를 처리합니다.(viewBox를 숨김)
  7. window에서 이벤트 흐름이 종료됩니다.

올바르게 작동하지 않는 이유는 순서 6번 때문입니다. 순서 4번에서 시작된 이벤트가 버블링으로 인해 window로 전파 되면서 순서 6번이 실행되기 때문입니다.

이벤트가 버블링 되지 않도록 하려면 어떻게 해야 할까요?

Event.stopPropagation()

Event객체에 있는 stopPropagation 메서드를 사용하면 됩니다.

The stopPropagation() method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases

stopPropagation 메서드를 이용하여 버블링 단계에서의 추가 전파를 막으면 됩니다.

video.addEventListener('click', (event) => {
  event.stopPropagation();
  video.play();
});

최종 jsfiddle은 여기에서 확인해주세요.

이벤트 위임(delegation)

버블링을 이용해서 이벤트 위임 패턴을 사용 할 수 있습니다.

이벤트 위임이란 DOM내에서 관심의 대상이 되는 엘리먼트보다 상위에 위치한 엘리먼트에 이벤트 핸들러를 지정하는 행위입니다.

먼저 여기 간단한 예제가 있습니다.

jsfiddle

특별한 동작은 없고 각 li 엘레먼트를 클릭하면 그 안에 있는 textContent를 alert으로 보여주는 코드입니다.

코드를 살펴 보면 li 엘레먼트들을 forEach로 순회하면서 각 li에 click 이벤트 리스너를 할당 합니다.

const lists = document.querySelectorAll('li');

lists.forEach((list) => {
  list.addEventListener('click', () => {
    if (event.target.nodeName === 'LI') {
      alert(event.target.textContent);
    }
    return;
  });
});

이 코드를 이벤트 위임을 이용한 방식으로 구현할 수 있습니다.

const root = document.querySelector('.root');

root.addEventListener('click', () => {
  if (event.target.nodeName === 'LI') {
    alert(event.target.textContent);
  }
  return;
});

이벤트 처리를 li의 부모인 ul에게 위임하는 것입니다.

li를 순회하면서 똑같은 일을 하는 이벤트 리스너를 하나하나 할당하지 않아도 되기 때문에 훨씬 효율적입니다.

이렇게 부모인 ul에게 이벤트 위임이 가능한것은 버블링과 event.target을 통해서 실제로 어디에서 이벤트가 발생했는지 알 수 있기 때문입니다.

event.target

이벤트 위임 예제를 그림으로 표현하면 아래와 같습니다.

img2

부모에게 이벤트 핸들러를 할당하면 Event 객체의 target 프로퍼티를 이용하여

이벤트를 전달한 객체에 대한 참조를 얻을 수 있습니다.

Event.target

event.currentTarget

Event.currentTarget

event.target과 다른점은 currentTarget을 이용해서 이벤트 리스너가 있는 대상을 참조 할 수 있습니다.

이 예제에서는 ul 부모 자신입니다.

최종 jsfiddle은 여기에서 확인해주세요.

마치며

2편에서는 실무에서 한번쯤은 겪여봤을 버블링 예제와 버블링을 이용한 이벤트 위임 패턴에 대해서 알아 보았습니다.

흔하게 공식처럼 stop.proPagation()을 사용하곤 했었는데 이번 기회를 통해

왜 이러한 문제가 발생하는지, DOM에서의 이벤트가 어떻게 동작하는지 이해 할 수 있게 되었습니다.

다음달 주제는 무엇을 해야하나 고민하며 이만 마치겠습니다…

읽어주셔서 감사합니다.

참고문서


추천 글