실전 DOM 조작 예제

2025. 3. 30. 22:40Web Development/JavaScript

실전 DOM 조작 예제

여기서는 자주 사용되는 DOM 조작 패턴들의 실전 예제를 살펴보겠습니다.

동적 목록 관리

사용자가 항목을 추가하고 삭제할 수 있는 간단한 할 일 목록 예제입니다.

// HTML 구조:
// <div id="todo-app">
//   <input id="todo-input" type="text" placeholder="할 일 입력">
//   <button id="add-button">추가</button>
//   <ul id="todo-list"></ul>
// </div>

// 할 일 목록 관리 기능
const todoInput = document.querySelector('#todo-input');
const addButton = document.querySelector('#add-button');
const todoList = document.querySelector('#todo-list');

// 할 일 추가 함수
function addTodo() {
  const text = todoInput.value.trim();
  if (text === '') return; // 빈 입력 방지
  
  // 새 할 일 항목 생성
  const li = document.createElement('li');
  li.innerHTML = `
    <span class="todo-text">${text}</span>
    <button class="delete-button">삭제</button>
    <button class="complete-button">완료</button>
  `;
  
  // 목록에 항목 추가
  todoList.appendChild(li);
  
  // 입력 필드 초기화
  todoInput.value = '';
  todoInput.focus();
}

// 추가 버튼 클릭 이벤트
addButton.addEventListener('click', addTodo);

// 엔터 키로 추가
todoInput.addEventListener('keypress', (e) => {
  if (e.key === 'Enter') {
    addTodo();
  }
});

// 이벤트 위임을 사용한 항목 관리
todoList.addEventListener('click', (e) => {
  const target = e.target;
  
  // 삭제 버튼 클릭
  if (target.classList.contains('delete-button')) {
    const li = target.parentElement;
    li.remove();
  }
  
  // 완료 버튼 클릭
  if (target.classList.contains('complete-button')) {
    const li = target.parentElement;
    const todoText = li.querySelector('.todo-text');
    todoText.classList.toggle('completed');
    
    // 버튼 텍스트 변경
    if (todoText.classList.contains('completed')) {
      target.textContent = '취소';
    } else {
      target.textContent = '완료';
    }
  }
});

// CSS (참고용):
// .completed { text-decoration: line-through; color: #888; }

탭 인터페이스 구현

사용자가 다른 내용 패널 사이를 전환할 수 있는 탭 인터페이스 예제입니다.

// HTML 구조:
// <div class="tab-container">
//   <div class="tab-buttons">
//     <button class="tab-button active" data-tab="tab1">탭 1</button>
//     <button class="tab-button" data-tab="tab2">탭 2</button>
//     <button class="tab-button" data-tab="tab3">탭 3</button>
//   </div>
//   <div class="tab-content">
//     <div class="tab-panel active" id="tab1">탭 1 내용...</div>
//     <div class="tab-panel" id="tab2">탭 2 내용...</div>
//     <div class="tab-panel" id="tab3">탭 3 내용...</div>
//   </div>
// </div>

// 탭 기능 구현
document.querySelector('.tab-buttons').addEventListener('click', (e) => {
  // 클릭된 요소가 탭 버튼인지 확인
  if (e.target.classList.contains('tab-button')) {
    // 모든 탭 버튼에서 active 클래스 제거
    document.querySelectorAll('.tab-button').forEach(button => {
      button.classList.remove('active');
    });
    
    // 클릭된 탭 버튼에 active 클래스 추가
    e.target.classList.add('active');
    
    // 탭 ID 가져오기
    const tabId = e.target.dataset.tab;
    
    // 모든 탭 패널 숨기기
    document.querySelectorAll('.tab-panel').forEach(panel => {
      panel.classList.remove('active');
    });
    
    // 선택된 탭 패널 표시
    document.getElementById(tabId).classList.add('active');
  }
});

// CSS (참고용):
// .tab-panel { display: none; }
// .tab-panel.active { display: block; }
// .tab-button.active { background-color: #eee; font-weight: bold; }

폼 유효성 검사

사용자 입력 데이터의 유효성을 검사하는 예제입니다.

