모든 강의를 무료로 볼 수 있어요. 회원가입 없이도 학습 가능합니다.

18강 / 전체 22강

이벤트 처리

14분 읽기 조회 3

addEventListener로 이벤트 등록, 이벤트 객체의 target·key·preventDefault, 클릭·마우스·키보드 이벤트 종류, removeEventListener와 메모리 관리까지 사용자 상호작용의 모든 것을 배웁니다.

🎯 학습 목표

이 강을 마치면 다음을 할 수 있습니다.

  • addEventListener로 이벤트를 등록하고 removeEventListener로 해제할 수 있습니다.
  • 이벤트 객체(event)의 target, currentTarget, type을 활용할 수 있습니다.
  • preventDefault()와 stopPropagation()의 역할을 이해하고 사용할 수 있습니다.
  • 클릭, 마우스, 키보드, 포커스 이벤트를 처리할 수 있습니다.

🎧 addEventListener — 이벤트 등록

이 섹션에서는 DOM 요소에 이벤트 리스너를 등록하는 방법과 기본 원리를 살펴보겠습니다.

웹 페이지에서 사용자의 행동(클릭, 키 입력, 마우스 이동 등)은 모두 이벤트(Event)로 표현됩니다. 자바스크립트는 이 이벤트가 발생했을 때 실행할 함수를 등록해 두는 방식으로 사용자와 상호작용합니다. 이를 이벤트 리스너(Event Listener) 패턴이라고 합니다.

const btn = document.querySelector("#myButton");

// 기본 형태: addEventListener(이벤트명, 콜백 함수)
btn.addEventListener("click", function(event) {
  console.log("버튼 클릭!");
});

// 화살표 함수로 (더 간결)
btn.addEventListener("click", (event) => {
  console.log("버튼 클릭!");
});

// 함수를 분리해 등록 (재사용 및 나중에 해제 가능)
function handleClick(event) {
  console.log("클릭 이벤트!", event.type);  // "click"
}

btn.addEventListener("click", handleClick);

// 이벤트 해제 — 동일한 함수 참조 필요!
btn.removeEventListener("click", handleClick);
// 주의: 아래처럼 익명 함수면 해제 불가
// btn.removeEventListener("click", () => {});  // ❌ 새 함수라 매칭 안 됨

// 한 번만 실행하는 이벤트
btn.addEventListener("click", handleClick, { once: true });
// 클릭 후 자동으로 리스너 제거됨

addEventListener는 구형 방식인 onclick = function에 비해 여러 장점이 있습니다. 첫째, 같은 이벤트에 여러 리스너를 등록할 수 있습니다. 둘째, 세 번째 인수로 옵션을 설정할 수 있습니다(once, passive, capture). 셋째, removeEventListener로 명시적으로 해제할 수 있습니다. 이벤트 리스너는 등록할 때 사용한 함수와 동일한 참조여야 해제할 수 있으므로, 나중에 해제할 리스너는 변수에 담아두어야 합니다.

📦 이벤트 객체 — event

이 섹션에서는 이벤트 발생 시 콜백 함수에 전달되는 이벤트 객체의 주요 속성을 살펴보겠습니다.

이벤트 리스너의 콜백 함수는 이벤트 객체를 자동으로 첫 번째 인수로 받습니다. 이 객체에는 어디서, 무슨 이벤트가 발생했는지, 어떤 값으로 발생했는지 등 모든 정보가 담겨 있습니다.

document.addEventListener("click", (event) => {
  // 이벤트 기본 정보
  console.log(event.type);           // "click"
  console.log(event.timeStamp);      // 이벤트 발생 시각 (ms)

  // 어떤 요소에서 발생했나
  console.log(event.target);         // 실제 클릭된 요소
  console.log(event.currentTarget);  // addEventListener가 등록된 요소
  // target: 실제로 클릭된 요소 (자식일 수 있음)
  // currentTarget: 이벤트 리스너가 붙은 요소

  // 마우스 위치
  console.log(event.clientX, event.clientY);  // 뷰포트 기준 좌표
  console.log(event.pageX, event.pageY);      // 페이지 기준 좌표
});

// 키보드 이벤트 객체
document.addEventListener("keydown", (event) => {
  console.log(event.key);     // "a", "Enter", "ArrowLeft" 등
  console.log(event.code);    // "KeyA", "Enter", "ArrowLeft" (물리 키)
  console.log(event.ctrlKey); // Ctrl 키 눌렸나? (boolean)
  console.log(event.shiftKey); // Shift 키?
  console.log(event.altKey);   // Alt 키?

  // Ctrl+S 단축키 감지
  if (event.ctrlKey && event.key === "s") {
    console.log("저장!");
    event.preventDefault();  // 브라우저 기본 동작(파일 저장) 막기
  }
});

