본문 바로가기
  • 코딩, 허쌤이 떠먹여 줄게
FrontEnd/Javascript

12장. 이벤트 (Event)

by 허쌤 2026. 1. 11.

12장. 이벤트 (Event)

이벤트란?

이벤트(Event)는 사용자의 행동(클릭, 키 입력, 마우스 이동 등)이나 브라우저의 동작(페이지 로드, 리사이즈 등)을 의미합니다. JavaScript를 통해 이러한 이벤트에 반응하여 동적인 웹 페이지를 만들 수 있습니다.


1. 이벤트 리스너 추가

addEventListener() (권장)

가장 권장되는 방법입니다.

<button id="btn">클릭</button>
const btn = document.getElementById('btn');

btn.addEventListener('click', function() {
    alert('버튼이 클릭되었습니다!');
});

인라인 이벤트 (권장하지 않음)

HTML에 직접 이벤트를 작성하는 방법입니다.

<button onclick="alert('클릭됨')">클릭</button>

단점: HTML과 JavaScript가 섞여서 유지보수가 어려움


2. 주요 이벤트 타입

마우스 이벤트

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

// click: 클릭
btn.addEventListener('click', function() {
    console.log('클릭됨');
});

// dblclick: 더블 클릭
btn.addEventListener('dblclick', function() {
    console.log('더블 클릭됨');
});

// mousedown: 마우스 버튼 누름
btn.addEventListener('mousedown', function() {
    console.log('마우스 버튼 누름');
});

// mouseup: 마우스 버튼 뗌
btn.addEventListener('mouseup', function() {
    console.log('마우스 버튼 뗌');
});

// mouseover: 마우스가 요소 위로 이동
btn.addEventListener('mouseover', function() {
    console.log('마우스가 위로 이동');
});

// mouseout: 마우스가 요소 밖으로 이동
btn.addEventListener('mouseout', function() {
    console.log('마우스가 밖으로 이동');
});

키보드 이벤트

const input = document.getElementById('input');

// keydown: 키를 누름
input.addEventListener('keydown', function(event) {
    console.log('키 누름:', event.key);
});

// keyup: 키를 뗌
input.addEventListener('keyup', function(event) {
    console.log('키 뗌:', event.key);
});

// keypress: 키 입력 (deprecated, keydown 사용 권장)
input.addEventListener('keypress', function(event) {
    console.log('키 입력:', event.key);
});

폼 이벤트

const form = document.getElementById('form');
const input = document.getElementById('input');

// submit: 폼 제출
form.addEventListener('submit', function(event) {
    event.preventDefault();  // 기본 동작 방지
    console.log('폼 제출됨');
});

// change: 값이 변경되고 포커스가 벗어남
input.addEventListener('change', function() {
    console.log('값 변경됨:', this.value);
});

// input: 값이 변경될 때마다 (실시간)
input.addEventListener('input', function() {
    console.log('입력 중:', this.value);
});

// focus: 포커스를 받음
input.addEventListener('focus', function() {
    console.log('포커스 받음');
});

// blur: 포커스를 잃음
input.addEventListener('blur', function() {
    console.log('포커스 잃음');
});

윈도우 이벤트

// load: 페이지 로드 완료
window.addEventListener('load', function() {
    console.log('페이지 로드 완료');
});

// DOMContentLoaded: DOM 로드 완료 (더 빠름)
document.addEventListener('DOMContentLoaded', function() {
    console.log('DOM 로드 완료');
});

// resize: 윈도우 크기 변경
window.addEventListener('resize', function() {
    console.log('윈도우 크기 변경');
});

// scroll: 스크롤
window.addEventListener('scroll', function() {
    console.log('스크롤됨');
});

3. 이벤트 객체 (Event Object)

이벤트 핸들러는 이벤트 객체를 매개변수로 받습니다.

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

btn.addEventListener('click', function(event) {
    console.log(event.type);      // 'click'
    console.log(event.target);    // 클릭된 요소
    console.log(event.currentTarget);  // 이벤트 리스너가 있는 요소
});

주요 이벤트 객체 속성

