[JavaScript]_Event Bubbling + Capturing

hanseungjune·2022년 6월 26일
0

JavaScript

목록 보기
78/87

✅ 이벤트 버블링이란?

마치 바다 밑에서 올라오는 방울처럼 자식요소에 대한 이벤트가 발생하면, 해당 부모요소까지 이벤트가 발생되는 것을 말한다. 이벤트 파라미터의 target 프로퍼티를 통해서 가장 최근에 이벤트가 발생한 태그를 보여줄 수 있다.

☑️ 이벤트 버블링 예시

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="style.css">
  <title>JS with Codeit</title>
</head>
<body>
  <div id="content">
    content
    <h1 id="title">오늘 할 일</h1>
    <ol id="list">
      list
      <li class="item">자바스크립트 공부</li>
      <li class="item">유튜브 시청</li>
      <li class="item">저녁 약속</li>
      <li class="item">독서</li>
      <li class="item">일기</li>
    </ol>
  </div>
  <script src="index.js"></script>
</body>
</html>
body * {
  padding: 7px 10px;
  margin: 5px 8px;
  color: #ffffff;
  font-size: 12px;
  background-color: rgba(0, 0, 0, 0.4);
}

h1 {
  font-size: 20px;
  font-weight: 500;
}
// 이벤트 버블링(Event Bubbling)
const content = document.querySelector("#content");
const title = document.querySelector("#title");
const list = document.querySelector("#list");
const items = document.querySelectorAll(".item");

content.addEventListener("click", function(e) {
  console.log('content Event');
  console.log(e.target);
});

title.addEventListener("click", function(e) {
  console.log('title Event');
  console.log(e.target);
});

list.addEventListener("click", function(e) {
  console.log('list Event');
  console.log(e.target);
});

