JavaScript/DOM

[JS]커스텀 이벤트 생성하기(CustomEvent 및 dispatchEvent)

DevStory 2022. 12. 11.
해당 포스팅은 JavaScript에서 커스텀 이벤트를 생성할 수 있는 방법을 설명합니다.

개요

대부분의 개발자는 JavaScript에서 "click" 또는 "change" 이벤트를 많이 사용할 것이다. 아이디(id)와 패스워드(password)를 서버로 전송하기 위해 로그인 버튼을 클릭해야 하며, 네이버와 다음 또는 구글과 같은 웹 사이트의 검색 창에서 키워드를 변경할 때마다 자동 완성이 표시되어야 하기 때문이다.

 

하지만 경우에 따라 JavaScript에서 제공하는 기본 이벤트가 개발 요구 사항을 충족하지 않을 수 있다. 이러한 경우 개발자는 커스텀 이벤트를 생성하여 원하는 작업을 수행하도록 할 수 있다.

 

커스텀 이벤트 생성 방법

JavaScript에서 커스텀 이벤트를 생성하는 두 가지 방법이 존재한다.

  1. Event() 생성자
  2. CustomEvent() 생성자

 

이벤트 생성자

새로운 이벤트를 생성하려면 아래와 같이 Event() 생성자를 사용하여 새로운 Event 객체를 생성한다.

const event = new Event(type, options);

매개변수

type

 - 이벤트의 이름을 나타내는 문자열이다.

 

options

- 아래 프로퍼티를 포함하는 객체이며 options 객체 및 options 객체의 프로퍼티는 생략할 수 있다.

  • bubbles
    - 이벤트가 상위 요소로 전파되어야 하는지 여부를 설정한다.
    - 불리언 값을 설정할 수 있으며, 기본 값은 false로 설정된다.
  • cancelable
    - 이벤트를 취소할 수 있는지 여부를 설정한다.
    - 불리언 값을 설정할 수 있으며, 기본 값은 false로 설정된다.
  • composed
    - Shadow DOM에서 실제 DOM으로 전파되어야 하는지 여부를 설정한다.
    - 불리언 값을 설정할 수 있으며, 기본 값은 false로 설정된다.

반환 결과

새로운 Event 객체를 반환한다.

 

아래는 이름이 "myEvent"인 Event 객체를 생성하는 간단한 예제다.

const myEvent = new Event('myEvent');

 

커스텀 이벤트 생성자

또 다른 방법으로 CustomEvent() 생성자를 사용하여 새로운 이벤트를 생성할 수 있다.

const customEvent = new CustomEvent(type, options);

매개변수

type

 - 이벤트의 이름을 나타내는 문자열이다.

 

options

- 아래 프로퍼티를 포함하는 객체이며 options 객체 및 options 객체의 프로퍼티는 생략할 수 있다.

  • detail
    - 이벤트 객체에 포함할 세부 정보를 나타내는 값을 설정한다.
    - 기본 값은 null로 설정된다.
  • bubbles
    - 이벤트가 상위 요소로 전파되어야 하는지 여부를 설정한다.
    - 불리언 값을 설정할 수 있으며, 기본 값은 false로 설정된다.
  • cancelable
    - 이벤트를 취소할 수 있는지 여부를 설정한다.
    - 불리언 값을 설정할 수 있으며, 기본 값은 false로 설정된다.
  • composed
    - Shadow DOM에서 실제 DOM으로 전파되어야 하는지 여부를 설정한다.
    - 불리언 값을 설정할 수 있으며, 기본 값은 false로 설정된다.

반환 결과

새로운 CustomEvent 객체를 반환한다.

 

아래는 이름이 "myCustomEvent"이며, 세부 정보가 존재하는 CustomEvent 객체를 생성하는 간단한 예제다.

const myCustomEvent = new CustomEvent('myCustomEvent', {
  detail: {
    name: 'Hong Gil Dong',
    country: 'korea'
  }
});

 

커스텀 이벤트 전달

