icon

안동민 개발노트

5장 : 자바스크립트 기초

DOM 조작과 이벤트 처리 기초


우리는 지금까지 자바스크립트 기본 문법, 데이터 저장/조작, 흐름 제어를 학습했습니다. 이제는 이 지식을 바탕으로 웹 페이지와 직접 상호작용하는 단계로 넘어갑니다.

이를 가능하게 하는 핵심이 DOM(Document Object Model) 조작이벤트 처리입니다. 이번 장에서는 두 개념을 통해 정적 페이지에 동작과 반응을 추가하는 기본 흐름을 정리합니다.


DOM 조작: 웹 페이지의 요소 다루기

웹 브라우저가 HTML 문서를 로드하면, 그 문서는 객체 형태로 구조화되어 메모리에 저장됩니다. 이것이 바로 DOM(Document Object Model)입니다. DOM은 HTML 문서의 각 요소를 객체(노드)로 표현하고, 이 객체들을 트리(tree) 구조로 연결하여 구성됩니다. 자바스크립트는 이 DOM을 이용하여 HTML 요소의 내용, 스타일, 속성 등을 읽고 변경하며, 새로운 요소를 추가하거나 기존 요소를 삭제할 수 있습니다.

요소 선택하기: 조작의 첫걸음

어떤 HTML 요소를 조작하려면, 먼저 해당 요소를 자바스크립트 코드 내에서 선택해야 합니다. 요소를 선택하는 다양한 방법이 있습니다.

document.getElementById('id명'): id 속성 값으로 요소를 선택합니다. id는 문서 내에서 유일해야 합니다.

<h1 id="mainTitle">안녕하세요, DOM 조작!</h1>
// script.js (HTML 파일에 연결된 자바스크립트 파일)
const titleElement = document.getElementById('mainTitle');
console.log(titleElement); // <h1 id="mainTitle">...</h1> 요소 객체가 출력됩니다.

document.querySelector('CSS 선택자'): CSS 선택자와 동일한 방식으로 요소를 선택합니다. 조건에 맞는 첫 번째 요소를 반환합니다.

<p class="greeting">반갑습니다.</p>
<div id="container">
    <span class="text">첫 번째 텍스트</span>
    <span class="text">두 번째 텍스트</span>
</div>
const firstParagraph = document.querySelector('p');    // 첫 번째 <p> 태그
const greetingText = document.querySelector('.greeting'); // class가 greeting인 첫 번째 요소
const containerDiv = document.querySelector('#container'); // id가 container인 요소
const firstSpan = document.querySelector('#container .text'); // container 내부의 첫 번째 class="text" span

console.log(firstParagraph);
console.log(greetingText);
console.log(containerDiv);
console.log(firstSpan);

document.querySelectorAll('CSS 선택자'): CSS 선택자와 동일한 방식으로 요소를 선택합니다. 조건에 맞는 모든 요소를 NodeList 형태로 반환합니다. (배열과 유사하지만 완전히 같지는 않습니다. forEach 등을 사용할 수 있습니다.)

const allSpansInContainer = document.querySelectorAll('#container .text');
console.log(allSpansInContainer); // NodeList(2) [span.text, span.text]

allSpansInContainer.forEach(span => {
    console.log(span.textContent);
});
// 결과:
// 첫 번째 텍스트
// 두 번째 텍스트

요소 내용 조작하기

선택한 요소의 텍스트 내용이나 HTML 내용을 변경할 수 있습니다.

  • element.textContent: 요소 내부의 텍스트 콘텐츠를 가져오거나 설정합니다. HTML 태그는 순수한 텍스트로 처리됩니다.
  • element.innerHTML: 요소 내부의 HTML 콘텐츠를 가져오거나 설정합니다. HTML 태그가 포함된 문자열을 할당하면 브라우저가 이를 HTML로 파싱하여 렌더링합니다.
    <p id="myParagraph">원래 텍스트</p>
    <div id="myDiv"></div>
    const paragraph = document.getElementById('myParagraph');
    const myDiv = document.getElementById('myDiv');
    // textContent 변경
    paragraph.textContent = "새로운 텍스트입니다!";
    console.log(paragraph.textContent); // 결과: 새로운 텍스트입니다!
    // innerHTML 변경 (HTML 태그 포함)
    myDiv.innerHTML = "<h2>새로운 제목</h2><p>이것은 <b>HTML</b>입니다.</p>";
    innerHTML은 편리하지만, 사용자 입력을 그대로 innerHTML에 넣는 것은 보안상 취약점(XSS 공격)을 야기할 수 있으므로 주의해야 합니다. 순수한 텍스트만 변경할 때는 textContent를 사용하는 것이 안전합니다.

요소 속성(Attribute) 조작하기