for (let item of items) {
  item.addEventListener('click', function(e) {
    console.log("item Event");
    console.log(e.target);
}

😊 content 범위를 클릭 할 때,

😊 title 범위를 클릭 할 때,

😊 list 범위를 클릭 할 때,

😊 items 범위를 클릭 할 때,

☑️ target 대신 currentTarget 프로퍼티

// 이벤트 버블링(Event Bubbling)
const content = document.querySelector("#content");
const title = document.querySelector("#title");
const list = document.querySelector("#list");
const items = document.querySelectorAll(".item");

content.addEventListener("click", function(e) {
  console.log('content Event');
  console.log(e.currentTarget);
});

title.addEventListener("click", function(e) {
  console.log('title Event');
  console.log(e.currentTarget);
});

list.addEventListener("click", function(e) {
  console.log('list Event');
  console.log(e.currentTarget);
});

for (let item of items) {
  item.addEventListener('click', function(e) {
    console.log("item Event");
    console.log(e.currentTarget);
  });
}

😊 content 범위를 클릭 할 때,

😊 title 범위를 클릭 할 때,

😊 list 범위를 클릭 할 때,

😊 items 범위를 클릭 할 때,

target 과는 다르게 최근 발생 이벤트의 태그보다는 각 이벤트 발생의 태그를 가져옴. 구분하기 쉽게 쓰긴하는데 그렇게 자주 쓰지는 않는다고 함.

☑️ event.stopPropagation();

// 이벤트 버블링(Event Bubbling)
const content = document.querySelector("#content");
const title = document.querySelector("#title");
const list = document.querySelector("#list");
const items = document.querySelectorAll(".item");

content.addEventListener("click", function(e) {
  console.log('content Event');
  console.log(e.currentTarget);
});

title.addEventListener("click", function(e) {
  console.log('title Event');
  console.log(e.currentTarget);
});

list.addEventListener("click", function(e) {
  console.log('list Event');
  console.log(e.currentTarget);
});

for (let item of items) {
  item.addEventListener('click', function(e) {
    console.log("item Event");
    console.log(e.currentTarget);
    e.stopPropagation();
  });
}

부모 요소의 이벤트는 전혀 나오지 않게 해당 태그의 이벤트만 출력되게 함. 다만 이러면 해당 부모 요소가 무엇인지 모르기 때문에 버블링을 제거하기 위해서 해당 태그를 사용하지 않는다고 함.

✅ 캡쳐링

이벤트엔 버블링 이외에도 ‘캡처링(capturing)’ 이라는 흐름이 존재합니다.
실제 코드에서 자주 쓰이진 않지만, 상황에 따라 필요할 수도 있으니 간단하게 살펴봅시다.

먼저, 표준 DOM 이벤트에서 정의한 이벤트 흐름에는 3가지 단계가 있습니다.

  1. 캡처링 단계: 이벤트가 하위 요소로 전파되는 단계
  2. 타깃 단계: 이벤트가 실제 타깃 요소에 전달되는 단계
  3. 버블링 단계: 이벤트가 상위 요소로 전파되는 단계

버블링 단계는 이미 지난 시간에 배웠죠? 타깃 단계는 이벤트 객체의 target 프로퍼티가 되는 요소에 등록되어있던 이벤트 핸들러가 동작하는 단계인데, 쉽게 생각해서 가장 처음 이벤트 핸들러가 동작하게 되는 순간이라고 생각하시면 됩니다.

자, 그럼 이제 캡쳐링에 대해서 좀 더 알아볼까요?

☑️ 이벤트 캡쳐링 예시

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8">
    <title>JS with Codeit</title>
  </head>
  <body>
    <div id="content">
      <h1 id="title">오늘 할 일</h1>
      <ol id="list">
        <li class="item">자바스크립트 공부</li>
        <li class="item">독서</li>
      </ol>
    </div>
    <script src="index.js"></script>
  </body>
</html>

만약 위 코드에서 자바스크립트 공부를 클릭한다면, 버블링은 li태그 부터, ol태그, div태그, body태그, html태그, document, window 객체로 이벤트가 전파가 된다는 거 알고 계시죠?
캡쳐링은 이벤트가 발생하면 가장 먼저, 그리고 버블링의 반대 방향으로 진행되는 이벤트 전파 방식입니다.

아래 이미지를 한번 보세요.

이벤트가 발생하면 가장 먼저 window 객체에서부터 target 까지 이벤트 전파가 일어납니다. (캡쳐링 단계)
그리고 나서 타깃에 도달하면 타깃에 등록된 이벤트 핸들러가 동작하고, (타깃 단계)
이후 다시 window 객체로 이벤트가 전파됩니다. (버블링 단계)

이런 과정을 통해 각 요소에 할당된 이벤트 핸들러가 호출되는데요.

캡쳐링 단계에서 이벤트를 발생시켜야 하는 일은 매우 드문 경우입니다. 보통 타깃 단계에서 target에 등록된 이벤트 핸들러가 있으면 해당 이벤트 핸들러가 먼저 동작한 이 후에 버블링 단계에서 각 부모 요소에 등록된 이벤트 핸들러가 있으면 그 때 해당 이벤트 핸들러가 동작하는 것이 일반적인데요.

하지만 상황에 따라서는 캡쳐링 단계에서 부모 요소의 이벤트 핸들러를 동작시켜야 할 수도 있겠죠? 캡쳐링 단계에서 이벤트 핸들러를 동작시키려면, addEventListener에 세번째 프로퍼티에 true 또는 { capture:true }를 전달하면 됩니다.
아래 코드를 실행해서 각 태그들을 클릭해 보세요.

<body>
  <div>DIV
    <ul>UL
      <li>LI</li>
    </div>
  </form>
  
  <script>
    for (let elem of document.querySelectorAll('*')) {
      elem.addEventListener("click", e => alert(`캡쳐링 단계: ${elem.tagName}`), true);
      elem.addEventListener("click", e => alert(`버블링 단계: ${elem.tagName}`));
    }
  </script>
</body>
</html>

앞서 언급한 것처럼 캡쳐링은 흔하게 접할 만한 상황이 아니기 때문에 일부러 간략하게만 다뤘습니다.

혹시나 캡쳐링과 함께 자바스크립트의 이벤트에 더 궁금한 부분이 있다면 아래 링크를 참고해 주세요! :)

☑️ 이벤트 캡쳐링 예시2

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>오늘 할 일</title>
</head>
<body>
  <div id="main">
    <h2 id="title">오늘 할 일</h2>
    <ul id="to-do-list">
      <li class="item">자바스크립트 공부하기</li>
      <li class="item">고양이 화장실 청소하기</li>
      <li class="item">고양이 장난감 쇼핑하기</li>
    </ul>
  </div>
  <script src="index.js"></script>
</body>
</html>
const main = document.querySelector('#main');
const toDoList = main.lastElementChild;

function printCurrentTarget(event) {
  console.log(event.currentTarget);
}

main.addEventListener('click', printCurrentTarget);

for (let child of toDoList.children) {
  child.addEventListener('click', printCurrentTarget);
}

자바스크립트 공부하기를 클릭했을 때 콘솔에 출력되는 결과는?

<li class="item">자바스크립트 공부하기</li>
<div id="main">...</div>

profile
필요하다면 공부하는 개발자, 한승준

0개의 댓글