JavaScript/DOM 조작

JavaScript DOM 요소 선택 - getElementById, querySelector 완전 가이드

코딩하는 패션이과생 2025. 6. 24. 22:21
반응형

DOM 요소 선택이란?

DOM 요소 선택은 HTML 문서에서 특정 요소를 JavaScript로 가져오는 과정입니다. 요소를 선택해야 내용을 변경하거나 이벤트를 추가할 수 있습니다.

🔍 기본 HTML 예제

<div id="header" class="main-header">
  <h1 class="title">제목</h1>
  <nav>
    <ul class="menu">
      <li><a href="#home">홈</a></li>
      <li><a href="#about">소개</a></li>
    </ul>
  </nav>
</div>
<p class="description">설명문</p>

이 HTML에서 다양한 방법으로 요소를 선택할 수 있습니다.


getElementById - ID로 선택

getElementById()는 ID 속성으로 하나의 요소를 선택하는 가장 기본적이고 빠른 방법입니다.

기본 문법

// 문법
document.getElementById('아이디명')

// 사용 예제
let header = document.getElementById('header');
console.log(header); // <div id="header" class="main-header">...</div>

특징과 활용

// ID는 문서에서 유일해야 함
let headerElement = document.getElementById('header');

if (headerElement) {
    // 요소가 존재할 때만 조작
    headerElement.style.backgroundColor = 'lightblue';
    headerElement.textContent = '새로운 헤더';
}

// 존재하지 않는 ID
let nonExistent = document.getElementById('not-exist');
console.log(nonExistent); // null

실행 결과:

<div id="header" class="main-header">...</div>
null

장점과 단점

장점:

  • 가장 빠른 선택 방법
  • 간단하고 직관적
  • 모든 브라우저 지원

단점:

  • ID로만 선택 가능
  • 하나의 요소만 반환
  • 복잡한 선택 불가능

querySelector/querySelectorAll - CSS 선택자

querySelector()querySelectorAll()CSS 선택자를 사용해 요소를 선택하는 강력하고 유연한 방법입니다.

querySelector - 첫 번째 요소만 선택

// 클래스 선택
let title = document.querySelector('.title');

// ID 선택 (getElementById와 동일한 결과)
let header = document.querySelector('#header');

// 태그 선택
let firstParagraph = document.querySelector('p');

// 복합 선택자
let firstMenuItem = document.querySelector('.menu li');

// 속성 선택자
let homeLink = document.querySelector('a[href="#home"]');

console.log(title);         // <h1 class="title">제목</h1>
console.log(firstMenuItem); // <li><a href="#home">홈</a></li>

querySelectorAll - 모든 일치 요소 선택

// 모든 li 요소 선택
let allMenuItems = document.querySelectorAll('.menu li');
console.log(allMenuItems.length); // 2

// NodeList를 배열처럼 사용
allMenuItems.forEach((item, index) => {
    console.log(`${index + 1}번째 메뉴:`, item.textContent);
});

// 모든 a 태그 선택
let allLinks = document.querySelectorAll('a');
for (let link of allLinks) {
    console.log('링크:', link.href);
}

실행 결과:

<h1 class="title">제목</h1>
<li><a href="#home">홈</a></li>
2
1번째 메뉴: 홈
2번째 메뉴: 소개
링크: #home
링크: #about

다양한 CSS 선택자 활용

// 자식 선택자
let directChild = document.querySelector('nav > ul');

// 인접 형제 선택자
let nextElement = document.querySelector('h1 + nav');

// 속성 선택자
let externalLinks = document.querySelectorAll('a[href^="http"]');

// 가상 선택자
let firstChild = document.querySelector('li:first-child');
let lastChild = document.querySelector('li:last-child');

// 복잡한 선택자
let specificLink = document.querySelector('.menu li:nth-child(2) a');

기타 선택 메서드

DOM에는 다른 선택 메서드들도 있지만, 현재는 잘 사용되지 않습니다.

getElementsByClassName

// 클래스로 선택 (HTMLCollection 반환)
let titles = document.getElementsByClassName('title');
console.log(titles[0]); // 첫 번째 요소

// querySelector와 비교
let titleQuery = document.querySelector('.title');      // 하나만
let titlesQuery = document.querySelectorAll('.title');  // NodeList

getElementsByTagName

// 태그로 선택
let allParagraphs = document.getElementsByTagName('p');
let allDivs = document.getElementsByTagName('div');

// 특정 요소 내에서 선택
let menuItems = document.getElementById('header')
                        .getElementsByTagName('li');

