지금까지 우리는 자바스크립트로 웹 페이지의 요소를 찾고, 글자를 바꾸고, 새 요소를 추가하는 법을 배웠습니다. 그런데 여기서 한 가지 질문이 생깁니다.
"언제 바꿀까?"
버튼을 눌렀을 때 바꿀 수도 있고, 사용자가 글자를 입력할 때마다 바꿀 수도 있고, 폼을 제출하려 할 때 막을 수도 있습니다. 이처럼 브라우저에서 일어나는 사건을 자바스크립트가 감지하고 반응하는 것이 바로 이벤트입니다.1
쉽게 말해 DOM 조작이 "화면을 바꾸는 손"이라면, 이벤트는 "지금 움직여!"라고 알려 주는 신호입니다. 둘이 만나야 웹 페이지가 진짜로 인터랙티브해집니다.
이벤트란 무엇일까
이벤트는 브라우저 안에서 일어나는 여러 가지 행동이나 변화입니다. 사용자가 직접 만드는 이벤트도 있고, 브라우저가 알려 주는 이벤트도 있습니다.1
예를 들어 이런 것들이 이벤트입니다.
버튼을 클릭하는
click입력창에 글자를 쓰는
input폼을 제출하는
submit키보드를 누르는
keydown페이지가 모두 로드되는
load
즉, 이벤트는 "무언가 일어났다"는 알림입니다. 그리고 자바스크립트는 그 알림을 듣고 코드를 실행할 수 있습니다.
addEventListener는 무엇인가
이벤트를 다룰 때 가장 많이 쓰는 메서드는 addEventListener()입니다. 이름을 그대로 풀면 이벤트를 듣는 장치를 추가한다는 뜻입니다.2
기본 형태는 이렇습니다.
element.addEventListener("이벤트이름", 실행할함수);예를 들어 버튼을 클릭했을 때 반응하게 만들고 싶다면 이렇게 씁니다.
const button = document.querySelector("#my-button");
button.addEventListener("click", function () {
console.log("버튼이 클릭되었습니다!");
});이 코드는 이렇게 읽으면 됩니다.
"#my-button 요소를 지켜보다가, click 이벤트가 발생하면 뒤의 함수를 실행해라."
여기서 중요한 점이 하나 있습니다. addEventListener() 안에서는 "onclick"이 아니라 "click"처럼 on을 뺀 이름을 씁니다.2
첫 번째 실습: 클릭하면 글자 바꾸기
이벤트는 직접 만져 봐야 감이 빨리 옵니다. 가장 대표적인 예제는 역시 버튼 클릭입니다.
<button id="change-btn">눌러 보세요</button>
<p id="message">아직 아무 일도 일어나지 않았습니다.</p>const button = document.querySelector("#change-btn");
const message = document.querySelector("#message");
button.addEventListener("click", function () {
message.textContent = "버튼을 눌렀군요! 이제 이벤트가 동작했습니다.";
});이 예제의 흐름은 단순합니다.
먼저 버튼과 문단을 선택합니다. 그리고 버튼에 click 이벤트 리스너를 붙입니다. 사용자가 버튼을 클릭하면 함수가 실행되고, 그 안에서 문단의 글자가 바뀝니다.
바로 이 순간, DOM 조작과 이벤트가 연결됩니다.
함수를 따로 빼면 더 읽기 쉽다
작은 예제에서는 익명 함수를 바로 넣어도 괜찮습니다. 하지만 코드가 길어지면 함수 이름을 따로 붙여 두는 편이 읽기 쉽습니다.
<button id="hello-btn">인사하기</button>
<p id="result"></p>const helloBtn = document.querySelector("#hello-btn");
const result = document.querySelector("#result");
function sayHello() {
result.textContent = "안녕하세요! 반갑습니다.";
}
helloBtn.addEventListener("click", sayHello);이렇게 하면 코드가 훨씬 또렷해집니다.
addEventListener("click", sayHello)는 마치 버튼에게 "클릭되면 sayHello를 불러"라고 부탁하는 느낌입니다.
같은 요소에 여러 이벤트를 붙일 수도 있다
addEventListener()의 좋은 점은 하나의 요소에 이벤트를 여러 개 붙일 수 있다는 것입니다. 클릭도 듣고, 마우스를 올렸을 때도 듣고, 떼었을 때도 들을 수 있습니다.2
<button id="play-btn">나를 살펴봐 주세요</button>
<p id="status"></p>const playBtn = document.querySelector("#play-btn");
const status = document.querySelector("#status");
playBtn.addEventListener("click", function () {
status.textContent = "클릭했습니다.";
});
playBtn.addEventListener("mouseenter", function () {
status.textContent = "마우스가 버튼 위에 올라왔습니다.";
});
playBtn.addEventListener("mouseleave", function () {
status.textContent = "마우스가 버튼 밖으로 나갔습니다.";
});같은 버튼인데도 상황에 따라 다른 반응을 만들 수 있습니다. 웹 페이지가 슬슬 성격을 가지기 시작하는 순간입니다.
input 이벤트: 입력하는 즉시 반응하기
버튼 클릭만으로는 조금 아쉽습니다. 진짜 인터랙티브한 화면은 사용자가 입력하는 순간에도 반응합니다.
이때 아주 중요한 이벤트가 input입니다. input 이벤트는 사용자가 입력창에 글자를 치거나 값을 바꿀 때마다 발생합니다.3
<input id="name-input" type="text" placeholder="이름을 입력하세요" />
<p id="preview">여기에 입력한 내용이 보입니다.</p>const nameInput = document.querySelector("#name-input");
const preview = document.querySelector("#preview");
nameInput.addEventListener("input", function () {
preview.textContent = nameInput.value;
});이제 입력창에 민지라고 치면, 아래 문단도 글자 하나씩 바로 따라 바뀝니다.
이런 방식은 검색창 미리보기, 닉네임 표시, 글자 수 세기 같은 기능의 출발점입니다.
input과 change는 어떻게 다를까
초보자가 자주 헷갈리는 부분이 바로 input과 change입니다.
input은 값이 바뀌는 동안 계속 발생합니다. 사용자가 한 글자 입력할 때마다 반응합니다.3
반면 change는 값 변경이 확정되었을 때 발생합니다. 예를 들어 입력창에서 글자를 바꾸고 나서 포커스를 다른 곳으로 옮기면 그때 실행되기도 합니다.3
쉽게 기억하면 이렇습니다.
입력하는 즉시 반응하고 싶으면
input선택이나 입력 완료 후 반응해도 되면
change
초보자 연습에서는 실시간 반응을 눈으로 확인하기 쉬운 input이 특히 재미있습니다.
value: 입력한 값 읽기
입력 요소를 다룰 때는 value를 자주 사용합니다. value는 입력창 안에 들어 있는 현재 값을 뜻합니다.
const input = document.querySelector("#name-input");
console.log(input.value);이 코드는 사용자가 입력한 내용을 읽어 옵니다. 버튼과 문단은 textContent를 주로 다뤘다면, 입력창은 value를 자주 다룬다고 생각하면 됩니다.
예를 들어 버튼을 눌렀을 때 입력값을 화면에 보여 줄 수도 있습니다.
<input id="food-input" type="text" placeholder="좋아하는 음식을 입력하세요" />
<button id="show-btn">보여 주기</button>
<p id="food-result"></p>const foodInput = document.querySelector("#food-input");
const showBtn = document.querySelector("#show-btn");
const foodResult = document.querySelector("#food-result");
showBtn.addEventListener("click", function () {
foodResult.textContent = `좋아하는 음식: ${foodInput.value}`;
});이제 이벤트와 입력값 읽기가 함께 연결됩니다.
이벤트 객체란 무엇인가
이벤트가 발생하면 자바스크립트는 그냥 "클릭됐어요"만 알려 주지 않습니다. 이벤트에 대한 여러 정보를 함께 담아서 전달해 줍니다. 이 정보를 담고 있는 값이 바로 이벤트 객체입니다.2
보통 함수의 매개변수로 받아서 사용합니다.
button.addEventListener("click", function (event) {
console.log(event);
});event라는 이름은 많이 쓰는 관례일 뿐입니다. e라고 써도 됩니다.
button.addEventListener("click", function (e) {
console.log(e);
});이 객체 안에는 정말 많은 정보가 들어 있습니다. 초보자 단계에서는 전부 외울 필요는 없고, 자주 쓰는 몇 가지만 익히면 충분합니다.
가장 자주 보는 이벤트 정보들
이벤트 객체에서 특히 자주 만나는 속성은 다음과 같습니다.12
event.target: 실제로 이벤트가 발생한 요소event.type: 이벤트 이름event.key: 키보드 이벤트에서 어떤 키를 눌렀는지event.clientX,event.clientY: 마우스 위치
예제를 보겠습니다.
<button id="info-btn">내 정보를 찍어 줘</button>const infoBtn = document.querySelector("#info-btn");
infoBtn.addEventListener("click", function (event) {
console.log("이벤트 종류:", event.type);
console.log("클릭된 요소:", event.target);
});버튼을 클릭하면 콘솔에 click과 버튼 요소 정보가 출력됩니다.
이벤트 객체는 마치 현장 리포터 같습니다. "어디서 일어났는지", "무슨 종류인지", "어떤 값이 들어왔는지"를 알려 줍니다.
event.target은 왜 중요할까
event.target은 실제로 이벤트가 발생한 요소를 가리킵니다. 특히 여러 요소를 다룰 때 아주 유용합니다.
예를 들어 버튼을 클릭한 뒤, 클릭된 버튼 자신의 글자를 바꾸고 싶다면 이렇게 할 수 있습니다.
<button class="menu-btn">피자</button>
<button class="menu-btn">치킨</button>
<button class="menu-btn">햄버거</button>const menuButtons = document.querySelectorAll(".menu-btn");
menuButtons.forEach(function (button) {
button.addEventListener("click", function (event) {
event.target.textContent = "선택 완료!";
});
});어떤 버튼을 누르든, 바로 그 버튼의 글자만 바뀝니다.
이처럼 event.target은 "누가 지금 반응의 주인공인가"를 알려 줍니다.
키보드 이벤트도 이벤트다
입력창에서는 input 말고도 키보드 이벤트를 사용할 수 있습니다. 예를 들어 사용자가 어떤 키를 눌렀는지 알고 싶을 때 keydown을 사용합니다.1
<input id="key-input" type="text" placeholder="아무 키나 눌러 보세요" />
<p id="key-result"></p>const keyInput = document.querySelector("#key-input");
const keyResult = document.querySelector("#key-result");
keyInput.addEventListener("keydown", function (event) {
keyResult.textContent = `방금 누른 키: ${event.key}`;
});A를 누르면 A, Enter를 누르면 Enter처럼 표시됩니다.
키보드 이벤트는 나중에 게임 조작, 단축키, 엔터키 검색 같은 기능을 만들 때 아주 자주 등장합니다.
기본 동작이라는 것이 있다
브라우저의 요소들은 원래부터 자기 성격이 있습니다.
링크를 누르면 이동하려고 하고, 폼을 제출하면 새로고침하거나 서버로 데이터를 보내려고 하고, 체크박스를 누르면 체크 상태가 바뀌려고 합니다. 이런 브라우저의 원래 행동을 기본 동작이라고 합니다.4
그런데 우리는 가끔 이렇게 말하고 싶습니다.
"잠깐만, 브라우저야. 네가 평소 하던 행동은 잠시 멈추고, 이번에는 내가 정한 방식으로 움직여 줘."
이럴 때 사용하는 것이 event.preventDefault()입니다.4
preventDefault()로 기본 동작 막기
가장 대표적인 예시는 링크입니다.
<a rel="nofollow ugc noopener" id="my-link" href="https://example.com">이동 대신 메시지 보기</a>
<p id="link-result"></p>const myLink = document.querySelector("#my-link");
const linkResult = document.querySelector("#link-result");
myLink.addEventListener("click", function (event) {
event.preventDefault();
linkResult.textContent = "링크 이동을 막고 자바스크립트가 대신 반응했습니다.";
});원래라면 링크를 누르면 다른 페이지로 이동합니다. 하지만 preventDefault()를 호출하면 그 기본 동작이 취소되고, 대신 우리가 작성한 코드가 실행됩니다.4
폼 제출 막고 직접 처리하기
preventDefault()가 특히 자주 쓰이는 곳은 폼입니다. 폼은 제출되면 페이지가 새로고침되거나 다른 주소로 이동할 수 있습니다. 하지만 우리는 입력값을 먼저 검사하거나, 메시지를 보여 준 뒤에 처리하고 싶을 수 있습니다.
<form id="signup-form">
<input id="username" type="text" placeholder="사용자 이름" />
<button type="submit">가입하기</button>
</form>
<p id="form-message"></p>const signupForm = document.querySelector("#signup-form");
const username = document.querySelector("#username");
const formMessage = document.querySelector("#form-message");
signupForm.addEventListener("submit", function (event) {
event.preventDefault();
if (username.value === "") {
formMessage.textContent = "이름을 입력해 주세요.";
return;
}
formMessage.textContent = `${username.value}님, 가입 요청이 접수되었습니다.`;
});이 코드는 폼의 기본 제출 동작을 막고, 자바스크립트가 직접 입력값을 검사한 뒤 메시지를 보여 줍니다.
초보자 입장에서는 이 장면이 꽤 중요합니다. 왜냐하면 여기서부터 웹 페이지가 "사용자 입력을 받고 판단하는 프로그램"처럼 보이기 시작하기 때문입니다.
preventDefault()와 stopPropagation()은 다르다
이름이 비슷해서 헷갈리기 쉽지만, preventDefault()는 브라우저의 기본 행동을 막는 것이고, stopPropagation()은 이벤트가 부모 요소로 퍼져 나가는 것을 막는 것입니다.4
지금 단계에서는 이렇게만 기억해도 충분합니다.
링크 이동, 폼 제출 같은 기본 행동을 막고 싶다 →
preventDefault()클릭 이벤트가 바깥 요소까지 전달되지 않게 하고 싶다 →
stopPropagation()
이번 장의 핵심은 기본 동작 제어이므로, 우선은 preventDefault()를 확실히 익히는 것이 좋습니다.
작은 실전 예제: 실시간 글자 수 세기
이제 input 이벤트와 DOM 조작을 합쳐서 작은 예제를 만들어 봅시다.
<textarea id="post-input" placeholder="오늘의 한 줄을 적어 보세요"></textarea>
<p id="count">0자</p>const postInput = document.querySelector("#post-input");
const count = document.querySelector("#count");
postInput.addEventListener("input", function () {
count.textContent = `${postInput.value.length}자`;
});사용자가 글자를 입력할 때마다 길이가 바로 표시됩니다.
이 기능은 작아 보여도 실전에서 정말 자주 씁니다. 소개글 입력, 댓글 작성, 제목 길이 제한 표시 같은 곳에서 늘 등장합니다.
작은 실전 예제: 버튼 클릭 횟수 세기
클릭 이벤트도 조금 더 재밌게 써 볼 수 있습니다.
<button id="count-btn">클릭!</button>
<p id="click-count">0번 클릭했습니다.</p>const countBtn = document.querySelector("#count-btn");
const clickCount = document.querySelector("#click-count");
let number = 0;
countBtn.addEventListener("click", function () {
number += 1;
clickCount.textContent = `${number}번 클릭했습니다.`;
});사용자가 버튼을 누를 때마다 숫자가 올라갑니다.
여기서는 이벤트뿐 아니라 변수도 함께 쓰였습니다. 결국 인터랙티브한 웹은 이런 조합으로 만들어집니다.
사용자의 행동을 이벤트로 감지하고
자바스크립트가 값을 계산하고
DOM을 바꿔서 화면에 보여 준다
자주 하는 실수
이벤트를 처음 배울 때는 작은 실수가 자주 나옵니다. 미리 알고 있으면 디버깅 시간이 줄어듭니다.
이벤트 이름에 on을 붙이는 실수
button.addEventListener("onclick", myFunction);이렇게 쓰면 안 됩니다. addEventListener()에서는 "onclick"이 아니라 "click"을 써야 합니다.2
button.addEventListener("click", myFunction);함수 실행 결과를 넣는 실수
button.addEventListener("click", sayHello());이 코드는 클릭할 때 실행되는 것이 아니라, 코드를 읽는 순간 바로 실행됩니다.
이벤트에 연결하려면 함수 자체를 넘겨야 합니다.
button.addEventListener("click", sayHello);요소를 찾기 전에 스크립트가 실행되는 실수
HTML이 아직 다 만들어지기 전에 자바스크립트가 먼저 실행되면 요소를 찾지 못할 수 있습니다. 입문 단계에서는 <script>를 </body> 바로 앞에 두는 방식이 이해하기 쉽습니다.
input 값을 textContent로 읽으려는 실수
입력창의 내용은 보통 textContent가 아니라 value로 읽습니다.
console.log(input.value);이 차이를 헷갈리면 값이 안 나오는 것처럼 보일 수 있습니다.
이번 장의 핵심 흐름
이 장에서 배운 내용을 아주 짧게 정리하면 이렇습니다.
이벤트는 브라우저에서 일어나는 사건이고, addEventListener()는 그 사건을 기다리는 방법입니다. click은 클릭했을 때, input은 입력할 때마다 반응합니다. 이벤트가 발생하면 함수가 실행되고, 그때 이벤트 객체를 통해 target, type, key 같은 정보를 확인할 수 있습니다. 그리고 링크 이동이나 폼 제출 같은 기본 동작을 막고 싶을 때는 preventDefault()를 사용합니다.234
결국 인터랙티브한 웹 페이지의 기본 공식은 아주 단순합니다.
요소를 선택한다.
이벤트를 등록한다.
이벤트가 발생하면 실행할 코드를 작성한다.
필요하면 DOM을 바꾸거나 기본 동작을 막는다.
이 공식을 이해하면 버튼 클릭, 입력 미리보기, 간단한 폼 검사 정도는 스스로 만들 수 있습니다.
다음 장으로 가기 전에
이제 여러분은 웹 페이지가 사용자의 행동에 반응하도록 만들 수 있습니다. 이것은 정말 큰 변화입니다. 이전 장에서 배운 DOM 조작이 "화면을 바꾸는 능력"이었다면, 이번 장의 이벤트는 "사용자의 행동에 맞춰 바꾸는 능력"입니다.
다음 장에서는 한 걸음 더 나아가, 바로 실행되지 않는 작업을 다루는 비동기, 서버에서 데이터를 가져오는 fetch, 데이터를 주고받을 때 자주 쓰는 JSON을 만나게 됩니다.
웹 페이지는 클릭하고, 입력하고, 제출하는 데서 끝나지 않습니다. 이제 그 행동을 바탕으로 바깥 세상과도 연결되기 시작합니다.
참고
2EventTarget: addEventListener() method - Web APIs | MDN
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.