// HTML 구조:
// <form id="signup-form">
//   <div class="form-group">
//     <label for="username">사용자명:</label>
//     <input type="text" id="username" name="username" required>
//     <span class="error-message"></span>
//   </div>
//   <div class="form-group">
//     <label for="email">이메일:</label>
//     <input type="email" id="email" name="email" required>
//     <span class="error-message"></span>
//   </div>
//   <div class="form-group">
//     <label for="password">비밀번호:</label>
//     <input type="password" id="password" name="password" required>
//     <span class="error-message"></span>
//   </div>
//   <div class="form-group">
//     <label for="confirm-password">비밀번호 확인:</label>
//     <input type="password" id="confirm-password" name="confirmPassword" required>
//     <span class="error-message"></span>
//   </div>
//   <button type="submit">가입하기</button>
// </form>

// 폼 유효성 검사 구현
const form = document.querySelector('#signup-form');
const usernameInput = document.querySelector('#username');
const emailInput = document.querySelector('#email');
const passwordInput = document.querySelector('#password');
const confirmPasswordInput = document.querySelector('#confirm-password');

// 오류 메시지 표시 함수
function showError(input, message) {
  const formGroup = input.parentElement;
  const errorMessage = formGroup.querySelector('.error-message');
  formGroup.classList.add('error');
  errorMessage.textContent = message;
}

// 성공 상태 표시 함수
function showSuccess(input) {
  const formGroup = input.parentElement;
  formGroup.classList.remove('error');
  formGroup.classList.add('success');
  const errorMessage = formGroup.querySelector('.error-message');
  errorMessage.textContent = '';
}

// 이메일 형식 검사 함수
function isValidEmail(email) {
  const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(String(email).toLowerCase());
}

// 입력 필드 검사 함수
function checkInput(input, message) {
  if (input.value.trim() === '') {
    showError(input, message);
    return false;
  } else {
    showSuccess(input);
    return true;
  }
}

// 실시간 유효성 검사
usernameInput.addEventListener('input', () => {
  if (usernameInput.value.length < 3) {
    showError(usernameInput, '사용자명은 3자 이상이어야 합니다.');
  } else {
    showSuccess(usernameInput);
  }
});

emailInput.addEventListener('input', () => {
  if (!isValidEmail(emailInput.value)) {
    showError(emailInput, '유효한 이메일 주소를 입력하세요.');
  } else {
    showSuccess(emailInput);
  }
});

passwordInput.addEventListener('input', () => {
  if (passwordInput.value.length < 6) {
    showError(passwordInput, '비밀번호는 6자 이상이어야 합니다.');
  } else {
    showSuccess(passwordInput);
  }
});

confirmPasswordInput.addEventListener('input', () => {
  if (confirmPasswordInput.value !== passwordInput.value) {
    showError(confirmPasswordInput, '비밀번호가 일치하지 않습니다.');
  } else {
    showSuccess(confirmPasswordInput);
  }
});

// 폼 제출 이벤트
form.addEventListener('submit', (e) => {
  e.preventDefault(); // 기본 제출 동작 중지
  
  // 모든 입력 필드 검사
  const isUsernameValid = checkInput(usernameInput, '사용자명을 입력하세요.');
  const isEmailValid = checkInput(emailInput, '이메일을 입력하세요.');
  const isPasswordValid = checkInput(passwordInput, '비밀번호를 입력하세요.');
  const isConfirmPasswordValid = checkInput(confirmPasswordInput, '비밀번호 확인을 입력하세요.');
  
  // 추가 검사
  const isEmailFormatValid = isEmailValid && isValidEmail(emailInput.value);
  if (isEmailValid && !isEmailFormatValid) {
    showError(emailInput, '유효한 이메일 주소를 입력하세요.');
  }
  
  const isPasswordMatch = passwordInput.value === confirmPasswordInput.value;
  if (isPasswordValid && isConfirmPasswordValid && !isPasswordMatch) {
    showError(confirmPasswordInput, '비밀번호가 일치하지 않습니다.');
  }
  
  // 모든 검사를 통과하면 폼 제출
  if (isUsernameValid && isEmailFormatValid && isPasswordValid && isConfirmPasswordValid && isPasswordMatch) {
    console.log('폼 제출 성공!');
    
    // 서버에 데이터 전송하는 코드
    // form.submit();
  }
});

'Web Development > JavaScript' 카테고리의 다른 글

콜백 함수  (0) 2025.03.30
비동기 프로그래밍  (0) 2025.03.30
이벤트 처리  (0) 2025.03.30
요소 선택과 조작  (0) 2025.03.30
DOM 조작  (0) 2025.03.30