본문으로 건너뛰기
웹 개발 기초집LESSON 23

이벤트로 사용자 행동 처리하기

난이도입문
예상 시간25분
선수지식이전 강의

23강. 이벤트로 사용자 행동 처리하기

이번 강의의 결과물은 사용자가 버튼을 누르면 게임·웹 프로젝트만 골라 보여 주는 필터입니다.

1. 이번 강의에서 해결할 문제

현재 프로젝트 목록은 페이지가 열릴 때 한 번 만들어지고 사용자의 행동에는 반응하지 않습니다. 클릭이라는 입력을 관찰하고 선택된 분야에 따라 카드의 표시 상태를 변경합니다.

학습 목표

  • 현재 프로젝트 목록은 페이지가 열릴 때 한 번 만들어지고 사용자의 행동에는 반응하지 않습니다. 클릭이라는 입력을 관찰하고 선택된 분야에 따라 카드의 표시 상태를 변경합니다.
  • 핵심 개념을 코드 예시와 짧은 실습에 적용하고 결과를 설명합니다.

2. 핵심 개념

  • 이벤트: 클릭, 입력, 제출처럼 브라우저에서 발생한 사건
  • 이벤트 대상: 사건을 받은 DOM 객체
  • 이벤트 리스너: 특정 이벤트를 기다렸다가 실행할 함수
  • addEventListener(type, listener): 이벤트와 처리 함수 연결
  • event.currentTarget: 현재 리스너가 등록된 요소
  • data-*: HTML 요소에 페이지 전용 데이터를 저장하는 속성
button.addEventListener("click", handleClick);

게임의 입력 이벤트가 플레이어 동작을 호출하는 것처럼 웹 이벤트도 사용자의 행동과 상태 변경 함수를 연결합니다. WHATWG DOM Events 표준

3. 코드 예시

파일명: web-basics/portfolio/index.html

<div class="project-filters" aria-label="프로젝트 분야 필터">
<button type="button" data-filter="all" aria-pressed="true">전체</button>
<button type="button" data-filter="game" aria-pressed="false">게임</button>
<button type="button" data-filter="web" aria-pressed="false"></button>
</div>

<div class="project-grid" id="project-list"></div>

22강의 카드 생성 함수에 분야 데이터를 추가합니다.

function createProjectCard(project) {
const article = document.createElement("article");
const title = document.createElement("h3");
const description = document.createElement("p");

article.className = "project-card";
article.dataset.category = project.category;
title.textContent = project.title;
description.textContent = project.description;

article.append(title, description);
return article;
}

파일명: web-basics/portfolio/js/main.js

렌더링 코드 아래에 추가합니다.

const filterButtons = document.querySelectorAll("[data-filter]");

function handleFilterClick(event) {
const selectedFilter = event.currentTarget.dataset.filter;
const cards = document.querySelectorAll(".project-card");

for (const button of filterButtons) {
const isSelected = button === event.currentTarget;
button.setAttribute("aria-pressed", String(isSelected));
}

for (const card of cards) {
const matchesFilter =
selectedFilter === "all" ||
card.dataset.category === selectedFilter;

card.hidden = !matchesFilter;
}
}

for (const button of filterButtons) {
button.addEventListener("click", handleFilterClick);
}

실행 위치: D:\WebProject\StartBook\dev-foundations\web-basics\portfolio

python -m http.server 5500

4. 코드가 동작하는 이유

  1. 각 버튼의 data-filter가 필터 값을 보관합니다.
  2. addEventListener가 클릭 이벤트와 같은 처리 함수를 연결합니다.
  3. 클릭 시 currentTarget으로 실제 리스너가 등록된 버튼을 확인합니다.
  4. 선택된 버튼만 aria-pressed="true"가 되어 상태를 전달합니다.
  5. 각 카드의 category와 선택 값을 비교합니다.
  6. 일치하지 않는 카드는 hidden = true가 되어 렌더링과 접근성 트리에서 제외됩니다.

5. 자주 하는 실수

  • 함수 호출 결과 handleFilterClick()을 리스너로 전달함
  • HTML의 data-filter와 카드 category 철자가 다름
  • event.targetevent.currentTarget을 구분하지 않음
  • 보이는 카드만 바꾸고 버튼의 선택 상태는 갱신하지 않음
  • buttontype="button"을 빠뜨려 폼 안에서 제출됨
  • 숨긴 요소를 CSS 화면에서만 가리고 키보드 포커스는 남김

6. 짧은 실습 과제

  1. 전체·게임·웹 필터 버튼을 추가합니다.
  2. 각 프로젝트 객체에 game 또는 web category를 작성합니다.
  3. 클릭할 때 알맞은 카드만 표시되는지 확인합니다.
  4. 키보드로 필터 버튼을 조작합니다.
  5. 선택된 버튼의 aria-pressed가 바뀌는지 Elements 탭에서 확인합니다.
  6. category 철자를 일부러 다르게 해 필터 오류를 재현한 뒤 수정합니다.

완료 기준은 마우스와 키보드에서 필터가 같게 동작하고 시각적 목록과 선택 상태가 함께 갱신되는 것입니다.

7. 이해 점검 질문 3개

  1. addEventListener의 두 번째 인수에는 함수 호출 결과가 아니라 무엇을 전달해야 하나요?
  2. event.currentTarget은 어떤 요소를 가리키나요?
  3. 필터 버튼의 aria-pressed를 화면과 함께 갱신하는 이유는 무엇인가요?

핵심 요약

  • 이번 강의의 핵심 개념을 코드의 구조와 실행 결과에 연결했습니다.
  • 코드 예시를 직접 바꾸는 짧은 실습으로 핵심 동작을 확인했습니다.
  • 이해 점검 질문에 답하며 다음 강의에 필요한 기준을 정리했습니다.
MINI QUIZ

이벤트로 사용자 행동 처리하기 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“이벤트로 사용자 행동 처리하기” 내용을 실제 작업에 적용한 설명으로 가장 알맞은 것은 무엇인가요?
  2. 문제 2“이벤트로 사용자 행동 처리하기”의 코드·설정이 동작하는 이유로 본문과 일치하는 것은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

23강. 이벤트로 사용자 행동 처리하기 미완료 상태