JavaScript实战①|从零开发待办清单应用,巩固所学知识
·
author: 专注前端开发,分享JavaScript干货
title: JavaScript实战①|从零开发待办清单应用,巩固所学知识
update: 2026-04-28
tags: JavaScript,实战项目,待办清单,TodoApp,DOM操作,本地存储
作者:专注前端开发,分享JavaScript干货
更新时间:2026年4月
适合人群:学完本专栏基础内容,想通过实战巩固的开发者
前言:为什么做这个项目?
待办清单(Todo App)是前端入门的经典项目,涵盖:
- DOM 操作(增删改查)
- 事件处理
- 本地存储(LocalStorage)
- ES6+ 语法
做完这个项目,你的JS基础就扎实了。
一、项目功能规划
- ✅ 添加待办事项
- ✅ 标记完成/未完成
- ✅ 删除待办事项
- ✅ 筛选(全部/未完成/已完成)
- ✅ 本地存储(刷新不丢失)
- ✅ 统计待办数量
二、HTML 结构
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>待办清单</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 50px 20px;
}
.container {
max-width: 500px;
margin: 0 auto;
background: white;
border-radius: 16px;
padding: 30px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
.input-group {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#todoInput {
flex: 1;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 16px;
outline: none;
transition: border-color 0.3s;
}
#todoInput:focus {
border-color: #667eea;
}
#addBtn {
padding: 12px 24px;
background: #667eea;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
transition: background 0.3s;
}
#addBtn:hover {
background: #5a67d8;
}
.filters {
display: flex;
gap: 10px;
margin-bottom: 20px;
justify-content: center;
}
.filter-btn {
padding: 8px 16px;
border: 1px solid #e0e0e0;
background: white;
border-radius: 20px;
cursor: pointer;
transition: all 0.3s;
}
.filter-btn.active {
background: #667eea;
color: white;
border-color: #667eea;
}
.todo-list {
list-style: none;
}
.todo-item {
display: flex;
align-items: center;
padding: 15px;
border-bottom: 1px solid #f0f0f0;
transition: background 0.3s;
}
.todo-item:hover {
background: #f8f9fa;
}
.todo-item.completed .todo-text {
text-decoration: line-through;
color: #999;
}
.todo-checkbox {
width: 20px;
height: 20px;
margin-right: 15px;
cursor: pointer;
}
.todo-text {
flex: 1;
font-size: 16px;
}
.delete-btn {
padding: 6px 12px;
background: #ff4757;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.delete-btn:hover {
background: #ff3838;
}
.stats {
text-align: center;
margin-top: 20px;
color: #666;
}
.empty-state {
text-align: center;
padding: 40px;
color: #999;
}
</style>
</head>
<body>
<div class="container">
<h1>📝 待办清单</h1>
<div class="input-group">
<input type="text" id="todoInput" placeholder="添加新的待办事项...">
<button id="addBtn">添加</button>
</div>
<div class="filters">
<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 class="todo-list" id="todoList"></ul>
<div class="stats" id="stats"></div>
</div>
<script src="app.js"></script>
</body>
</html>
三、JavaScript 实现(app.js)
// 待办事项管理类
class TodoApp {
constructor() {
this.todos = JSON.parse(localStorage.getItem('todos')) || [];
this.filter = 'all';
this.todoInput = document.getElementById('todoInput');
this.addBtn = document.getElementById('addBtn');
this.todoList = document.getElementById('todoList');
this.stats = document.getElementById('stats');
this.filterBtns = document.querySelectorAll('.filter-btn');
this.init();
}
init() {
this.bindEvents();
this.render();
}
bindEvents() {
// 添加按钮点击
this.addBtn.addEventListener('click', () => this.addTodo());
// 回车键添加
this.todoInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') this.addTodo();
});
// 筛选按钮
this.filterBtns.forEach(btn => {
btn.addEventListener('click', (e) => {
this.filterBtns.forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
this.filter = e.target.dataset.filter;
this.render();
});
});
}
addTodo() {
const text = this.todoInput.value.trim();
if (!text) {
alert('请输入待办事项');
return;
}
const todo = {
id: Date.now(),
text: text,
completed: false,
createdAt: new Date().toISOString()
};
this.todos.unshift(todo);
this.saveTodos();
this.todoInput.value = '';
this.render();
}
toggleTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
this.saveTodos();
this.render();
}
}
deleteTodo(id) {
if (confirm('确定要删除这个待办事项吗?')) {
this.todos = this.todos.filter(t => t.id !== id);
this.saveTodos();
this.render();
}
}
getFilteredTodos() {
switch (this.filter) {
case 'active':
return this.todos.filter(t => !t.completed);
case 'completed':
return this.todos.filter(t => t.completed);
default:
return this.todos;
}
}
saveTodos() {
localStorage.setItem('todos', JSON.stringify(this.todos));
}
render() {
const filteredTodos = this.getFilteredTodos();
if (filteredTodos.length === 0) {
this.todoList.innerHTML = `
<div class="empty-state">
<p>暂无待办事项</p>
</div>
`;
} else {
this.todoList.innerHTML = filteredTodos.map(todo => `
<li class="todo-item ${todo.completed ? 'completed' : ''}">
<input type="checkbox"
class="todo-checkbox"
${todo.completed ? 'checked' : ''}
onchange="app.toggleTodo(${todo.id})">
<span class="todo-text">${this.escapeHtml(todo.text)}</span>
<button class="delete-btn" onclick="app.deleteTodo(${todo.id})">删除</button>
</li>
`).join('');
}
// 更新统计
const activeCount = this.todos.filter(t => !t.completed).length;
const completedCount = this.todos.filter(t => t.completed).length;
this.stats.textContent = `共 ${this.todos.length} 项 | 未完成 ${activeCount} 项 | 已完成 ${completedCount} 项`;
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
// 初始化应用
const app = new TodoApp();
四、知识点回顾
| 知识点 | 应用 |
|---|---|
| DOM 操作 | getElementById, querySelector, innerHTML |
| 事件监听 | addEventListener |
| ES6 Class | class TodoApp |
| 数组方法 | filter, find, map, forEach |
| 本地存储 | localStorage.setItem, localStorage.getItem |
| 模板字符串 | 动态生成 HTML |
五、扩展挑战
- 添加编辑功能:双击待办事项可以编辑
- 添加拖拽排序:可以拖动调整顺序
- 添加截止日期:显示距离截止还有多久
- 添加分类标签:工作、生活、学习等
六、课后作业
- 完成上述代码,运行并测试所有功能
- 尝试添加"清空已完成"按钮
- 给待办事项添加优先级(高/中/低)
有问题欢迎评论区留言,大家一起讨论!
标签:JavaScript | 实战项目 | 待办清单 | TodoApp | DOM操作 | 本地存储
更多推荐

所有评论(0)