자바스크립트로 웹 개발을 하다 보면 사용자와의 상호작용이 필수적입니다.
버튼 클릭, 마우스 움직임, 키보드 입력 등 사용자의 모든 행동은 이벤트로 처리됩니다.
이번 포스트에서는 모던 자바스크립트에서 이벤트를 효과적으로 처리하는 방법들을 체계적으로 살펴보겠습니다.
📌 목차
- 이벤트란 무엇인가?
- 이벤트 리스너 등록하기
- 이벤트 객체 활용하기
- 이벤트 버블링와 캡처링
- 이벤트 위임(Event Delegation)
- 다양한 이벤트 타입들
- 실무에서 자주 사용하는 패턴들
📝 이벤트란 무엇인가?
이벤트는 웹 페이지에서 발생하는 사용자의 행동이나 브라우저의 상태 변화를 의미합니다.
클릭, 키 입력, 페이지 로드 등이 모두 이벤트에 해당합니다.
// 가장 기본적인 이벤트 처리
document.getElementById('myButton').onclick = function() {
alert('버튼이 클릭되었습니다!');
};
📝 이벤트 리스너 등록하기
addEventListener 메서드 사용
모던 자바스크립트에서는 addEventListener를 사용하는 것이 권장됩니다.
const button = document.getElementById('myButton');
// 기본 사용법
button.addEventListener('click', function() {
console.log('버튼 클릭됨');
});
// 화살표 함수 사용
button.addEventListener('click', () => {
console.log('화살표 함수로 처리');
});
// 함수를 별도로 정의
function handleClick() {
console.log('별도 함수로 처리');
}
button.addEventListener('click', handleClick);
이벤트 리스너 제거하기
// 이벤트 리스너 제거
button.removeEventListener('click', handleClick);
// 한 번만 실행되는 이벤트
button.addEventListener('click', function() {
console.log('한 번만 실행됩니다');
}, { once: true });
📝이벤트 객체 활용하기
이벤트가 발생할 때마다 이벤트 객체가 생성되어 핸들러 함수에 전달됩니다.
button.addEventListener('click', function(event) {
console.log('이벤트 타입:', event.type);
console.log('클릭된 요소:', event.target);
console.log('현재 요소:', event.currentTarget);
console.log('마우스 X좌표:', event.clientX);
console.log('마우스 Y좌표:', event.clientY);
});
// 키보드 이벤트에서의 활용
document.addEventListener('keydown', function(event) {
console.log('눌린 키:', event.key);
console.log('키 코드:', event.keyCode);
if (event.key === 'Enter') {
console.log('엔터키가 눌렸습니다');
}
});
📝이벤트 버블링과 캡처링
이벤트 버블링
이벤트가 발생한 요소에서 시작해서 부모 요소로 전파되는 현상입니다.
// HTML 구조: <div id="parent"><button id="child">클릭</button></div>
document.getElementById('parent').addEventListener('click', function() {
console.log('부모 div 클릭됨');
});
document.getElementById('child').addEventListener('click', function() {
console.log('자식 button 클릭됨');
});
// button 클릭 시 출력:
// "자식 button 클릭됨"
// "부모 div 클릭됨"
이벤트 전파 제어하기
document.getElementById('child').addEventListener('click', function(event) {
console.log('자식 button 클릭됨');
event.stopPropagation(); // 이벤트 전파 중단
});
// 기본 동작 방지
document.getElementById('myLink').addEventListener('click', function(event) {
event.preventDefault(); // 링크의 기본 동작(페이지 이동) 방지
console.log('링크 클릭됨');
});
이벤트 캡처링
// 캡처링 단계에서 이벤트 처리
document.getElementById('parent').addEventListener('click', function() {
console.log('캡처링 단계에서 처리됨');
}, true); // 세 번째 매개변수를 true로 설정
📝이벤트 위임
부모 요소에서 자식 요소들의 이벤트를 처리하는 패턴입니다. 동적으로 생성되는 요소들에 특히 유용합니다.
// 전통적인 방식 (비효율적)
const buttons = document.querySelectorAll('.item-button');
buttons.forEach(button => {
button.addEventListener('click', handleClick);
});
// 이벤트 위임 방식 (효율적)
document.getElementById('item-list').addEventListener('click', function(event) {
if (event.target.classList.contains('item-button')) {
handleClick(event);
}
});
// 실용적인 예제
document.getElementById('todo-list').addEventListener('click', function(event) {
const target = event.target;
if (target.classList.contains('delete-btn')) {
// 삭제 버튼 클릭 처리
target.closest('.todo-item').remove();
} else if (target.classList.contains('edit-btn')) {
// 편집 버튼 클릭 처리
editTodoItem(target.closest('.todo-item'));
}
});
📝 다양한 이벤트 타입들
마우스 이벤트
const element = document.getElementById('myElement');
element.addEventListener('mouseenter', () => console.log('마우스 진입'));
element.addEventListener('mouseleave', () => console.log('마우스 떠남'));
element.addEventListener('mouseover', () => console.log('마우스 오버'));
element.addEventListener('mouseout', () => console.log('마우스 아웃'));
element.addEventListener('mousedown', () => console.log('마우스 버튼 누름'));
element.addEventListener('mouseup', () => console.log('마우스 버튼 뗌'));
키보드 이벤트
document.addEventListener('keydown', function(event) {
switch(event.key) {
case 'Escape':
closeModal();
break;
case 'Enter':
if (event.ctrlKey) {
submitForm();
}
break;
case 'ArrowUp':
navigateUp();
break;
}
});
폼 이벤트
const form = document.getElementById('myForm');
const input = document.getElementById('myInput');
form.addEventListener('submit', function(event) {
event.preventDefault(); // 폼 제출 방지
const formData = new FormData(form);
console.log('폼 데이터:', Object.fromEntries(formData));
});
input.addEventListener('focus', () => console.log('입력 필드 포커스'));
input.addEventListener('blur', () => console.log('입력 필드 포커스 해제'));
input.addEventListener('input', () => console.log('입력값 변경'));
input.addEventListener('change', () => console.log('입력값 확정'));
윈도우 이벤트
window.addEventListener('load', function() {
console.log('페이지 완전히 로드됨');
});
window.addEventListener('resize', function() {
console.log('윈도우 크기 변경됨');
});
window.addEventListener('scroll', function() {
console.log('스크롤 위치:', window.scrollY);
});
📝 실무에서 자주 사용하는 패턴들
디바운싱(Debouncing)
연속적으로 발생하는 이벤트를 제어하는 기법입니다.
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// 검색 입력 필드에 적용
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(function(event) {
console.log('검색어:', event.target.value);
// 실제 검색 로직 실행
}, 300);
searchInput.addEventListener('input', debouncedSearch);
스로틀링(Throttling)
function throttle(func, delay) {
let lastCall = 0;
return function(...args) {
const now = new Date().getTime();
if (now - lastCall < delay) {
return;
}
lastCall = now;
return func.apply(this, args);
};
}
// 스크롤 이벤트에 적용
const throttledScroll = throttle(function() {
console.log('스크롤 위치:', window.scrollY);
}, 100);
window.addEventListener('scroll', throttledScroll);
커스텀 이벤트
// 커스텀 이벤트 생성
const customEvent = new CustomEvent('myCustomEvent', {
detail: { message: '커스텀 데이터' }
});
// 커스텀 이벤트 리스너 등록
document.addEventListener('myCustomEvent', function(event) {
console.log('커스텀 이벤트 발생:', event.detail.message);
});
// 커스텀 이벤트 발생
document.dispatchEvent(customEvent);
이벤트 체이닝과 프로미스
function waitForClick(element) {
return new Promise(resolve => {
element.addEventListener('click', resolve, { once: true });
});
}
// 사용 예
async function handleUserFlow() {
console.log('버튼 클릭을 기다립니다...');
await waitForClick(document.getElementById('nextButton'));
console.log('다음 단계로 진행합니다!');
}
📚 마무리 정리
이번 포스트에서 배운 이벤트 처리 개념들을 정리하면:
기본 개념: 이벤트는 사용자 상호작용과 브라우저 상태 변화를 처리하는 핵심 메커니즘입니다.
이벤트 리스너: addEventListener를 사용하여 이벤트를 등록하고, 필요시 removeEventListener로 제거할 수 있습니다.
이벤트 객체: 이벤트 발생 시 생성되는 객체로, 이벤트에 대한 상세 정보를 제공합니다.
이벤트 전파: 버블링과 캡처링을 이해하고 stopPropagation()과 preventDefault()로 제어할 수 있습니다.
이벤트 위임: 부모 요소에서 자식 요소들의 이벤트를 처리하여 성능을 최적화할 수 있습니다.
실무 패턴: 디바운싱, 스로틀링, 커스텀 이벤트 등을 활용하여 더 나은 사용자 경험을 제공할 수 있습니다.
💡 오늘 새롭게 알게 된 것
- 디바운싱과 스로틀링의 차이점과 각각의 적절한 사용 상황입니다
- 커스텀 이벤트를 통해 컴포넌트 간 통신을 구현할 수 있다는 점입니다
- once: true 옵션으로 일회성 이벤트 리스너를 간단히 만들 수 있다는 점입니다
🤔 어려웠던 점
- 이벤트 버블링과 캡처링의 정확한 동작 순서를 이해하는게 어려웠습니다
- 언제 이벤트 위임을 사용해야 하고 언제 직접 리스너를 등록해야 하는지 판단하는게 아직 어렵습니다
- 디바운싱과 스로틀링 함수를 직접 구현할 때 클로저 개념을 정확히 적용하는 것이 어렵습니다
🎯 다음 학습 계획
다음 포스팅에서는 HTTP 제어(Ajax)에 대해 알아보겠습니다.
'Development > Javascript' 카테고리의 다른 글
모던 자바스크립트 입문 - Chapter 17: MVC 모델에 기반을 둔 프로그램 설계 💻 (0) | 2025.07.03 |
---|---|
모던 자바스크립트 입문 - Chapter 16: HTTP 제어 (Ajax) 💻 (1) | 2025.07.02 |
모던 자바스크립트 입문 - Chapter 14: 문서제어 💻 (1) | 2025.06.30 |
모던 자바스크립트 입문 - Chapter 13: 웹브라우저의 객체 💻 (4) | 2025.06.28 |
모던 자바스크립트 입문 - Chapter 12: 정규 표현식 💻 (1) | 2025.06.27 |