btn.addEventListener('click', function(event) {
    // 이벤트 타입
    console.log(event.type);  // 'click'

    // 이벤트가 발생한 요소
    console.log(event.target);  // 실제 클릭된 요소

    // 이벤트 리스너가 있는 요소
    console.log(event.currentTarget);  // btn 요소

    // 마우스 위치 (클릭 이벤트)
    console.log(event.clientX, event.clientY);  // 화면 기준 좌표
    console.log(event.pageX, event.pageY);       // 페이지 기준 좌표

    // 키보드 이벤트
    console.log(event.key);      // 눌린 키
    console.log(event.keyCode);  // 키 코드 (deprecated)
    console.log(event.code);     // 물리적 키 코드
});

4. 이벤트 전파 (Event Propagation)

이벤트는 버블링(Bubbling)과 캡처링(Capturing) 단계를 거칩니다.

버블링 (Bubbling)

이벤트가 자식 요소에서 부모 요소로 전파됩니다 (기본값).

<div id="parent">
    <button id="child">클릭</button>
</div>
const parent = document.getElementById('parent');
const child = document.getElementById('child');

// 버블링: child → parent
child.addEventListener('click', function() {
    console.log('자식 클릭');
});

parent.addEventListener('click', function() {
    console.log('부모 클릭');
});

// child 클릭 시: "자식 클릭" → "부모 클릭"

캡처링 (Capturing)

이벤트가 부모 요소에서 자식 요소로 전파됩니다.

parent.addEventListener('click', function() {
    console.log('부모 클릭');
}, true);  // true: 캡처링 단계

child.addEventListener('click', function() {
    console.log('자식 클릭');
});

// child 클릭 시: "부모 클릭" → "자식 클릭"

이벤트 전파 중지

child.addEventListener('click', function(event) {
    console.log('자식 클릭');
    event.stopPropagation();  // 전파 중지
});

parent.addEventListener('click', function() {
    console.log('부모 클릭');  // 실행 안 됨
});

5. 기본 동작 방지

preventDefault()

폼 제출, 링크 이동 등의 기본 동작을 방지합니다.

<form id="form">
    <input type="text" name="username">
    <button type="submit">제출</button>
</form>
const form = document.getElementById('form');

form.addEventListener('submit', function(event) {
    event.preventDefault();  // 폼 제출 방지
    console.log('폼 제출이 방지되었습니다');
    // 여기서 유효성 검사 등을 수행
});

링크 기본 동작 방지

<a href="https://example.com" id="link">링크</a>
const link = document.getElementById('link');

link.addEventListener('click', function(event) {
    event.preventDefault();  // 링크 이동 방지
    console.log('링크 클릭됨 (이동 안 함)');
});

6. 이벤트 위임 (Event Delegation)

부모 요소에 이벤트 리스너를 추가하여 자식 요소의 이벤트를 처리합니다.

<ul id="list">
    <li>항목 1</li>
    <li>항목 2</li>
    <li>항목 3</li>
</ul>
const list = document.getElementById('list');

// 각 li에 이벤트 추가 (비효율적)
// const items = list.querySelectorAll('li');
// items.forEach(item => {
//     item.addEventListener('click', function() {
//         console.log(this.textContent);
//     });
// });

// 이벤트 위임 (효율적)
list.addEventListener('click', function(event) {
    if (event.target.tagName === 'LI') {
        console.log(event.target.textContent);
    }
});

// 새로운 항목 추가해도 자동으로 이벤트 처리됨
const newItem = document.createElement('li');
newItem.textContent = '항목 4';
list.appendChild(newItem);

7. 실전 예제

예제 1: 폼 유효성 검사

<form id="loginForm">
    <input type="text" id="username" placeholder="사용자명" required>
    <input type="password" id="password" placeholder="비밀번호" required>
    <button type="submit">로그인</button>
</form>
<div id="error"></div>
const form = document.getElementById('loginForm');
const error = document.getElementById('error');

form.addEventListener('submit', function(event) {
    event.preventDefault();

    const username = document.getElementById('username').value;
    const password = document.getElementById('password').value;

    if (username.trim() === '') {
        error.textContent = '사용자명을 입력하세요';
        return;
    }

    if (password.length < 6) {
        error.textContent = '비밀번호는 6자 이상이어야 합니다';
        return;
    }

    error.textContent = '';
    alert('로그인 성공!');
});

