해당 포스팅은 JavaScript에서 커스텀 이벤트를 생성할 수 있는 방법을 설명합니다.
개요
대부분의 개발자는 JavaScript에서 "click" 또는 "change" 이벤트를 많이 사용할 것이다. 아이디(id)와 패스워드(password)를 서버로 전송하기 위해 로그인 버튼을 클릭해야 하며, 네이버와 다음 또는 구글과 같은 웹 사이트의 검색 창에서 키워드를 변경할 때마다 자동 완성이 표시되어야 하기 때문이다.
하지만 경우에 따라 JavaScript에서 제공하는 기본 이벤트가 개발 요구 사항을 충족하지 않을 수 있다. 이러한 경우 개발자는 커스텀 이벤트를 생성하여 원하는 작업을 수행하도록 할 수 있다.
커스텀 이벤트 생성 방법
JavaScript에서 커스텀 이벤트를 생성하는 두 가지 방법이 존재한다.
- Event() 생성자
- 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?
'JavaScript > DOM' 카테고리의 다른 글
[JS]data 애트리뷰트(Attribute) 사용 방법 (0) | 2022.12.15 |
---|---|
[JS]이벤트 위임(Event Delegation)이란? (0) | 2022.12.11 |
[JS]이벤트 핸들러와 이벤트 리스너 (0) | 2022.12.10 |
[JS]이벤트 흐름(Event Flow) 이해하기 (0) | 2022.12.10 |
[JS]insertAdjacentHTML 메서드로 HTML 요소 추가하기 (0) | 2022.12.10 |
댓글