Event() 또는 CustomEvent() 생성자로 커스텀 이벤트 객체를 생성한 다음 커스텀 이벤트를 사용하려면 이벤트 객체를 전달하는 과정이 필요하다. 이 과정이 필요한 이유는 커스텀 이벤트 객체를 생성했다고 해당 이벤트를 바로 사용할 수 없기 때문이다.

 

HTML 요소에서 커스텀 이벤트를 사용하려면 dispatchEvent() 메서드를 사용한다.

domElement.dispatchEvent(event);

매개변수

event

 - Event 객체 또는 CustomEvent 객체를 설정한다.

 

반환 결과

매개변수인 event가 취소 가능(cancelable 프로퍼티의 값이 true)하며, 이벤트 처리기에서 Event.preventDefault() 메서드를 호출한 경우 false이며 그 외에는 true를 반환한다.

 

전역 객체인 window에 커스텀 이벤트를 전달하려면 window 객체에서 dispatchEvent() 메서드를 호출한다.

const myCustomEvent = new CustomEvent('myCustomEvent', {
  detail: {
    name: 'Hong Gil Dong',
    country: 'korea'
  }
});

window.dispatchEvent(myCustomEvent);

 

전역 객체가 아닌 특정 HTML 요소에서만 커스텀 이벤트를 사용하려면 특정 HTML 요소를 접근한 다음 dispatchEvent() 메서드를 호출한다.

 

아래 예제는 id가 "content"인 HTML 요소를 접근한 다음 dispatchEvent() 메서드를 호출한다.

const divContent = document.getElementById('content');

const myCustomEvent = new CustomEvent('myCustomEvent', {
  detail: {
    name: 'Hong Gil Dong',
    country: 'korea'
  }
});

divContent.dispatchEvent(myCustomEvent);

 

커스텀 이벤트 예시

아래는 id가 "btn"인 버튼을 클릭했을 때, 커스텀 이벤트가 동작하는 간단한 예제다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JavaScript Custom Event</title>
  </head>
  <body>
    <button id="btn">JS Custom Event</div>
    <script>
      // id가 "btn"인 HTML 요소 접근
      const btnElement = document.getElementById('btn');

      // 커스텀 이벤트 생성
      const newCustomEvent = new CustomEvent("newCustomEvent", {
        detail: {
          title: "error",
          content: "커스텀 이벤트 동작"
        }
      });
      
      // 클릭 이벤트가 발생하면 커스텀 이벤트 전달
      btnElement.addEventListener("click", function(e) {
        btnElement.dispatchEvent(newCustomEvent);
      });

      // 커스텀 이벤트 추가
      btnElement.addEventListener("newCustomEvent", function(e) {
        alert(`${e.detail.title}: ${e.detail.content}`);
      });
    </script>
  </body>
</html>

 

커스텀 이벤트를 사용하는 이유

지금까지 커스텀 이벤트를 생성, 전달, 적용 방법을 알아보았는데, "굳이 커스텀 이벤트를 사용해야 하나?"라는 의문을 가질 수 있다.

 

아래 예제처럼 커스텀 이벤트를 사용하지 않고 title과 content라는 두 개의 파라미터를 가진 함수를 호출해도 상관없기 때문이다.

const btnElement = document.getElementById('btn');

function showAlert(title, content) {
  alert(`${title}: ${content}`);
}

btnElement.addEventListener("click", function(e) {
  showAlert('error', '커스텀 이벤트 동작');
});

그리고 개요에서 "JavaScript에서 제공하는 기본 이벤트가 개발 요구 사항을 충족하지 않을 경우 커스텀 이벤트를 사용할 수 있다"라고 언급했지만 이벤트 리스너에서 JavaScript에서 제공하는 "click" 이벤트를 등록했다.

 

그럼에도 불구하고 커스텀 이벤트를 사용해야 하는 이유가 무엇일까?

 