HTMLCollection vs NodeList

// HTMLCollection (살아있는 컬렉션)
let liveCollection = document.getElementsByClassName('menu');

// NodeList (정적 컬렉션)
let staticList = document.querySelectorAll('.menu');

// 차이점 확인
console.log('Live:', liveCollection.length);   // 1
console.log('Static:', staticList.length);     // 1

// 새 요소 추가 후
document.body.innerHTML += '<div class="menu">새 메뉴</div>';

console.log('Live:', liveCollection.length);   // 2 (자동 업데이트)
console.log('Static:', staticList.length);     // 1 (변경 없음)

성능 비교 및 선택 기준

📊 성능 순서 (빠른 순)

  1. getElementById ⚡ (가장 빠름)
  2. getElementsByClassName
  3. getElementsByTagName
  4. querySelector
  5. querySelectorAll (가장 느림)

🎯 언제 어떤 것을 사용할까?

getElementById 사용 시기

// ✅ ID가 있고 하나의 요소만 필요할 때
let loginButton = document.getElementById('login-btn');
let mainContent = document.getElementById('main-content');

querySelector 사용 시기

// ✅ CSS 선택자가 필요할 때
let firstActiveTab = document.querySelector('.tab.active');
let submitButton = document.querySelector('form button[type="submit"]');

// ✅ 복잡한 선택이 필요할 때
let errorMessage = document.querySelector('.form-group.error .message');

querySelectorAll 사용 시기

// ✅ 여러 요소를 처리해야 할 때
let allButtons = document.querySelectorAll('button');
let formInputs = document.querySelectorAll('input, textarea, select');

allButtons.forEach(button => {
    button.addEventListener('click', handleClick);
});

실무 활용 패턴

1. 안전한 요소 선택

// 요소 존재 확인 후 조작
function safeElementUpdate(selector, callback) {
    let element = document.querySelector(selector);
    if (element && typeof callback === 'function') {
        callback(element);
    }
}

// 사용 예제
safeElementUpdate('#status', (element) => {
    element.textContent = '로딩 완료';
    element.classList.add('success');
});

2. 여러 요소 일괄 처리

// 모든 버튼에 이벤트 추가
function setupButtons() {
    let buttons = document.querySelectorAll('.action-btn');

    buttons.forEach(button => {
        button.addEventListener('click', (e) => {
            let action = e.target.dataset.action;
            console.log(`${action} 버튼 클릭됨`);
        });
    });
}

// 폼 입력 필드 초기화
function clearForm(formSelector) {
    let inputs = document.querySelectorAll(`${formSelector} input, ${formSelector} textarea`);
    inputs.forEach(input => input.value = '');
}

clearForm('#contact-form');

3. 동적 요소 선택

// 데이터 속성으로 선택
function updateStatus(userId, status) {
    let userElement = document.querySelector(`[data-user-id="${userId}"]`);
    if (userElement) {
        userElement.querySelector('.status').textContent = status;
    }
}

// 조건부 스타일 적용
function highlightErrors() {
    let invalidInputs = document.querySelectorAll('input:invalid');
    let validInputs = document.querySelectorAll('input:valid');

    invalidInputs.forEach(input => input.classList.add('error'));
    validInputs.forEach(input => input.classList.remove('error'));
}

4. 성능 최적화 패턴

// 한 번 선택해서 재사용
class ComponentManager {
    constructor() {
        this.elements = {
            header: document.getElementById('header'),
            nav: document.querySelector('nav'),
            content: document.getElementById('content'),
            footer: document.querySelector('footer')
        };
    }

    updateHeader(title) {
        if (this.elements.header) {
            this.elements.header.querySelector('h1').textContent = title;
        }
    }

    showContent(html) {
        if (this.elements.content) {
            this.elements.content.innerHTML = html;
        }
    }
}

let pageManager = new ComponentManager();

5. 이벤트 위임 패턴

// 부모 요소에서 이벤트 처리 (성능 향상)
document.getElementById('todo-list').addEventListener('click', (e) => {
    if (e.target.classList.contains('delete-btn')) {
        // 삭제 버튼 클릭
        e.target.closest('li').remove();
    } else if (e.target.classList.contains('edit-btn')) {
        // 수정 버튼 클릭
        let li = e.target.closest('li');
        editTodoItem(li);
    }
});

마무리

DOM 요소 선택은 JavaScript 웹 개발의 첫 번째 단계입니다. 올바른 선택 방법을 사용하면 효율적이고 안정적인 웹 애플리케이션을 만들 수 있습니다.