event.target과 event.currentTarget의 차이는 중요합니다. target은 실제로 이벤트가 발생한 요소이고, currentTarget은 리스너가 등록된 요소입니다. 부모 요소에 리스너를 등록했을 때 자식 요소를 클릭하면 target은 자식, currentTarget은 부모가 됩니다. 이 개념은 21강의 이벤트 버블링과 이벤트 위임의 핵심입니다.

🚫 preventDefault와 stopPropagation

이 섹션에서는 브라우저의 기본 동작을 막고 이벤트 전파를 제어하는 방법을 살펴보겠습니다.

HTML 요소 중에는 자체 기본 동작이 있는 것들이 있습니다. <a> 태그를 클릭하면 페이지를 이동하고, 폼을 제출하면 페이지가 새로고침됩니다. 자바스크립트로 이 동작을 막아 원하는 처리를 할 수 있습니다.

// 링크 기본 동작 막기
const link = document.querySelector("a");
link.addEventListener("click", (event) => {
  event.preventDefault();  // 페이지 이동 막기
  console.log("링크 클릭! 이동 안 함");
  // 여기서 자바스크립트로 원하는 동작 수행
});

// 폼 제출 막기 — AJAX 처리를 위해 자주 사용
const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
  event.preventDefault();  // 페이지 새로고침 막기

  // 대신 자바스크립트로 처리
  const formData = new FormData(form);
  console.log(formData.get("username"));
  // fetch로 비동기 전송 (26강에서 학습)
});

// 우클릭 컨텍스트 메뉴 막기
document.addEventListener("contextmenu", (event) => {
  event.preventDefault();
  // 커스텀 컨텍스트 메뉴 표시
});

// stopPropagation — 이벤트 버블링 중단
const outer = document.querySelector(".outer");
const inner = document.querySelector(".inner");

outer.addEventListener("click", () => {
  console.log("outer 클릭");
});

inner.addEventListener("click", (event) => {
  event.stopPropagation();  // outer까지 이벤트 전파 막기
  console.log("inner 클릭");  // 이것만 출력됨
});

preventDefault()는 브라우저의 기본 동작을 막습니다. stopPropagation()은 이벤트가 부모 요소로 전파되는 것을 막습니다. 이 둘은 독립적입니다. 폼 제출에서 preventDefault()를 사용하면 페이지 새로고침 없이 자바스크립트로 데이터를 처리할 수 있는데, 이는 현대 웹 앱의 핵심 패턴입니다. stopPropagation()에 대해서는 21강에서 이벤트 버블링과 위임을 배울 때 자세히 다룹니다.

🖱️ 주요 이벤트 종류

이 섹션에서는 실무에서 자주 사용하는 이벤트 종류와 각각의 특성을 살펴보겠습니다.

자바스크립트 이벤트는 수십 가지가 있지만, 실무에서 자주 쓰는 것은 한정되어 있습니다. 카테고리별로 핵심 이벤트를 정리해 보겠습니다.

const el = document.querySelector(".box");
const input = document.querySelector("input");

// 마우스 이벤트
el.addEventListener("click",      (e) => console.log("클릭"));
el.addEventListener("dblclick",   (e) => console.log("더블클릭"));
el.addEventListener("mousedown",  (e) => console.log("마우스 버튼 눌림"));
el.addEventListener("mouseup",    (e) => console.log("마우스 버튼 뗌"));
el.addEventListener("mouseenter", (e) => console.log("마우스 진입 (버블링 없음)"));
el.addEventListener("mouseleave", (e) => console.log("마우스 이탈 (버블링 없음)"));
el.addEventListener("mouseover",  (e) => console.log("마우스 오버 (버블링 있음)"));
el.addEventListener("mousemove",  (e) => console.log(`좌표: ${e.clientX}, ${e.clientY}`));

// 키보드 이벤트
document.addEventListener("keydown",  (e) => console.log(`키 눌림: ${e.key}`));
document.addEventListener("keyup",    (e) => console.log(`키 뗌: ${e.key}`));
// keypress는 deprecated — keydown 사용 권장

// 폼/입력 이벤트
input.addEventListener("input",  (e) => console.log(`입력값: ${e.target.value}`));
input.addEventListener("change", (e) => console.log(`확정값: ${e.target.value}`));
input.addEventListener("focus",  (e) => console.log("포커스 받음"));
input.addEventListener("blur",   (e) => console.log("포커스 잃음"));

