正在加载...

小项目 — 交互式待办清单

你在这一页做出一份短清单,手里只有三步:加入 buy tea,标成完成,再删掉。还开着的时候,那一行是 buy tea。做完以后,那一行是 done: buy tea。

上一页只点了名字

技能的名字说过了,屏幕上没有清单。这份页面就是清单。你用到数组、表单、textContent,还有一次点击。每加一条,页面都不能重新加载。

一条待办是对象

tasks 里放的是对象。每个对象带着 text 和 done。新的一条,done 一开始是 false。addTask 先做 trim。剪完若什么都不剩,就不会 push,这条也不存。

放进第一条对象

javascript
const tasks = [];
function addTask(text) {
const clean = text.trim();
if (!clean) {
return;
}
tasks.push({ text: clean, done: false });
}
addTask("buy tea");
console.log(tasks[0].text);
console.log(tasks[0].done);

两次记录挨着出现:先是 buy tea,再是 false。addTask(" ") 剪完是空的,什么都不存,长度仍是 0。

一提交,文档就会重新加载

数组只活在内存里,页面一换,清单就没了。event.preventDefault() 把这次重新加载停住。停住以后才写入文字、清空输入框、再画一遍。

提交后页面还在

javascript
const form = document.querySelector("#add-form");
const input = document.querySelector("#task-text");
form.addEventListener("submit", (event) => {
event.preventDefault();
addTask(input.value);
input.value = "";
render();
});

文档还在。输入框空了。render 跑过。框里若只有空格,不会多出一行。

两个按钮都不能提交表单

render 先清空 #tasks,再为每一条做一个 li。没完成的显示 text。完成的显示 done:,后面接上文字。每一行有两个按钮,都写着 type="button",这样点击不会提交表单。Done 把那个布尔值反过来。删除走 splice。两件事之后都要再画,不然旧的序号会指到别的条目。

一行、切换、删掉

javascript
function toggleTask(index) {
tasks[index].done = !tasks[index].done;
}
function removeTask(index) {
tasks.splice(index, 1);
}
function render() {
const list = document.querySelector("#tasks");
list.textContent = "";
tasks.forEach((task, index) => {
const item = document.createElement("li");
item.textContent = task.done ? "done: " + task.text : task.text;
const doneButton = document.createElement("button");
doneButton.type = "button";
doneButton.textContent = "Done";
doneButton.addEventListener("click", () => {
toggleTask(index);
render();
});
const removeButton = document.createElement("button");
removeButton.type = "button";
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => {
removeTask(index);
render();
});
item.append(doneButton, removeButton);
list.append(item);
});
}

顺序是 addTask("buy tea"),接着 toggleTask(0),接着 render。这一行变成 done: buy tea。再切换一次,又回到 buy tea。removeTask(0) 之后长度是 0,下一次绘制没有任何行。输入框里的词用 textContent 放进页面,不要当成 HTML 贴进去。

序号只属于这一轮

forEach 记住的是这一轮的序号。splice 之后,旧序号指错任务。再绘制一次会丢掉旧按钮,按现在的序号做新的。少了这第二次绘制,Remove 会删错行。

三件事分开做

表单负责加入。清单负责画出来。Done 和 Remove 只改 tasks,然后重新画。

表单和清单

html
<!DOCTYPE html>
<html>
<body>
<form id="add-form">
<input id="task-text" type="text">
<button type="submit">Add</button>
</form>
<ul id="tasks"></ul>
<script>
const tasks = [];
function addTask(text) {
const clean = text.trim();
if (!clean) return;
tasks.push({ text: clean, done: false });
}
function toggleTask(index) {
tasks[index].done = !tasks[index].done;
}
function removeTask(index) {
tasks.splice(index, 1);
}
function render() {
const list = document.querySelector("#tasks");
list.textContent = "";
tasks.forEach((task, index) => {
const item = document.createElement("li");
item.textContent = task.done ? "done: " + task.text : task.text;
const doneButton = document.createElement("button");
doneButton.type = "button";
doneButton.textContent = "Done";
doneButton.addEventListener("click", () => {
toggleTask(index);
render();
});
const removeButton = document.createElement("button");
removeButton.type = "button";
removeButton.textContent = "Remove";
removeButton.addEventListener("click", () => {
removeTask(index);
render();
});
item.append(doneButton, removeButton);
list.append(item);
});
}
document.querySelector("#add-form").addEventListener("submit", (event) => {
event.preventDefault();
addTask(document.querySelector("#task-text").value);
document.querySelector("#task-text").value = "";
render();
});
</script>
</body>
</html>

输入 buy tea,按 Add。出现一行 buy tea,输入框被清空。按 Done,这一行变成 done: buy tea。按 Remove,清单空了。输入框空着再按 Add,什么都不会加上。

桌上的五步

  1. 调用 addTask("buy tea")。第一条 text 是 buy tea,done 是 false。
  2. 提交表单。页面不重新加载,行出现了。
  3. 按 Done。这一行是 done: buy tea。
  4. 按 Remove。tasks.length 变成 0。
  5. 只提交空格。清单不会变长。

真正会踩的错

  • 跳过 preventDefault,数组在提交时就没了
  • 对空字符串做 push
  • 在 Done 或 Remove 上使用 type="submit"
  • 只从画面上删掉一行,却忘了 splice,下一次绘制又把它画回来
  • splice 之后不调用 render
  • 把输入框的内容当成 HTML 写进页面

带走这几句

  • 一条待办是 { text, done },done 从 false 开始
  • addTask("buy tea") 存下 buy tea,空白什么都不存
  • preventDefault 留住页面,render 画出各行
  • Done 显示 done: buy tea,Remove 让长度变成 0
  • 每次改动之后都要再画一次

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
5
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部