← 代码俱乐部 · 创作者层 04 / 8
★ 代码俱乐部 · 压轴 ★
整个学院的压轴。不是练习项目 —— 是给爷爷/奶奶/弟弟用的真工具。功能完整、有测试、放在网上、那个人真的会用第二次。
把这一项做完,你已经做了 一件真东西。不是练习。不是模拟。一个具体的人,因为你写的代码,今天比昨天好一点点。
这就是工程师的真本事。
升级版,加了本地存储(刷新页面后数据不丢失):
<!DOCTYPE html>
<html>
<head>
<style>
/* 完整的样式代码 */
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: sans-serif; background: linear-gradient(135deg, #667eea, #764ba2); min-height: 100vh; padding: 20px; }
.container { max-width: 700px; margin: 0 auto; }
.card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); }
h1 { color: #667eea; margin-bottom: 10px; }
.stats { color: #999; font-size: 14px; margin-bottom: 20px; }
.input-area { display: flex; gap: 10px; margin-bottom: 20px; }
input { flex: 1; padding: 12px; border: 2px solid #eee; border-radius: 5px; font-size: 14px; }
input:focus { outline: none; border-color: #667eea; }
button { padding: 12px 24px; background: #667eea; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: bold; }
button:hover { background: #764ba2; }
.todo-list { list-style: none; }
.todo-item { padding: 15px; border-bottom: 1px solid #f0f0f0; display: flex; align-items: center; gap: 12px; transition: background 0.2s; }
.todo-item:hover { background: #f9f9f9; }
.todo-item input[type="checkbox"] { width: 20px; height: 20px; cursor: pointer; }
.todo-item.done span { text-decoration: line-through; color: #ccc; }
.delete-btn { margin-left: auto; background: #f44336; padding: 6px 12px; font-size: 12px; border-radius: 3px; }
.empty { text-align: center; color: #ccc; padding: 40px; font-size: 16px; }
</style>
</head>
<body>
<div class="container">
<div class="card">
<h1>📝 我的待办清单</h1>
<div class="stats">完成: <span id="stats">0/0</span></div>
<div class="input-area">
<input type="text" id="newTodo" placeholder="输入一个新任务..." onkeypress="if(event.key==='Enter') addTodo()" />
<button onclick="addTodo()">添加</button>
</div>
<ul class="todo-list" id="todoList"></ul>
<div class="empty" id="emptyMsg">还没有任务。来添加一个吧!</div>
</div>
</div>
<script>
let todos = JSON.parse(localStorage.getItem('todos')) || [];
function addTodo() {
let input = document.getElementById('newTodo');
let text = input.value.trim();
if (!text) return;
todos.push({ id: Date.now(), text, done: false });
input.value = '';
save();
render();
}
function toggleTodo(id) {
let todo = todos.find(t => t.id === id);
if (todo) todo.done = !todo.done;
save();
render();
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
save();
render();
}
function save() {
localStorage.setItem('todos', JSON.stringify(todos));
}
function render() {
if (todos.length === 0) {
document.getElementById('emptyMsg').style.display = 'block';
document.getElementById('todoList').innerHTML = '';
document.getElementById('stats').innerText = '0/0';
return;
}
document.getElementById('emptyMsg').style.display = 'none';
let html = '';
let done = todos.filter(t => t.done).length;
for (let todo of todos) {
let cls = todo.done ? 'done' : '';
html += '<li class="todo-item ' + cls + '">' +
'<input type="checkbox" ' + (todo.done ? 'checked' : '') + ' onchange="toggleTodo(' + todo.id + ')" />' +
'<span>' + todo.text + '</span>' +
'<button class="delete-btn" onclick="deleteTodo(' + todo.id + ')">删除</button>' +
'</li>';
}
document.getElementById('todoList').innerHTML = html;
document.getElementById('stats').innerText = done + '/' + todos.length;
}
render();
</script>
</body>
</html>
关键进阶功能:localStorage 让任务在刷新页面后保留。这样用户关掉浏览器再打开,他的清单还在。
这个练习没有代码框。你需要自己决定:
在下面写你的计划:
一个真实的例子:
"我要给奶奶做一个'用药提醒'的网页。 功能: 1. 奶奶每天需要吃三种药,分别在早中晚。 2. 网页上显示大大的'今天早上该吃药了'。 3. 奶奶点'我吃过了',就记录下来。 4. 晚上还没吃,网页就变红色,提醒她别忘了。 为什么是她最需要的:她现在用纸条记,经常丢。这个网页用大字体,永远不会丢。"
关键:这不是"我想做什么",而是"我身边的人真正需要什么"。前者通常没人用,后者会被用很多次。