// 문서/창 이벤트
window.addEventListener("load",   () => console.log("모든 리소스 로드 완료"));
window.addEventListener("resize", () => console.log(`창 크기: ${window.innerWidth}`));
window.addEventListener("scroll", () => console.log(`스크롤: ${window.scrollY}`));
document.addEventListener("DOMContentLoaded", () => console.log("HTML 파싱 완료"));

mouseenter/mouseleave와 mouseover/mouseout의 차이를 알아두세요. mouseenter는 요소 자체에 마우스가 들어올 때만 발생하고 버블링이 없습니다. mouseover는 하위 요소에서도 버블링이 일어나 자식에 마우스가 들어와도 발생합니다. 대부분의 경우 mouseenter/mouseleave가 의도한 동작에 맞습니다. input 이벤트는 사용자가 타이핑할 때마다 발생하고, change는 포커스를 잃을 때(또는 체크박스/셀렉트 변경 시) 발생합니다. 실시간 검색 자동완성은 input을 사용합니다.

⚠️ 자주 하는 실수

이 섹션에서는 이벤트 처리에서 초보자가 가장 자주 겪는 실수를 살펴보겠습니다.

// 실수 1: 클로저 문제 — 루프에서 이벤트 등록
const buttons = document.querySelectorAll(".btn");

// ❌ 잘못된 방법 — var는 함수 스코프라 클로저 문제 발생
for (var i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener("click", () => {
    console.log(i);  // 항상 buttons.length 출력 (3 등)
  });
}

// ✅ let으로 해결 — 블록 스코프
for (let i = 0; i < buttons.length; i++) {
  buttons[i].addEventListener("click", () => {
    console.log(i);  // 정확한 인덱스 출력
  });
}

// ✅ forEach로 해결
buttons.forEach((btn, index) => {
  btn.addEventListener("click", () => {
    console.log(index);  // 정확한 인덱스
  });
});

// 실수 2: 이벤트 리스너 중복 등록
function setup() {
  // setup()이 여러 번 호출되면 리스너도 중복 등록!
  document.querySelector("#btn").addEventListener("click", handleClick);
}
// 해결: 리스너 해제 후 재등록, 또는 once 옵션 사용

// 실수 3: this 컨텍스트 혼동
const obj = {
  name: "홍길동",
  // 화살표 함수는 this가 obj가 아님!
  handleClick: (event) => {
    console.log(this.name);  // undefined
  },
  // 일반 함수는 this가 이벤트 타겟
  handleClick2(event) {
    console.log(this === event.currentTarget);  // true
    // obj.name에 접근하려면 화살표 함수나 bind 필요
  }
};

📝 핵심 요약

18강에서 배운 내용을 정리해 보겠습니다.

개념사용법핵심 특징
이벤트 등록el.addEventListener(type, fn)같은 이벤트에 여러 리스너 가능
이벤트 해제el.removeEventListener(type, fn)동일 함수 참조 필수
한 번만 실행{ once: true } 옵션실행 후 자동 해제
event.target실제 이벤트 발생 요소자식 요소 클릭 시 자식
event.currentTarget리스너가 등록된 요소항상 addEventListener 대상
preventDefault()브라우저 기본 동작 막기링크 이동, 폼 새로고침 등
stopPropagation()이벤트 버블링 중단부모로 전파 차단

다음 강인 19강 — 폼과 입력값에서는 이벤트 처리를 폼과 연결합니다. 텍스트 입력, 체크박스, 라디오 버튼, 셀렉트 박스 등 다양한 폼 요소에서 값을 읽는 방법, 유효성 검사, 폼 데이터 처리까지 배웁니다. 18강의 이벤트 처리 + 19강의 폼 처리가 합쳐지면 실용적인 입력 기능을 만들 수 있게 됩니다!

관련 주제

  • addEventListener
  • 이벤트 객체 target
  • preventDefault
  • stopPropagation
  • 클릭 키보드 이벤트
  • 개발·프로그래밍
  • 개발·프로그래밍 강의
  • 자바스크립트 기초 30강 — 웹을 움직이는 언어
  • 무료강의
  • 무료 온라인 강의
  • NUGUNA
  • 누구나

📚 시리즈 전체 공유

자바스크립트 기초 30강 — 웹을 움직이는 언어

이 강의가 속한 시리즈는 총 22강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.

댓글

0/1000

불러오는 중...