第一步:吃透「待办清单」需求(明确目标、边界、验收标准)
核心目标
使用对象
需求边界(明确做 / 不做)
验收标准
第二步:拆解需求(把大需求拆成最小粒度的小任务)
第三步:选型设计(为每个小任务选最优方案)
第四步:预演逻辑(用伪代码梳理核心流程)
第五步:编码实现(按任务逐个写,边写边测)
第六步:复盘优化(做完后回头看,找可优化点)
第一步:吃透「待办清单」需求(明确目标、边界、验收标准)
先把模糊的 “待办清单” 需求变清晰,避免做偏:
核心目标
让用户能添加、查看、标记完成、删除待办事项,所有数据暂存于前端(不连后端,降低复杂度)。
使用对象
普通前端用户(浏览器访问)。
需求边界(明确做 / 不做)
✅ 必须做:
- 输入待办内容,点击 “添加” 按钮,新增待办项到列表;
- 待办项显示内容,可点击 “完成” 标记为已完成(文字变灰色 + 划线);
- 待办项可点击 “删除” 按钮,从列表中移除;
- 输入框非空校验(空内容无法添加)。
❌ 暂不做:
- 数据持久化(刷新页面不保留待办);
- 待办分类、优先级、编辑、分页;
- 样式极致美化(保证能用即可,后续可优化)。
验收标准
- 输入非空内容→点击添加→列表实时显示新待办;
- 空内容点击添加→提示 “请输入待办内容”,不新增;
- 点击 “完成”→待办文字变灰色 + 划线;
- 点击 “删除”→待办项从列表消失。
第二步:拆解需求(把大需求拆成最小粒度的小任务)
按「业务流程 + 功能模块」拆解,标注依赖关系:
| 序号 | 小任务(1~2 小时可完成) | 依赖关系 | 核心诉求 |
|---|---|---|---|
| 1 | 搭建基础页面结构(HTML):输入框 + 添加按钮 + 待办列表容器 | 无 | 页面有基础 UI |
| 2 | 基础样式(CSS):简单布局,区分待办项、按钮样式 | 依赖 1 | 页面不混乱 |
| 3 | 定义存储待办的数据结构(JS 数组) | 无 | 管理待办数据 |
| 4 | 实现输入框非空校验逻辑(JS) | 无 | 空内容不添加 |
| 5 | 实现 “添加” 按钮点击事件:新增待办到数组(JS) | 依赖 3、4 | 数据正确新增 |
| 6 | 实现渲染待办列表逻辑:把数组数据展示到页面(JS) | 依赖 3 | 页面实时显示待办 |
| 7 | 实现 “完成” 按钮点击事件:修改待办完成状态(JS) | 依赖 5、6 | 标记完成状态 |
| 8 | 实现 “删除” 按钮点击事件:从数组删除待办(JS) | 依赖 5、6 | 数据删除后页面同步 |
| 9 | 异常提示:空内容添加时弹出提示(JS) | 依赖 4 | 提示用户错误操作 |
第三步:选型设计(为每个小任务选最优方案)
技术栈:原生 HTML+CSS+JS(无框架,新手易上手,无额外依赖)。
| 小任务 | 技术方案 | 选型原因 |
|---|---|---|
| 1(HTML) | 用<input type="text">做输入框,<button>做添加按钮,<ul>/<li>做待办列表 |
原生标签满足需求,语义化清晰 |
| 2(CSS) | 基础布局用 Flex,完成状态用text-decoration: line-through和color: #999 |
简单易实现,无需复杂样式 |
| 3(数据结构) | 数组存储对象,每个对象包含id(唯一标识)、content(待办内容)、isDone(是否完成) |
id用于删除 / 标记完成时精准定位,isDone记录状态 |
| 4(非空校验) | JS 判断input.value.trim()是否为空字符串 |
去除首尾空格,避免用户输入空格冒充内容 |
| 5~9(JS 逻辑) | 原生 DOM 操作(获取元素、绑定点击事件、创建 / 删除 DOM 节点) | 无需框架,直接操作页面,新手易理解 |
第四步:预演逻辑(用伪代码梳理核心流程)
先在脑子里 “跑一遍” 核心逻辑,避免编码卡壳:
plaintext
// 核心流程伪代码:添加待办
点击“添加”按钮 →
获取输入框内容(去除首尾空格)→
内容为空 → 弹出提示“请输入待办内容” → 终止执行 →
内容非空 → 生成唯一id → 新建待办对象(id、content、isDone: false)→
把待办对象添加到数组 →
调用渲染列表函数 →
清空页面原有列表 →
遍历待办数组 →
为每个待办创建li标签 →
根据isDone状态设置样式(完成则划线+灰色)→
添加“完成”“删除”按钮 →
把li插入到页面列表 →
清空输入框内容
// 核心流程伪代码:标记完成
点击某待办的“完成”按钮 →
获取该待办的id →
遍历数组,找到对应id的待办对象 →
反转isDone状态(true↔false)→
调用渲染列表函数(页面同步样式)
// 核心流程伪代码:删除待办
点击某待办的“删除”按钮 →
获取该待办的id →
过滤数组,移除对应id的待办对象 →
调用渲染列表函数(页面同步删除)
第五步:编码实现(按任务逐个写,边写边测)
下面是完整可运行的代码,每个部分对应拆解的小任务,带详细注释,你可以直接复制到本地(新建
todo.html文件)运行测试:html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>简单待办清单</title>
<style>
/* 小任务2:基础样式 */
.todo-container {
max-width: 600px;
margin: 20px auto;
padding: 0 20px;
}
.todo-input-area {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
#todo-input {
flex: 1;
padding: 8px;
font-size: 16px;
}
#add-btn {
padding: 8px 20px;
background: #4299e1;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.todo-list {
list-style: none;
padding: 0;
}
.todo-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px;
border-bottom: 1px solid #eee;
margin-bottom: 8px;
}
.todo-content {
flex: 1;
font-size: 16px;
}
.todo-content.done {
color: #999;
text-decoration: line-through;
}
.complete-btn {
background: #48bb78;
color: white;
border: none;
padding: 4px 10px;
border-radius: 4px;
cursor: pointer;
}
.delete-btn {
background: #e53e3e;
color: white;
border: none;
padding: 4px 10px;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<!-- 小任务1:基础HTML结构 -->
<div class="todo-container">
<div class="todo-input-area">
<input type="text" id="todo-input" placeholder="请输入待办内容...">
<button id="add-btn">添加待办</button>
</div>
<ul class="todo-list" id="todo-list"></ul>
</div>
<script>
// 小任务3:定义待办数据数组(存储所有待办)
let todoList = [];
// 生成唯一id的辅助函数(简单实现:时间戳+随机数)
function generateId() {
return Date.now() + Math.floor(Math.random() * 1000);
}
// 小任务6:渲染待办列表到页面
function renderTodoList() {
const todoListDom = document.getElementById('todo-list');
// 清空原有列表,避免重复渲染
todoListDom.innerHTML = '';
// 遍历待办数组,创建每个待办项的DOM
todoList.forEach(todo => {
const li = document.createElement('li');
li.className = 'todo-item';
li.dataset.id = todo.id; // 把id存到DOM属性,方便后续查找
// 创建待办内容元素
const contentDiv = document.createElement('div');
contentDiv.className = `todo-content ${todo.isDone ? 'done' : ''}`;
contentDiv.textContent = todo.content;
// 创建完成按钮
const completeBtn = document.createElement('button');
completeBtn.className = 'complete-btn';
completeBtn.textContent = todo.isDone ? '取消完成' : '完成';
// 小任务7:绑定完成按钮点击事件
completeBtn.addEventListener('click', () => toggleTodoDone(todo.id));
// 创建删除按钮
const deleteBtn = document.createElement('button');
deleteBtn.className = 'delete-btn';
deleteBtn.textContent = '删除';
// 小任务8:绑定删除按钮点击事件
deleteBtn.addEventListener('click', () => deleteTodo(todo.id));
// 组装DOM元素
li.appendChild(contentDiv);
li.appendChild(completeBtn);
li.appendChild(deleteBtn);
todoListDom.appendChild(li);
});
}
// 小任务4+5:添加待办的核心函数
function addTodo() {
const input = document.getElementById('todo-input');
const content = input.value.trim(); // 去除首尾空格
// 小任务4:非空校验
if (!content) {
// 小任务9:空内容提示
alert('请输入待办内容!');
return;
}
// 小任务5:创建新待办对象并添加到数组
const newTodo = {
id: generateId(),
content: content,
isDone: false // 默认未完成
};
todoList.push(newTodo);
// 重新渲染列表
renderTodoList();
// 清空输入框
input.value = '';
}
// 小任务7:标记待办完成/取消完成
function toggleTodoDone(todoId) {
// 找到对应id的待办,反转isDone状态
todoList = todoList.map(todo => {
if (todo.id === todoId) {
return { ...todo, isDone: !todo.isDone };
}
return todo;
});
// 重新渲染列表
renderTodoList();
}
// 小任务8:删除待办
function deleteTodo(todoId) {
// 过滤掉对应id的待办
todoList = todoList.filter(todo => todo.id !== todoId);
// 重新渲染列表
renderTodoList();
}
// 绑定添加按钮点击事件
document.getElementById('add-btn').addEventListener('click', addTodo);
// 支持按回车键添加待办(优化体验)
document.getElementById('todo-input').addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
addTodo();
}
});
</script>
</body>
</html>
代码使用说明
- 新建一个文本文件,将上述代码复制进去;
- 把文件后缀改为
.html(比如todo.html); - 用浏览器打开这个文件,即可测试所有功能。
边写边测的建议
- 写完 HTML/CSS 后,先打开页面,确认输入框、按钮、列表容器显示正常;
- 写完
addTodo函数后,测试空输入点击添加→看是否提示,输入内容添加→看数组是否新增(可在控制台打印todoList); - 写完渲染函数后,测试添加待办→页面是否显示;
- 写完完成 / 删除函数后,分别测试标记完成、删除功能是否生效。
第六步:复盘优化(做完后回头看,找可优化点)
1. 本次编码中可能卡壳的点 & 解决方法
- 问题:点击完成 / 删除按钮,无法定位到对应的待办项;
解决:给每个待办 DOM 绑定
data-id属性,通过 id 精准查找数组中的待办。 - 问题:渲染列表时重复添加;
解决:渲染前先清空原有列表(
todoListDom.innerHTML = '')。
2. 可优化的点(新手可逐步实现)
- 数据持久化:用
localStorage存储todoList,页面刷新后不丢失; - 样式优化:添加 hover 效果、调整配色、适配移动端;
- 功能扩展:添加待办编辑、批量删除、清空所有待办;
- 体验优化:提示不用
alert,改用页面内的友好提示框。
3. 可复用的代码
generateId函数:生成唯一标识,后续做其他列表类功能可复用;renderTodoList的思路:“数据驱动视图”(修改数据→重新渲染),这是前端核心思想,所有列表类功能都能用。
总结
- 思考待办清单需求的核心是先明确边界(做 / 不做),再拆解成最小任务,避免一上来就写代码导致逻辑混乱;
- 实现的关键是数据驱动视图:所有操作先修改数组数据,再重新渲染页面,而非直接修改 DOM;
- 新手编码时要边写边测,完成一个小功能就测试,及时发现并修复问题,避免 bug 堆积。
你可以先把这份代码跑起来,体验完整的功能,然后尝试按 “复盘优化” 里的点做扩展(比如先实现
localStorage持久化),遇到具体问题可以随时问~