예제 2: 실시간 검색

<input type="text" id="search" placeholder="검색...">
<div id="results"></div>
const search = document.getElementById('search');
const results = document.getElementById('results');

search.addEventListener('input', function() {
    const query = this.value;

    if (query.length > 0) {
        // 검색 로직 (예시)
        results.textContent = `"${query}" 검색 결과...`;
    } else {
        results.textContent = '';
    }
});

예제 3: 키보드 단축키

document.addEventListener('keydown', function(event) {
    // Ctrl + S (저장)
    if (event.ctrlKey && event.key === 's') {
        event.preventDefault();
        console.log('저장됨');
    }

    // ESC 키
    if (event.key === 'Escape') {
        console.log('취소됨');
    }
});

예제 4: 드래그 앤 드롭 (간단한 예제)

<div id="box" style="width: 100px; height: 100px; background: red; position: absolute;"></div>
const box = document.getElementById('box');
let isDragging = false;
let offset = {x: 0, y: 0};

box.addEventListener('mousedown', function(event) {
    isDragging = true;
    offset.x = event.clientX - box.offsetLeft;
    offset.y = event.clientY - box.offsetTop;
});

document.addEventListener('mousemove', function(event) {
    if (isDragging) {
        box.style.left = (event.clientX - offset.x) + 'px';
        box.style.top = (event.clientY - offset.y) + 'px';
    }
});

document.addEventListener('mouseup', function() {
    isDragging = false;
});

8. 이벤트 리스너 제거

removeEventListener()

이벤트 리스너를 제거합니다.

function handleClick() {
    console.log('클릭됨');
}

btn.addEventListener('click', handleClick);

// 나중에 제거
btn.removeEventListener('click', handleClick);

주의: 같은 함수 참조를 사용해야 제거됩니다.


주의사항

1. 이벤트 리스너 중복 추가

// ❌ 같은 이벤트 리스너가 여러 번 추가될 수 있음
btn.addEventListener('click', function() {
    console.log('클릭');
});
btn.addEventListener('click', function() {
    console.log('클릭');  // 중복 실행됨
});

// ✅ 함수를 변수에 저장하여 제어
const handleClick = function() {
    console.log('클릭');
};
btn.addEventListener('click', handleClick);

2. 이벤트 객체 사용

// ✅ 이벤트 객체 활용
btn.addEventListener('click', function(event) {
    console.log(event.target);  // 클릭된 요소
    console.log(event.type);    // 이벤트 타입
});

3. this 바인딩

// 일반 함수: this는 이벤트가 발생한 요소
btn.addEventListener('click', function() {
    console.log(this);  // btn 요소
});

// 화살표 함수: this는 상위 스코프
btn.addEventListener('click', () => {
    console.log(this);  // window (또는 상위 스코프)
});

연습 문제

  1. 버튼 클릭 이벤트

    • 버튼을 클릭하면 콘솔에 메시지를 출력하세요.
  2. 입력 필드 이벤트

    • 입력 필드에 텍스트를 입력할 때마다 실시간으로 글자 수를 표시하세요.
  3. 폼 제출 이벤트

    • 폼을 제출할 때 기본 동작을 방지하고 유효성 검사를 수행하세요.
  4. 키보드 이벤트

    • Enter 키를 누르면 버튼이 클릭되도록 하세요.
  5. 이벤트 위임

    • 리스트에 동적으로 추가되는 항목들도 클릭 이벤트가 동작하도록 이벤트 위임을 사용하세요.

다음 장 예고

다음 장에서는 스코프(Scope)와 호이스팅(Hoisting)에 대해 학습합니다.

'FrontEnd > Javascript' 카테고리의 다른 글

14장. 실습 문제  (0) 2026.01.13
13장. 스코프와 호이스팅  (0) 2026.01.12
11장. DOM 조작  (0) 2026.01.10
10. 객체  (0) 2026.01.09
9. 배열  (0) 2026.01.09