Notice
Recent Posts
Recent Comments
관리 메뉴

즐겁게, 코드

이벤트의 버블링과 캡처링 이해하기 본문

💬 언어/Javascript

이벤트의 버블링과 캡처링 이해하기

Chamming2 2021. 1. 3. 00:42

이벤트는 화면에 커서를 올리거나 클릭, 키보드를 조작하는 등 사용자가 행하는 모든 동작을 의미한다.

오늘은 버블링과 캡처링으로 대표되는 이벤트의 동작 흐름에 대해 알아보자.

 

[사용할 예제 파일]

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="index.js" defer></script>
    <style>
      body {
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .grandParent {
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: red;
        width: 500px;
        height: 500px;
      }
      .parent {
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: blue;
        width: 300px;
        height: 300px;
      }
      .child {
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: green;
        width: 100px;
        height: 100px;
      }
    </style>
  </head>
  <body>
    <div class="grandParent">
      <div class="parent">
        <div class="child"></div>
      </div>
    </div>
  </body>
</html>

 

 

const parent = document.querySelector(".parent");

parent.addEventListener("click", (e) => {
  parent.style.backgroundColor = "black";
});

위 코드는 parent 클래스명을 가진 요소를 클릭하는 이벤트가 발생할 시 배경을 검정색으로 변경한다.

addEventListener로 이벤트 리스너를 추가하는 것은 대부분 알고 있겠지만 앞으로 소개할 내용들은 꽤나 생소한 개념일 것이다.

 

1. 이벤트의 버블링

const grandParent = document.querySelector(".grandParent");
const parent = document.querySelector(".parent");
const child = document.querySelector(".child");

grandParent.addEventListener("click", (e) => {
  grandParent.style.backgroundColor = "black";
});

parent.addEventListener("click", (e) => {
  parent.style.backgroundColor = "black";
});

child.addEventListener("click", (e) => {
  child.style.backgroundColor = "black";
});

 가장 안쪽의 child부터 바깥쪽의 grandParent까지 클릭 이벤트를 감지하는 리스너를 추가했다.

이제 child 요소를 클릭하면 가장 안쪽의 child만 검정색으로 변할 것이다.

 

... 라고 생각했지만 child 바깥의 모든 요소들의 색도 검게 변한 모습이다.

 

이렇게 된 이유는 이벤트의 버블링(Bubbling) 때문인데, 버블링이란 자식 요소에서 발생한 이벤트에 상위 요소의 리스너까지 반응하는 것을 의미하며, 버블링이 일어나면 해당 요소로부터 거슬러 올라가 최상단 document 객체에 도달할 때까지 사이에 있는 리스너들이 동작하게 된다.

 

따라서 child 요소에서 클릭 이벤트가 발생했으므로 상위 요소인 parentgrandParent 역시 이벤트에 반응해 배경이 검게 변한 것이다.

 

2. 이벤트의 캡처링

이벤트의 버블링이 자식에서 부모로 거슬러 올라가는 흐름이었다면 캡처링(Capturing)은 부모에서 자식으로 전파되는 흐름이다.

기본적으로 이벤트의 전파는 버블링 기반이고 캡처링은 별도의 옵션을 지정해줘야 발동하지만, 캡처링이 활성화되면 버블링보다 먼저 동작한다는 특징이 있다.

 

먼저 캡처링(위에서 아래로)이 진행된 후 버블링(아래에서 위로)이 진행된다.

 

캡처링을 활성화하기 위해서는 addEventListener("이벤트명", "콜백") 의 세 번째 인자로 { capture: true } 옵션을 넣어 주면 되는데, 캡처링이 어떻게 동작하는지 코드로 확인해보자.

const grandParent = document.querySelector(".grandParent");
const parent = document.querySelector(".parent");
const child = document.querySelector(".child");

grandParent.addEventListener(
  "click",
  (e) => {
    console.log("GrandParent Capturing");
  },
  {
    capture: true,
  }
);

grandParent.addEventListener("click", (e) => {
  console.log("GrandParent Bubbling");
});

parent.addEventListener(
  "click",
  (e) => {
    console.log("Parent Capturing");
  },
  {
    capture: true,
  }
);

parent.addEventListener("click", (e) => {
  console.log("Parent Bubbling");
});

child.addEventListener(
  "click",
  (e) => {
    console.log("Child Capturing");
  },
  {
    capture: true,
  }
);

document.addEventListener("click", (e) => {
  console.log("Child Bubbling");
});

document.addEventListener(
  "click",
  (e) => {
    console.log("Document Capturing");
  },
  {
    capture: true,
  }
);

document.addEventListener("click", (e) => {
  console.log("Document Bubbling");
});

 

 

 

위 코드를 실행한 다음 가장 안쪽 child 요소를 클릭한 모습이다.

이를 통해 캡처링이 버블링보다 먼저 수행되었고 캡처링 단계에서는 document에서 child로, 버블링 단계에서는 child에서 document로 서로 반대 방향으로 이벤트의 흐름이 진행된 것을 확인할 수 있다.

 

3. stopPropagation() 함수 사용하기

이렇게 요소를 클릭한다고 해서 해당 요소의 이벤트만 발생하는 것이 아니라는 것을 알았는데, 어떻게 해야 child 요소를 클릭했을 때 child 요소만 검정색으로 바꿀 수 있을까?

 

이럴 때는 e.stopPropagation() 함수를 활용할 수 있다.

e.stopPropagation() 함수는 다음 단계로의 이벤트 전파를 중단시키는데, 배경색을 바꾸는 코드를 이렇게 수정해보자.

const grandParent = document.querySelector(".grandParent");
const parent = document.querySelector(".parent");
const child = document.querySelector(".child");

grandParent.addEventListener("click", (e) => {
  grandParent.style.backgroundColor = "black";
});

parent.addEventListener("click", (e) => {
  parent.style.backgroundColor = "black";
});

child.addEventListener("click", (e) => {
  child.style.backgroundColor = "black";
  e.stopPropagation();
});

 

 

child 요소를 클릭했을 때 상위 요소로 이벤트 전파를 차단함으로써 이제 child 요소만 검게 변한 것을 확인할 수 있다.

그러나 인위적으로 이벤트 전파를 제어하는 것은 꼭 필요한 경우가 아니면 권장되지 않는다.

반응형
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