HTML 요소의 속성(예: src, href, class, id 등)을 가져오거나 설정할 수 있습니다.

  • element.getAttribute('속성명'): 특정 속성의 값을 가져옵니다.
  • element.setAttribute('속성명', '값'): 특정 속성의 값을 설정합니다.
  • element.removeAttribute('속성명'): 특정 속성을 제거합니다.
    <img id="myImage" src="image1.jpg" alt="첫 번째 이미지">
    <a id="myLink" href="https://www.google.com">Google로 이동</a>
    const image = document.getElementById('myImage');
    const link = document.getElementById('myLink');
    // src 속성 값 가져오기
    console.log(image.getAttribute('src')); // 결과: image1.jpg
    // src 속성 값 변경
    image.setAttribute('src', 'image2.png');
    image.setAttribute('alt', '두 번째 이미지');
    // href 속성 값 변경
    link.setAttribute('href', 'https://www.naver.com');
    link.textContent = "Naver로 이동"; // 링크 텍스트도 변경
    // class 속성 추가/제거 (class는 특별히 classList 메서드를 주로 사용)
    // image.removeAttribute('alt'); // alt 속성 제거
클래스(Class) 조작: classList

요소의 class 속성은 스타일링에 매우 중요하며, 자바스크립트에서는 classList 속성을 통해 편리하게 조작할 수 있습니다.

  • element.classList.add('클래스명')
  • element.classList.remove('클래스명')
  • element.classList.toggle('클래스명') (있으면 제거, 없으면 추가)
  • element.classList.contains('클래스명') (해당 클래스가 있는지 확인, 불리언 반환)
    <button id="myButton" class="btn">클릭하세요</button>
    /* style.css */
    .btn {
        padding: 10px 20px;
        background-color: blue;
        color: white;
    }
    .active {
        background-color: green;
        font-weight: bold;
    }
    const button = document.getElementById('myButton');
    button.classList.add('active');    // 'active' 클래스 추가
    console.log(button.className);     // 결과: "btn active"
    button.classList.remove('btn');    // 'btn' 클래스 제거
    console.log(button.className);     // 결과: "active"
    button.classList.toggle('active'); // 'active' 클래스 제거
    console.log(button.className);     // 결과: ""
    button.classList.toggle('active'); // 'active' 클래스 다시 추가
    console.log(button.classList.contains('active')); // 결과: true

요소 스타일(CSS) 조작하기

자바스크립트로 직접 요소의 CSS 스타일을 변경할 수 있습니다. element.style.속성명 형식으로 접근합니다. CSS 속성 이름이 하이픈(-)으로 연결되어 있다면, 자바스크립트에서는 카멜 케이스(camelCase)로 변환하여 사용해야 합니다.

<p id="styledParagraph">이 문단은 스타일이 바뀔 것입니다.</p>
const styledParagraph = document.getElementById('styledParagraph');

styledParagraph.style.color = 'red';        // 글자색 변경
styledParagraph.style.fontSize = '20px';    // 글자 크기 변경
styledParagraph.style.backgroundColor = 'lightgray'; // 배경색 변경 (CSS: background-color)

하지만, 인라인 스타일로 직접 조작하는 것보다는 CSS 클래스를 토글하여 스타일을 변경하는 것이 더 효율적이고 유지보수가 용이합니다.

새로운 요소 생성 및 추가/제거하기

DOM API를 사용하여 완전히 새로운 HTML 요소를 생성하고, 문서에 추가하거나 제거할 수 있습니다.

  • document.createElement('태그명'): 새로운 HTML 요소를 생성합니다.
  • 부모요소.appendChild(자식요소): 부모 요소의 자식으로 요소를 맨 뒤에 추가합니다.
  • 부모요소.removeChild(자식요소): 부모 요소에서 특정 자식 요소를 제거합니다.
    <ul id="myList">
        <li>기존 아이템 1</li>
        <li>기존 아이템 2</li>
    </ul>
    const myList = document.getElementById('myList');
    // 새로운 li 요소 생성
    const newItem = document.createElement('li');
    newItem.textContent = "새로운 아이템 3";
    newItem.style.color = "purple"; // 생성된 요소에 스타일 적용
    // ul에 li 추가
    myList.appendChild(newItem);
    // 결과: <ul>...<li>새로운 아이템 3</li></ul>
    // 마지막 아이템 제거
    const lastChild = myList.lastElementChild; // 마지막 자식 요소 선택
    if (lastChild) {
        myList.removeChild(lastChild);
    }
    // 결과: <ul><li>기존 아이템 1</li><li>기존 아이템 2</li></ul> (새로운 아이템 3은 사라짐)

이벤트 처리: 사용자 상호작용에 반응하기

이벤트(Event)는 웹 페이지에서 발생하는 모든 종류의 사건을 의미합니다. 예를 들어, 사용자가 버튼을 클릭하는 것, 키보드를 누르는 것, 마우스를 움직이는 것, 페이지 로딩이 완료되는 것 등 모든 것이 이벤트입니다. 이벤트 처리(Event Handling)는 이러한 이벤트가 발생했을 때 특정 자바스크립트 코드를 실행하도록 하는 메커니즘입니다.

이벤트 리스너 등록하기

요소에 이벤트를 감지하고 처리하는 함수(이벤트 핸들러)를 연결하는 가장 일반적이고 권장되는 방법은 addEventListener() 메서드를 사용하는 것입니다.

