본문 바로가기

언어(JS,TS)/그룹스터디

그룹스터디 [DOM: 이벤트 버블링이란?]

반응형

이벤트 버블링(Event Bubbling)

이벤트 버블링이란 한 요소에 이벤트가 발생하면 이 요소에 할당된 핸들러가 동작하고, 이어서 부모 요소의 핸들러가 동작하고 최상단의 부모 요소를 만날 때까지 반복되면서 핸들러가 동작하는 현상을 말한다.

버블링 예제 코드

<style>
  body * {
    margin: 10px;
    border: 1px solid red;
  }
</style>

<body>
  <div class="DIV1">
    DIV1
    <div class="DIV2">
      DIV2
      <div class="DIV3">DIV3</div>
    </div>
  </div>
</body>
// 태그div를 전부 찾아서 배열 형태로 만듬
const divs = document.querySelectorAll("div");

// 현재 타겟의 클래스 이름을 콘솔에 출력
const clickEvent = (e) => {
  console.log(e.currentTarget.className);
};

// 찾은 요소들 각각에 이벤트 넣기
divs.forEach((div) => {
  div.addEventListener("click", clickEvent);
});

div를 클릭하면 해당하는 클래스의 이름이 콘솔로 출력되는 코드이다. 자바스크립트는 기본적으로 버블링이 발생하기 때문에 

<div class="DIV3">DIV3</div>를 클릭한다면 콘솔에는 DIV3, DIV2, DIV1

<div class="DIV2">DIV2</div>를 클릭하면  DIV2, DIV1

<div class="DIV1">DIV1</div>는 DIV1

이 출력 됨

<div class="DIV3">DIV3</div> 를 클릭하면 할당되어 있는 이벤트가 발생하고 다음에는 바깥의 div 태그에 할당된 이벤트가 발생하고 document 객체를 만날 때까지 이벤트가 전파된다.

 

그래서 만약에 모든요소에 이벤트를 넣으면 document객체까지 출력 되는 모습을 볼 수 있다.

// 모든요소 전부 찾아서 배열 형태로 만듬
const all = document.querySelectorAll("*");

// 현재 타겟을 콘솔에 출력
const clickEvent = (e) => {
  console.log(e.currentTarget);
};

// 찾은 요소들 각각에 이벤트 넣기
all.forEach((el) => {
  el.addEventListener("click", clickEvent);
});

몇몇 이벤트는 window 객체까지 거슬러 올라가기도 합니다. 이 때도 모든 핸들러가 호출됩니다.

 

 

그런데 핸들러에게 이벤트를 완전히 처리하고 난 후 버블링을 중단하도록 명령할 수도 있습니다.

이벤트 객체의 메서드인 event.stopPropagation()를 사용하면 됩니다.

 

event.stopPropagation() 사용방법

 

<body onclick="alert(`버블링은 여기까지 도달하지 못합니다.`)">
  <button onclick="event.stopPropagation()">클릭해 주세요.</button>
</body>

모든 요소에 클릭 요소 넣음

버튼을 클릭 했을 경우

다른요소를 클릭 했을 경우

주의

하지만 버블링은 유용합니다. 버블링을 꼭 멈춰야 하는 명백한 상황이 아니라면 버블링을 막지않는 것이 좋다고 합니다.

아키텍처를 잘 고려해 진짜 막아야 하는 상황에서만 버블링을 막아야 합니다.

 

event.stopPropagation()은 추후에 문제가 될 수 있는 상황을 만들어낼 수 있습니다.

문제가 발생할만한 시나리오를 살펴봅시다.

1. 중첩 메뉴를 만들었다 가정합시다. 각 서브메뉴(submenu)에 해당하는 요소에서 클릭 이벤트를 처리하도록 하고, 상위 메뉴의 클릭 이벤트 핸들러는 동작하지 않도록 stopPropagation을 적용합니다.

2. 사람들이 페이지에서 어디를 클릭했는지 등의 행동 패턴을 분석하기 위해, window내에서 발생하는 클릭 이벤트 전부를 감지하기로 결정합니다. 분석 시스템을 도입하기로 합니다. 그런데 이런 분석 시스템의 코드는 클릭 이벤트를 감지하기 위해 document.addEventListener('click'…)을 사용합니다.

3. stopPropagation로 버블링을 막아놓은 영역에선 분석 시스템의 코드가 동작하지 않기 때문에, 분석이 제대로 되지 않습니다. 안타깝게도 stopPropagation을 사용한 영역은 '죽은 영역(dead zone)'이 되어버립니다.

 

이벤트 버블링을 막아야 하는 경우는 거의 없습니다.

버블링을 막아야 해결되는 문제라면 커스텀 이벤트 등을 사용해 문제를 해결할 수 있습니다.

핸들러의 event 객체에 데이터를 저장해 다른 핸들러에서 읽을 수 있게 하면,

아래쪽에서 무슨 일이 일어나는지를 부모 요소의 핸들러에게 전달할 수 있으므로,

이 방법으로도 이벤트 버블링을 통제할 수 있습니다.

 

 

 

 

++

https://ko.javascript.info/bubbling-and-capturing

 

버블링과 캡처링

 

ko.javascript.info