← JavaScript 강의 목록으로
🖱️
DOM
중급 · 선수: 18_DOM_조작

19. 이벤트 처리

같은 함수 참조를 넘겨야 제거가 가능합니다. 익명 함수는 제거할 수 없습니다.

이벤트click버블링위임
소요 시간
약 1시간
난이도
📊 중급
선수 조건
🎯 단원 18
결과물
같은 함수 참조를 넘겨야 제거가 가능합니다. 익명 함수는 제거할 수 없습니다.

이 강의에서 배우는 것

  • 1`addEventListener` 로 이벤트 핸들러를 등록/해제한다.
  • 2이벤트 객체에서 target, type 등을 읽는다.
  • 3`preventDefault` 와 `stopPropagation` 을 구분한다.
  • 4이벤트 위임(delegation) 을 활용해 많은 핸들러를 줄인다.
  • 5캡처/버블 단계의 개념을 안다.

소개

같은 함수 참조를 넘겨야 제거가 가능합니다. 익명 함수는 제거할 수 없습니다.

핵심 개념

1. addEventListener

javascript
btn.addEventListener("click", handler);
btn.removeEventListener("click", handler);

같은 함수 참조를 넘겨야 제거가 가능합니다. 익명 함수는 제거할 수 없습니다.

2. 이벤트 객체

콜백은 `Event` 객체를 받습니다.

  • `event.target`: 실제로 이벤트가 발생한 요소
  • `event.currentTarget`: 리스너가 붙은 요소
  • `event.type`: "click", "input" 등
  • `event.key`, `event.code`: 키보드 이벤트

3. preventDefault / stopPropagation

  • `preventDefault()`: 기본 동작(폼 제출, 링크 이동 등)을 막음.
  • `stopPropagation()`: 이벤트가 부모로 전파되는 것을 막음.

4. 이벤트 위임

자식이 많을 때 각각 등록하지 말고 부모 한 곳에서 처리합니다.

javascript
list.addEventListener("click", (e) => {
  const li = e.target.closest("li");
  if (!li) return;
  console.log("클릭된 항목:", li.textContent);
});

5. 캡처와 버블

이벤트는 window → 대상 → 부모로 전파됩니다(캡처 → 버블). 기본은 버블 단계에서 호출되며 `addEventListener(type, fn, { capture: true })` 로 캡처 단계 등록도 가능합니다.

핵심 예제

파일다루는 내용
index.html예제 HTML
01_addeventlistener.js이벤트 등록/해제
02_event_object.js이벤트 객체 속성
03_prevent_default.jspreventDefault 사용
04_delegation.js이벤트 위임

src/01_addeventlistener.js

javascript
/**
 * addEventListener / removeEventListener 사용.
 */
const btn = document.querySelector("#btn");

function onClick() {
  console.log("버튼 클릭됨");
}

btn.addEventListener("click", onClick);

// 한 번만 실행되는 리스너
btn.addEventListener("click", () => console.log("한 번만!"), { once: true });

src/02_event_object.js

javascript
/**
 * 이벤트 객체에서 정보를 읽습니다.
 */
const input = document.querySelector("#text");
input.addEventListener("input", (event) => {
  console.log("type:", event.type);
  console.log("target value:", event.target.value);
});

src/03_prevent_default.js

javascript
/**
 * preventDefault 로 링크 이동을 막습니다.
 */
const link = document.querySelector("#link");
link.addEventListener("click", (event) => {
  event.preventDefault();
  console.log("링크 이동을 막았습니다.");
});

src/04_delegation.js

javascript
/**
 * 부모 한 곳에서 자식 클릭을 처리(이벤트 위임).
 */
const menu = document.querySelector("#menu");
menu.addEventListener("click", (event) => {
  const li = event.target.closest("li");
  if (!li || !menu.contains(li)) return;
  console.log("선택:", li.textContent);
});

src/index.html

html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>이벤트 처리</title>
  </head>
  <body>
    <button id="btn">클릭</button>
    <a id="link" href="https://example.com">링크</a>
    <ul id="menu">
      <li>홈</li>
      <li>소개</li>
      <li>연락처</li>
    </ul>
    <input id="text" type="text" placeholder="입력" />

    <script src="01_addeventlistener.js"></script>
    <script src="02_event_object.js"></script>
    <script src="03_prevent_default.js"></script>
    <script src="04_delegation.js"></script>
  </body>
</html>

자주 하는 실수

  1. `onclick = fn` 으로 한 번에 한 핸들러만 등록 가능한 문제.
  2. 익명 함수를 등록 후 제거 시도.
  3. `event.target` 과 `event.currentTarget` 혼동.
  4. 폼의 submit 에서 `preventDefault` 잊어 페이지가 새로고침.
  5. 동적으로 추가된 자식에 이벤트가 없어 위임 필요한 상황을 못 봄.

FAQ

Q1. once 옵션은?

`{ once: true }` 로 한 번만 실행 후 자동 해제됩니다.

Q2. passive 리스너는?

스크롤 성능을 위해 `{ passive: true }` 로 등록하면 preventDefault 호출이 무시됩니다.

Q3. 이벤트 전파를 막는 건 항상 좋나요?

다른 핸들러를 깨뜨릴 수 있으므로 꼭 필요한 경우만.

과제

목록에서 어떤 항목을 클릭해도 클릭된 텍스트를 출력하는 위임형 핸들러를 만드세요.

homework/README.md

목록(`<ul>`)에 항목 5개를 두고, 위임 한 방식으로 클릭된 항목의 텍스트를 콘솔에 출력하세요.

답안은 `answer/homework_01.html`, `answer/homework_01.js` 참고.

homework/answer/homework_01.html

html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>과제 19-1</title>
  </head>
  <body>
    <ul id="list">
      <li>알파</li>
      <li>베타</li>
      <li>감마</li>
      <li>델타</li>
      <li>엡실론</li>
    </ul>
    <script src="homework_01.js"></script>
  </body>
</html>

homework/answer/homework_01.js

javascript
/**
 * 위임으로 목록 클릭을 한 곳에서 처리합니다.
 */
const list = document.querySelector("#list");
list.addEventListener("click", (event) => {
  const li = event.target.closest("li");
  if (!li || !list.contains(li)) return;
  console.log("클릭:", li.textContent);
});

다음 단원

[20_폼과_입력](../20_폼과_입력/) — 폼 제어와 검증

예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