// element.addEventListener('이벤트_타입', 함수);
  • 이벤트_타입: 발생할 이벤트의 종류를 나타내는 문자열입니다. (예: 'click', 'mouseover', 'keydown', 'submit', 'load')
  • 함수: 이벤트가 발생했을 때 실행될 코드 블록을 포함하는 함수(이벤트 핸들러)입니다.
    <button id="clickMeBtn">여기를 클릭하세요</button>
    <input type="text" id="myInput" placeholder="여기에 입력하세요">
    const clickButton = document.getElementById('clickMeBtn');
    const myInput = document.getElementById('myInput');
    // 1. 클릭 이벤트 (click)
    clickButton.addEventListener('click', function() {
        alert("버튼이 클릭되었습니다!");
    });
    // 2. 입력 이벤트 (input)
    myInput.addEventListener('input', function() {
        console.log("현재 입력 값:", myInput.value);
    });
    // 3. 마우스 오버 이벤트 (mouseover)
    clickButton.addEventListener('mouseover', function() {
        this.style.backgroundColor = 'lightgreen'; // this는 이벤트가 발생한 요소를 가리킵니다.
    });
    // 4. 마우스 아웃 이벤트 (mouseout)
    clickButton.addEventListener('mouseout', function() {
        this.style.backgroundColor = ''; // 원래대로 (또는 특정 색상)
    });
이벤트 객체 (Event Object)

이벤트 핸들러 함수는 종종 event 객체(관례적으로 eevent로 명명)를 인자로 받습니다. 이 event 객체는 발생한 이벤트에 대한 자세한 정보를 담고 있습니다.

myInput.addEventListener('keydown', function(e) {
    console.log("키가 눌렸습니다. 눌린 키:", e.key); // 눌린 키 문자열
    console.log("키 코드:", e.keyCode); // 눌린 키의 숫자 코드 (구식)
    if (e.key === 'Enter') {
        alert("Enter 키를 누르셨군요!");
    }
});

// 링크 기본 동작 방지 예시
const preventLink = document.getElementById('myLink');
preventLink.addEventListener('click', function(e) {
    e.preventDefault(); // 링크의 기본 동작(페이지 이동)을 막습니다.
    console.log("링크 클릭! 하지만 페이지 이동은 막았습니다.");
});
  • e.target: 이벤트가 실제로 발생한 요소를 가리킵니다.
  • e.preventDefault(): 특정 이벤트의 기본 동작(예: 링크 클릭 시 페이지 이동, 폼 제출 시 새로고침)을 막습니다.
  • e.stopPropagation(): 이벤트 버블링(이벤트가 상위 요소로 전파되는 현상)을 중단합니다. (고급 주제)

이벤트 리스너 제거하기

removeEventListener() 메서드를 사용하여 등록했던 이벤트 리스너를 제거할 수 있습니다. 이는 특히 메모리 누수를 방지하거나, 특정 조건에서만 이벤트를 처리하고 싶을 때 유용합니다. addEventListener()에 전달했던 것과 동일한 함수 참조를 사용해야 합니다.

const onceButton = document.getElementById('clickMeBtn');

function clickHandler() {
    alert("한 번만 실행됩니다!");
    onceButton.removeEventListener('click', clickHandler); // 함수 실행 후 리스너 제거
}

onceButton.addEventListener('click', clickHandler);

자주 사용되는 이벤트 타입

몇 가지 일반적인 이벤트 타입을 정리해드립니다.

  • 마우스 이벤트: click, dblclick, mousedown, mouseup, mouseover, mouseout, mousemove
  • 키보드 이벤트: keydown, keyup, keypress
  • 폼 이벤트: submit, focus, blur, change, input
  • 문서/창 이벤트: load (페이지 로드 완료), DOMContentLoaded (DOM 트리 구성 완료), resize, scroll

반복 실전 점검

이번 장에서는 자바스크립트로 웹 페이지에 동적인 생명력을 불어넣는 핵심 기술인 DOM 조작과 이벤트 처리에 대해 학습했습니다.

DOM 조작을 통해 여러분은 웹 페이지의 특정 요소를 선택하고, 그 내용(textContent, innerHTML), 속성(setAttribute, classList), 스타일(style)을 자유롭게 변경하는 방법을 익혔습니다. 또한, 새로운 요소를 생성하고 추가하거나 제거하는 능력도 갖추게 되었습니다.

이벤트 처리를 통해 사용자의 상호작용(클릭, 입력 등)에 반응하여 특정 자바스크립트 코드를 실행하는 방법을 배웠습니다. addEventListener()를 사용하여 이벤트 리스너를 등록하고, event 객체를 통해 이벤트에 대한 상세 정보를 얻는 방법을 이해했습니다.

이 두 가지 개념은 프론트엔드 웹 개발의 심장과 같습니다. 여러분이 배운 지식을 바탕으로 이제 정적인 HTML 페이지를 넘어, 사용자와 소통하고 변화하는 다이내믹한 웹 페이지를 만들 수 있게 되었습니다. 다양한 예제를 직접 코딩해보면서 DOM 조작과 이벤트 처리의 원리를 완전히 자기 것으로 만드시길 강력히 권합니다.

목차