JavaScript: 综合项目:待办清单
恭喜你走到了最后一课!前面的 27 课你学到了变量、函数、数组、DOM、事件、JSON、异步、Class……现在该把它们串起来,做一个完整的小应用了。这个项目将是你学习成果的集大成之作。
1. 项目介绍
我们将开发一个待办清单(Todo App)——别看它小,它几乎用到了你学过的所有核心知识。完成后你会有一个可以真正使用的效率工具。
▶ 示例
JAVASCRIPT
// 本节代码示例
const message = "你好,世界!";
console.log(message);
这是最简单的示例,后续章节会详细解释。## 2. 功能需求
- 添加待办事项 — 输入框 + 按钮,回车或点击都能添加
- 标记完成/未完成 — 点击待办项切换完成状态(划线效果)
- 删除待办事项 — 每项旁有删除按钮
- 筛选 — 三个按钮:全部 / 未完成 / 已完成
- 本地存储 — 用
localStorage保存数据,刷新页面不丢失 - 统计未完成数量 — 底部显示"X 项未完成"
3. 技术要求
| 知识点 | 用在哪 |
|---|---|
| Class | TodoApp 类组织所有逻辑 |
| async/await | localStorage 的读写操作包装成异步函数 |
| DOM 操作 | 动态创建列表项、修改内容、删除元素 |
| 事件处理 | 表单 submit、列表 click、筛选按钮 click |
| JSON | JSON.stringify 保存、JSON.parse 读取 |
| 数组方法 | filter、map、find 操作待办数据 |
| 模板字符串 | 拼接 HTML |
4. 验收标准
- [ ] 所有 6 项功能正常工作
- [ ] 刷新页面后数据不丢失
- [ ] 代码有清晰注释
- [ ] 无
alert/prompt/confirm,用页面内交互 - [ ] 空输入不能添加(有提示)
5. 参考实现思路
以下是提示和方向,不是完整代码。自己动手写出来,收获才最大。
(1) 数据结构
HTML
<script>
// 每个待办项是一个对象
const todo = {
id: Date.now(), // 唯一标识
text: '学习 JavaScript',
completed: false
};
console.log(todo);
// 所有待办项存在数组中
let todos = [];
</script>
(2) 类结构
HTML
<script>
class TodoApp {
constructor() {
this.todos = []; // 数据
this.filter = 'all'; // 当前筛选
this.init(); // 初始化
}
async init() {
// 1. 从 localStorage 加载数据
// 2. 绑定事件
// 3. 渲染列表
}
async save() {
// JSON.stringify → localStorage.setItem
}
async load() {
// localStorage.getItem → JSON.parse
}
addTodo(text) { /* 创建对象,push,save,render */ }
toggleTodo(id) { /* 找到对应项,取反 completed,save,render */ }
deleteTodo(id) { /* 过滤掉对应项,save,render */ }
render() {
// 1. 根据 filter 筛选 todos
// 2. 清空列表容器
// 3. 遍历筛选后的数组,创建 DOM
// 4. 更新统计数字
}
}
</script>
(3) 事件绑定思路
- 表单
submit:e.preventDefault()→ 取输入值 →addTodo(text)→ 清空输入框 - 列表
click(事件委托):判断e.target是完成按钮还是删除按钮 → 调用对应方法 - 筛选按钮
click:更新this.filter→render()
(4) 渲染思路
HTML
<script>
render() {
const filtered = this.todos.filter(function(todo) {
if (this.filter === 'active') return !todo.completed;
if (this.filter === 'completed') return todo.completed;
return true; // 'all'
}.bind(this));
// 清空容器
this.listEl.innerHTML = '';
filtered.forEach(function(todo) {
var li = document.createElement('li');
// 设置内容、样式、数据属性
// 绑定完成和删除的事件
this.listEl.appendChild(li);
}.bind(this));
// 更新统计
var activeCount = this.todos.filter(function(t) { return !t.completed; }).length;
this.countEl.textContent = activeCount + ' 项未完成';
}
</script>
6. 拓展方向
完成基本功能后,试试这些进阶挑战:
- 🔄 拖拽排序 — 用 HTML5 Drag & Drop API 或触摸事件实现
- ✏️ 编辑功能 — 双击待办项进入编辑模式,回车保存
- 🏷️ 分类标签 — 给待办项加标签(工作/学习/生活),按标签筛选
- 🎨 主题切换 — 深色/浅色主题,用
localStorage记住偏好 - ⏰ 到期提醒 — 给待办项加截止日期,过期变红
▶ 示例
使用类和 localStorage 的完整 Todo 应用:
HTML
<!DOCTYPE html>
<html>
<head><style>body{font-family:Arial;max-width:600px;margin:20px auto;}.done{text-decoration:line-through;color:gray;}</style></head>
<body>
<h1>Todo 应用</h1>
<input id="taskInput" placeholder="新任务">
<button id="addBtn">添加</button>
<ul id="taskList"></ul>
<script>
class Todo {
constructor() { this.tasks = JSON.parse(localStorage.getItem('tasks') || '[]'); }
add(text) { this.tasks.push({text, done: false}); localStorage.setItem('tasks', JSON.stringify(this.tasks)); this.render(); }
toggle(i) { this.tasks[i].done = !this.tasks[i].done; localStorage.setItem('tasks', JSON.stringify(this.tasks)); this.render(); }
render() { document.getElementById('taskList').innerHTML = this.tasks.map((t, i) => `<li class="${t.done ? 'done' : ''}">${t.text}</li>`).join(''); }
}
const todo = new Todo();
document.getElementById('addBtn').onclick = () => todo.add(document.getElementById('taskInput').value);
todo.render();
</script>
</body>
</html>
这演示了基于类的状态管理、localStorage 持久化、动态 DOM 渲染的完整 Todo 应用。
❓ 常见问题
Q 为什么用 Class 而不是构造函数?
A Class 语法更清晰简洁,
constructor、this、继承都有明确的语法支持。虽然底层仍然是原型链,但写起来像其他面向对象语言,可读性更好。Q localStorage 存储的数据会丢失吗?
A 除非用户手动清除浏览器数据或使用无痕模式,否则 localStorage 的数据会永久保存在本地。注意它只能存字符串,对象需要
JSON.stringify 后再存。Q 事件委托是什么?为什么在待办清单中特别有用?
A 事件委托是把事件监听器绑在父元素上,通过判断
e.target 来处理子元素的事件。在待办清单中,新增的待办项自动获得事件处理,不用重复绑定,性能更好。📖 小节
- 综合项目串联了变量、函数、数组、对象、DOM 操作、事件处理、JSON、Class 等核心知识
- 用 Class 组织代码让结构更清晰,
constructor初始化、方法定义在 prototype 上 - localStorage 实现数据持久化,刷新页面数据不丢失
- 事件委托利用事件冒泡机制,减少重复绑定,动态元素自动生效
- 筛选功能通过维护
filter状态和条件渲染实现,是 MVVM 模式的基础思路
📝 作业
完成上述待办清单应用的所有功能,并通过所有验收标准。
建议步骤:
- 先搭 HTML 结构和 CSS 样式
- 实现
TodoApp类的骨架(constructor、init) - 实现
addTodo和render,先让添加功能跑通 - 实现
toggleTodo,标记完成/未完成 - 实现
deleteTodo,删除功能 - 实现筛选功能
- 实现
save和load,持久化数据 - 统计未完成数量
- 最后打磨:空输入提示、样式优化
💡 提示: 别想一步到位,先让最小功能跑起来,再一点点加。软件开发就是"先让它工作,再让它好看,最后让它快"。
📝 作业
- 基础:完成待办清单的核心功能——添加、标记完成、删除,数据用数组存储即可(无需 localStorage)。
- 进阶:在基础版上加入 localStorage 持久化和筛选功能(全部/未完成/已完成),刷新后数据不丢失。
- 挑战:实现拓展功能中的至少一项(拖拽排序、编辑功能、分类标签、主题切换或到期提醒),并写出实现思路说明。