프로젝트 소개 및 목표
🔗 관련 에러 해결 가이드
이 30분만에 만드는 Todo App 완성 가이드는 웹 개발 초보자부터 중급자까지 누구나 따라할 수 있는 실전 프로젝트입니다. 바닐라 JavaScript와 HTML, CSS만으로 완전히 동작하는 할 일 관리 애플리케이션을 만들어봅니다. 이 가이드를 통해 DOM 조작, 이벤트 핸들링, 로컬 스토리지 활용 등 실무에서 필수적인 기술들을 익힐 수 있습니다. 완성된 프로젝트는 포트폴리오에 바로 추가할 수 있으며, 확장 가능한 구조로 설계되어 있어 추가 기능을 자유롭게 구현할 수 있습니다.
필요한 기술 스택
이 프로젝트는 별도의 프레임워크 없이 순수 웹 기술만 사용합니다:
- HTML5: 시맨틱 마크업으로 구조 작성
- CSS3: Flexbox를 활용한 반응형 디자인
- JavaScript (ES6+): 할 일 추가, 삭제, 완료 기능 구현
- LocalStorage API: 데이터 영구 저장
- 코드 에디터: VS Code 권장
- 웹 브라우저: Chrome, Firefox 등 모던 브라우저
프로젝트 셋업
먼저 프로젝트 폴더를 생성하고 기본 파일 구조를 만듭니다:
mkdir todo-app
cd todo-app
touch index.html style.css app.js
프로젝트 구조는 다음과 같습니다:
todo-app/
├── index.html
├── style.css
└── app.js
이 간단한 구조로 시작하여 모든 기능을 구현할 수 있습니다. 별도의 빌드 도구나 패키지 매니저가 필요 없어 즉시 개발을 시작할 수 있습니다. VS Code에서 Live Server 확장을 설치하면 실시간으로 변경사항을 확인할 수 있습니다.
단계별 구현 과정
Step 1: HTML 구조 작성
index.html 파일에 기본 구조를 작성합니다:
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>30분 Todo App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>📝 나의 할 일 목록</h1>
<div class="input-section">
<input type="text" id="todoInput" placeholder="할 일을 입력하세요...">
<button id="addBtn">추가</button>
</div>
<div class="filter-section">
<button class="filter-btn active" data-filter="all">전체</button>
<button class="filter-btn" data-filter="active">진행중</button>
<button class="filter-btn" data-filter="completed">완료</button>
</div>
<ul id="todoList"></ul>
<div class="stats">
<span>전체: <span id="totalCount">0</span></span>
<span>완료: <span id="completedCount">0</span></span>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
Step 2: CSS 스타일링
style.css에 깔끔한 디자인을 적용합니다:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.container {
background: white;
border-radius: 15px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
padding: 30px;
width: 100%;
max-width: 500px;
}
h1 {
color: #333;
text-align: center;
margin-bottom: 25px;
}
.input-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#todoInput {
flex: 1;
padding: 12px 15px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.3s;
}
#todoInput:focus {
outline: none;
border-color: #667eea;
}
#addBtn {
padding: 12px 25px;
background: #667eea;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: background 0.3s;
}
#addBtn:hover {
background: #5568d3;
}
.filter-section {
display: flex;
gap: 10px;
margin-bottom: 20px;
justify-content: center;
}
.filter-btn {
padding: 8px 16px;
background: #f5f5f5;
border: 2px solid transparent;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.filter-btn.active {
background: #667eea;
color: white;
}
#todoList {
list-style: none;
margin-bottom: 20px;
}
.todo-item {
display: flex;
align-items: center;
padding: 15px;
background: #f9f9f9;
border-radius: 8px;
margin-bottom: 10px;
transition: all 0.3s;
}
.todo-item:hover {
transform: translateX(5px);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.todo-item.completed {
opacity: 0.6;
}
.todo-item.completed .todo-text {
text-decoration: line-through;
}
.todo-item input[type="checkbox"] {
margin-right: 12px;
width: 20px;
height: 20px;
cursor: pointer;
}
.todo-text {
flex: 1;
font-size: 16px;
color: #333;
}
.delete-btn {
background: #ff6b6b;
color: white;
border: none;
padding: 6px 12px;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}
.delete-btn:hover {
background: #ee5a52;
}
.stats {
display: flex;
justify-content: space-around;
padding: 15px;
background: #f5f5f5;
border-radius: 8px;
font-weight: bold;
color: #666;
}
Step 3: JavaScript 기능 구현
이제 30분만에 만드는 Todo App 완성 가이드의 핵심인 JavaScript 기능을 구현합니다. app.js에 다음 코드를 작성하세요:
// DOM 요소 선택
const todoInput = document.getElementById('todoInput');
const addBtn = document.getElementById('addBtn');
const todoList = document.getElementById('todoList');
const filterBtns = document.querySelectorAll('.filter-btn');
const totalCount = document.getElementById('totalCount');
const completedCount = document.getElementById('completedCount');
// 전역 변수
let todos = [];
let currentFilter = 'all';
// LocalStorage에서 데이터 로드
function loadTodos() {
const savedTodos = localStorage.getItem('todos');
if (savedTodos) {
todos = JSON.parse(savedTodos);
renderTodos();
}
}
// LocalStorage에 데이터 저장
function saveTodos() {
localStorage.setItem('todos', JSON.stringify(todos));
}
// 할 일 추가
function addTodo() {
const text = todoInput.value.trim();
if (text === '') {
alert('할 일을 입력해주세요!');
return;
}
const newTodo = {
id: Date.now(),
text: text,
completed: false,
createdAt: new Date().toISOString()
};
todos.push(newTodo);
todoInput.value = '';
saveTodos();
renderTodos();
}
// 할 일 삭제
function deleteTodo(id) {
todos = todos.filter(todo => todo.id !== id);
saveTodos();
renderTodos();
}
// 할 일 완료/미완료 토글
function toggleTodo(id) {
todos = todos.map(todo => {
if (todo.id === id) {
return { ...todo, completed: !todo.completed };
}
return todo;
});
saveTodos();
renderTodos();
}
// 필터링된 할 일 목록 반환
function getFilteredTodos() {
switch (currentFilter) {
case 'active':
return todos.filter(todo => !todo.completed);
case 'completed':
return todos.filter(todo => todo.completed);
default:
return todos;
}
}
// 화면에 할 일 렌더링
function renderTodos() {
const filteredTodos = getFilteredTodos();
todoList.innerHTML = '';
if (filteredTodos.length === 0) {
todoList.innerHTML = '할 일이 없습니다. ';
} else {
filteredTodos.forEach(todo => {
const li = document.createElement('li');
li.className = `todo-item ${todo.completed ? 'completed' : ''}`;
li.innerHTML = `
${todo.text}
`;
todoList.appendChild(li);
});
}
updateStats();
}
// 통계 업데이트
function updateStats() {
totalCount.textContent = todos.length;
completedCount.textContent = todos.filter(todo => todo.completed).length;
}
// 이벤트 리스너
addBtn.addEventListener('click', addTodo);
todoInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
addTodo();
}
});
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
filterBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilter = btn.dataset.filter;
renderTodos();
});
});
// 초기 로드
loadTodos();
이 코드는 할 일 추가, 삭제, 완료 표시, 필터링, 통계 표시 등 모든 핵심 기능을 포함합니다. LocalStorage를 사용하여 브라우저를 닫아도 데이터가 유지됩니다.
테스트 및 배포
로컬 테스트
VS Code에서 Live Server를 실행하거나 index.html 파일을 브라우저에서 직접 열어 테스트합니다. 다음 항목을 확인하세요:
- ✅ 할 일 추가 기능 (Enter 키 및 버튼 클릭)
- ✅ 체크박스로 완료 표시
- ✅ 삭제 버튼 동작
- ✅ 필터 버튼 (전체/진행중/완료)
- ✅ 통계 정보 업데이트
- ✅ 페이지 새로고침 후 데이터 유지
배포 방법
완성된 프로젝트는 다음 플랫폼에 무료로 배포할 수 있습니다:
# GitHub Pages
git init
git add .
git commit -m "Initial commit: Todo App"
git branch -M main
git remote add origin [your-repo-url]
git push -u origin main
또는 Netlify, Vercel에 드래그 앤 드롭으로 즉시 배포 가능합니다. 정적 파일만 사용하므로 별도의 서버 설정이 필요 없습니다.
마무리 및 확장 아이디어
축하합니다! 30분만에 만드는 Todo App 완성 가이드를 따라 완전히 동작하는 할 일 관리 앱을 완성했습니다. 이제 다음과 같은 기능을 추가하여 더욱 발전시킬 수 있습니다:
- 🎨 다크모드 테마 전환
- 🔍 할 일 검색 기능
- 📅 마감일 설정 및 알림
- 🏷️ 카테고리/태그 시스템
- 📱 PWA로 변환하여 모바일 앱처럼 사용
- ☁️ Firebase 연동으로 클라우드 동기화
- ✨ 드래그 앤 드롭으로 순서 변경
- 📊 생산성 통계 및 차트
이 프로젝트는 포트폴리오에 추가하기 좋으며, 실무에서 사용하는 JavaScript 패턴과 웹 API를 모두 경험할 수 있습니다. 코드를 자유롭게 수정하고 확장하여 나만의 독특한 Todo 앱을 만들어보세요!
📚 함께 읽으면 좋은 글
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 15.
🎯 30분만에 만드는 Todo App 완성 가이드
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 10.
🎯 30분만에 만드는 Todo App 완성 가이드
30분만에 만드는 Todo App 완성 가이드 – 완성까지 한번에!
📅 2025. 10. 5.
🎯 30분만에 만드는 Todo App 완성 가이드
REST API 서버 구축 단계별 튜토리얼 – 완성까지 한번에!
📅 2025. 10. 19.
🎯 REST API 서버 구축 단계별 튜토리얼
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 10. 18.
🎯 실시간 채팅 앱 만들기 with Socket.io
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
여러분은 30분만에 만드는 Todo App 완성 가이드에 대해 어떻게 생각하시나요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!