첫 번째 이유는 커스텀 이벤트를 호출하여 원하는 정보를 detail 프로퍼티로만 전달할 수 있으므로 데이터가 꼬일 일이 없다는 것이다. 즉, 기본 이벤트를 호출했는지 커스텀 이벤트를 호출했는지 detail 프로퍼티로 구분할 수 있다.

 

두 번째 이유는 커스텀 이벤트는 트리거 된다는 것이다. 기본 이벤트인 마우스 클릭 이벤트는 클릭이 발생하면 mousedown → mouseup click 순서로 이벤트가 처리되기 때문에 mousedown 이벤트 핸들러가 끝나기 전에는 click 이벤트 핸들러를 호출할 수 없다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JavaScript Custom Event</title>
  </head>
  <body>
    <button id="btn">click 순서</div>
    <script>
      // id가 "btn"인 HTML 요소 접근
      const btnElement = document.getElementById('btn');
      
      btnElement.addEventListener("mousedown", function(e) {
        console.log('mousedown');
      });

      btnElement.addEventListener("mouseup", function(e) {
        console.log('mouseup');
      });

      btnElement.addEventListener("click", function(e) {
        console.log('click');
      });
    </script>
  </body>
</html>

버튼을 클릭하면 콘솔에 "mousedown", "mouseup", "click"가 순서대로 출력되는 것을 확인할 수 있다.

 

하지만, 커스텀 이벤트는 도중에 트리거 되므로 기본 이벤트가 종료되기 전에 커스텀 이벤트를 호출할 수 있다. 아래 예제는 "click" 이벤트에서 커스텀 이벤트를 발생시킨다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JavaScript Custom Event</title>
  </head>
  <body>
    <button id="btn">click 순서</div>
    <script>
      // id가 "btn"인 HTML 요소 접근
      const btnElement = document.getElementById('btn');

      btnElement.addEventListener("click", function(e) {
        // 커스텀 이벤트 전달
        window.dispatchEvent(new CustomEvent('alertEvent', {
          detail: 'Alert Event First Call'
          }));
        
        console.log('Click Event Call');

        // 커스텀 이벤트 전달
        window.dispatchEvent(new CustomEvent('alertEvent', {
          detail: 'Alert Event Second Call'
          }));
      });

      window.addEventListener("alertEvent", function(e) {
        alert(e.detail);
      });
    </script>
  </body>
</html>

위 예제를 통해 우리가 알 수 있는 내용은 두 가지다. 첫 번째는 기본 이벤트 안에서 커스텀 이벤트를 발생시킬 수 있다는 것이며, 두 번째는 커스텀 이벤트 끝난 후 코드가 실행된다는 것이다.

 

커스텀 이벤트를 사용하는 몇 가지 사례가 존재한다. 특정 버튼을 클릭하면 서버에 데이터 전달 후 응답을 받을 때까지 다른 작업을 수행할 수 없다고 가정하자. 이러한 경우 일반적으로 로딩바를 표시하여 사용자에게 다른 작업을 수행할 수 없도록 할 수 있다.

 

아래는 도서  「자바스크립트 완벽 가이드」에서 예시로 설명하는 코드를 일부 발췌하였다.

// 로딩바 활성화
window.dispatchEvent(new CustomEvent("loading", { detail: true }));

fetch(url)
  .then(handleNetworkResponse)
  .catch(handleNetworkError)
  .finally(() => {
    // 로딩바 비활성화
    document.dispatchEvent(new CustomEvent("loading", { detail: false }));
  });

window.addEventListener("loading", (e) => {
  if (e.detail) {
    showLoading();
  } else {
    hideLoading();
  }
});

 

참고 자료

[1] medium - JavaScript: Understanding CustomEvent and dispatchEvent

[2] javascripttutorial - JavaScript Custom Events

[3] javascripttutorial - JavaScript dispatchEvent

[4] stackoverflow - Why use custom events instead of direct method calling?

[5] joyfuljoeunlee - Custom Event

[6] kirupa - Custom Events in JavaScript

반응형

댓글