JavaScript/DOM

[JS]이벤트 흐름(Event Flow) 이해하기

DevStory 2022. 12. 10.

이벤트 흐름(Event Flow) 이해하기

JavaScript에서 이벤트라는 개념은 간단하면서 복잡합니다. 특정 이벤트(클릭, 값 변경, 마우스 커서 이동 등)가 발생했을 때, 동작하는 이벤트 핸들러 함수를 구현하는 것은 간단하지만 이벤트가 발생하고 처리되는 과정은 생각보다 복잡하기 때문입니다.

 

이번 포스팅은 JavaScript에서 이벤트가 무엇이고 어떻게 동작하는지 설명합니다.


이벤트(Event)

이벤트는 웹 페이지를 사용하는 사용자에 의해 일어나는 사건입니다. 이벤트의 대표적인 예시로 버튼 클릭, 엔터 키 입력, 파일 드래그 앤 드롭이 존재합니다.

 

사용자가 로그인 화면에서 id와 password를 입력 후 엔터키를 입력하거나 로그인 버튼을 눌렀을 때, id와 password를 처리하는 기능은 개발자가 구현하며 이 기능을 이벤트 리스너 혹은 이벤트 핸들러라고 말합니다.


이벤트 흐름(Event Flow)

이벤트 흐름은 이벤트가 발생하고 DOM 트리에서 이벤트가 수신되는 순서를 말합니다.

 

아래와 같이 <div> 태그가 중첩되어 있고 모든 <div> 태그에 클릭 이벤트 리스너가 존재하는 경우 이벤트가 무작위로 실행되면 안 됩니다. JavaScript는 이벤트 실행 순서를 제어하기 위해 이벤트 버블링과 이벤트 캡처라는 두 가지 이벤트 모델을 사용합니다.

<div id="div-1">div-1 클릭
  <div id="div-2">div-2 클릭
    <div id="div-3">div-3 클릭</div>
  </div>
</div>
const div1 = document.getElementById("div-1");
const div2 = document.getElementById("div-2");
const div3 = document.getElementById("div-3");

div1.addEventListener("click", function () {
  console.log("div1");
});

div2.addEventListener("click", function () {
  console.log("div2");
});

div3.addEventListener("click", function () {
  console.log("div3");
});

이벤트 버블링(Event Bubbling)

이벤트 버블링을 쉽게 설명하자면 아래에서 위로 이동하는 것입니다. 아래 예제에서 버튼을 클릭하면 다음 순서대로 이벤트가 실행됩니다.

<div id="content">
  <div id="btn-content">
    <button id="btn">클릭</button>
  </div>
</div>
const contentNode = document.getElementById("content");
const btnContentNode = document.getElementById("btn-content");
const btnNode = document.getElementById("btn");

contentNode.addEventListener("click", function () {
  console.log("id가 `content`인 div 태그의 Click EventListener");
});

btnContentNode.addEventListener("click", function () {
  console.log("id가 `btn-content`인 div 태그의 Click EventListener");
});

btnNode.addEventListener("click", function () {
  console.log("button Click EventListener");
});

[실행 결과]

[이벤트 실행 순서]

1. id가 "btn"인 <button>

2. id가 "btn-content"인 <div>

3. id가 "content"인 <div>

4. <body>

5. <html>

6. Document

 

먼저 이벤트가 발생한 요소에서 click 이벤트가 발생합니다. 그런 다음 Document에 도달할 때까지 click 이벤트가 각 노드에서 실행됩니다.

 

아래 그림은 사용자가 버튼을 클릭할 때 이벤트 버블링 과정입니다.

반응형

이벤트 버블링 중지

이벤트 버블링을 도중에 중지하고 싶을 수 있습니다.

 

예를 들어, id가 "btn"인 버튼을 클릭했을 때, 상위 요소의 클릭 이벤트 리스너가 실행되면 안 됩니다. 이러한 경우 이벤트 객체의 stopPropagation() 메서드를 호출합니다.

<div id="content">
  <div id="btn-content">
    <button id="btn">클릭</button>
  </div>
</div>
const contentNode = document.getElementById("content");
const btnContentNode = document.getElementById("btn-content");
const btnNode = document.getElementById("btn");

contentNode.addEventListener("click", function () {
  console.log("id가 `content`인 div 태그의 Click EventListener");
});

btnContentNode.addEventListener("click", function () {
  console.log("id가 `btn-content`인 div 태그의 Click EventListener");
});

btnNode.addEventListener("click", function (event) {
  console.log("button Click EventListener");
  event.stopPropagation();
});

이벤트 캡처(Event Capturing)

이벤트 캡처는 이벤트 버블링의 반대라고 생각하면 됩니다. 즉, 위에서 아래로 이동하는 것입니다.

 

이벤트 캡처는 거의 사용되지 않으며 최신 브라우저에서는 지원조차 안 하지만 addEventListener() 메서드의 세 번째 매개변수로 true를 전달하면 이벤트 캡처를 활성화시킬 수 있습니다.

<div id="content">
  <div id="btn-content">
    <button id="btn">클릭</button>
  </div>
</div>
const contentNode = document.getElementById("content");
const btnContentNode = document.getElementById("btn-content");
const btnNode = document.getElementById("btn");

contentNode.addEventListener(
  "click",
  function () {
    console.log("id가 `content`인 div 태그의 Click EventListener");
  },
  true
);

btnContentNode.addEventListener(
  "click",
  function () {
    console.log("id가 `btn-content`인 div 태그의 Click EventListener");
  },
  true
);

btnNode.addEventListener("click", function (event) {
  console.log("button Click EventListener");
});

[이벤트 실행 순서]

1. Document

2. <html>

3. <body>

4. id가 "content"인 <div>

5. id가 "btn-content"인 <div>

6. id가 "btn"인 <button>

 

아래 그림은 사용자가 버튼을 클릭할 때 이벤트 캡처 과정입니다.


이벤트 흐름 정리

이벤트 흐름에는 3단계가 존재합니다.

1. 이벤트 캡처(Event Capturing)

2. 이벤트 타겟(event.target)

3. 이벤트 버블링(Event Bubbling)

사용자가 id가 "btn"인 버튼을 클릭하면 해당 버튼이 이벤트 대상으로 설정됩니다.

 

그런 다음 1단계인 이벤트 캡처에 진입하고 addEventListener() 메서드의 세 번째 인수가 true로 설정된 이벤트 핸들러를 호출합니다. 모든 이벤트 핸들러에서 세 번째 인수가 false(기본 값)로 설정된 경우 1단계에서 이벤트가 처리되지 않습니다.

 

2단계인 이벤트 타겟에 도달하면 해당 이벤트 핸들러가 호출됩니다.

 

마지막 3단계로 이벤트 버블링이 발생하면서 addEventListener() 메서드의 세 번째 인수가 false(기본 값)으로 설정된 이벤트 핸들러를 호출합니다.


정리

  • 이벤트는 웹 페이지와 사용자 간에 발생하는 상호작용입니다.
  • 이벤트 버블링은 이벤트가 아래에서 위로 발생하는 개념입니다.
  • 이벤트 캡처는 이벤트가 위에서 아래로 발생하는 개념입니다.
반응형

댓글