🧠 为什么要从项目学 JavaScript?
JavaScript 是 Web 的「大脑」。HTML 定义结构,CSS 控制样式,而 JavaScript 让页面「活」起来 — 它可以响应用户操作、动态修改内容、与服务器通信。对于前端初学者来说,最容易犯的错误是花太多时间读语法书而迟迟不动手。To-Do List 是一个完美的入门项目:它足够简单让你快速完成,又包含了真实应用的所有核心环节(数据管理、用户交互、界面更新)。
在本教程中,你将学到:变量声明与数据类型、函数定义与调用、DOM 元素的选择与创建、事件监听与处理、数组和对象的简单使用 — 这些都是构建任何 JavaScript 应用都绕不开的基础知识。
📦 第一步:HTML 结构
任何 JavaScript 交互都始于 HTML。我们的 To-Do List 需要三个部分:输入区域(文本框 + 添加按钮)、列表容器(放置待办项)、以及每个待办项的模板(复选框 + 文字 + 删除按钮)。
<!-- 输入区域 -->
<div class="todo-input-group">
<input type="text" id="todoInput" placeholder="输入待办事项...">
<button id="addTodoBtn">添加</button>
</div>
<!-- 列表容器 -->
<ul class="todo-list" id="todoList">
<li>
<input type="checkbox" class="todo-check">
<span class="todo-text">学习 HTML 基础</span>
<button class="todo-delete">✕</button>
</li>
</ul>
HTML 结构的关键是给需要操作的元素加上 id 或 class,这样 JavaScript 才能准确找到它们。这里 todoInput 和 addTodoBtn 用 id(唯一),列表项内的元素用 class(复用)。
🎯 第二步:用 JS 选中 DOM 元素
JavaScript 通过 DOM API 与 HTML 交互。「DOM」是 Document Object Model 的缩写,浏览器把 HTML 文档解析成一棵对象树,JS 可以在这棵树上增删改查。最常用的选择方法有两个:
// 通过 ID 选中(返回单个元素)
const todoInput = document.getElementById('todoInput');
const addBtn = document.getElementById('addTodoBtn');
const todoList = document.getElementById('todoList');
// 通过 class 选中(返回类数组 HTMLCollection)
const allChecks = document.querySelectorAll('.todo-check');
// querySelectorAll 更灵活,支持任何 CSS 选择器
getElementById 是性能最快的选择器,适合有 id 的元素。querySelectorAll 支持完整的 CSS 选择器语法,适合复杂查询。在初学阶段,掌握这两个就足够了。
🖱️ 第三步:事件监听 — 让按钮有反应
事件监听(Event Listener)是 JavaScript 交互的核心。当用户点击按钮、按下键盘、或移动鼠标时,浏览器会触发对应的事件。我们用 addEventListener 来「监听」这些事件并执行代码:
// 监听添加按钮的点击事件
addBtn.addEventListener('click', function() {
const text = todoInput.value.trim(); // 获取输入框内容
if (!text) return; // 空内容不处理
// 这里稍后会写添加待办项的代码
todoInput.value = ''; // 清空输入框
todoInput.focus(); // 让输入框保持焦点
});
// 监听回车键(更自然的交互方式)
todoInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
addBtn.click(); // 模拟点击添加按钮
}
});
addEventListener 的第一个参数是事件类型('click'、'keydown' 等),第二个参数是回调函数 — 事件发生时执行的代码。注意 e.key === 'Enter' 检查按键是否为回车,让用户按 Enter 就能添加待办。
🏗️ 第四步:动态创建 DOM 元素
每次用户添加一个新待办,我们需要动态创建一个 <li> 元素并插入到列表中。JS 提供了 document.createElement 来创建元素:
function createTodoItem(text) {
// 创建三个子元素
const li = document.createElement('li');
const check = document.createElement('input');
check.type = 'checkbox';
check.className = 'todo-check';
const span = document.createElement('span');
span.className = 'todo-text';
span.textContent = text; // 设置文字内容
const del = document.createElement('button');
del.className = 'todo-delete';
del.textContent = '✕';
// 为复选框和删除按钮添加事件
check.addEventListener('change', function() {
span.classList.toggle('done', check.checked);
});
del.addEventListener('click', function() {
li.remove(); // 从 DOM 中删除整个 li
});
// 组装:li 包含 check + span + del
li.appendChild(check);
li.appendChild(span);
li.appendChild(del);
return li;
}
注意 classList.toggle('done', check.checked) 的用法 — 第二个参数是布尔值,当 check.checked 为 true 时添加 class,false 时移除。CSS 中 .todo-text.done 设置了删除线样式,视觉上标记任务完成。
🔗 第五步:串联所有功能
现在把添加逻辑和创建逻辑串起来:
function addTodo() {
const text = todoInput.value.trim();
if (text === '') return; // 防止添加空项
const newItem = createTodoItem(text);
todoList.appendChild(newItem); // 插入到列表末尾
todoInput.value = ''; // 清空输入
todoInput.focus();
}
addBtn.addEventListener('click', addTodo);
todoInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') addTodo();
});
这里把添加逻辑提取成 addTodo 函数,让点击按钮和按回车都能调用同一套逻辑。遵循 DRY(Don't Repeat Yourself)原则是写出整洁代码的第一步。
📝 完整代码汇总
下面是 To-Do List 的完整 HTML 文件,复制即可运行:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的 To-Do List</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: system-ui, sans-serif;
background: #1a1a2e;
color: #e0e0e0;
display: flex;
justify-content: center;
padding: 3rem 1rem;
}
.container { max-width: 500px; width: 100%; }
h1 { text-align: center; margin-bottom: 1.5rem; color: #f472b6; }
.input-group { display: flex; gap: 0.5rem; margin-bottom: 1.5rem; }
.input-group input {
flex: 1;
padding: 0.7rem 1rem;
border-radius: 0.5rem;
border: 1px solid rgba(255,255,255,0.1);
background: rgba(255,255,255,0.06);
color: white;
outline: none;
}
.input-group input:focus { border-color: #f472b6; }
.input-group button {
padding: 0.7rem 1.2rem;
background: #f472b6;
color: #1a1a2e;
border: none;
border-radius: 0.5rem;
font-weight: 700;
cursor: pointer;
}
.input-group button:hover { background: #ec4899; }
ul { list-style: none; }
ul li {
display: flex;
align-items: center;
padding: 0.7rem 1rem;
background: rgba(255,255,255,0.04);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 0.5rem;
margin-bottom: 0.5rem;
}
ul li span { flex: 1; margin: 0 0.75rem; }
ul li span.done { text-decoration: line-through; color: #6b7280; }
ul li .del {
background: none;
border: none;
color: #ef4444;
cursor: pointer;
font-size: 1.1rem;
}
</style>
</head>
<body>
<div class="container">
<h1>📋 我的待办列表</h1>
<div class="input-group">
<input type="text" id="input" placeholder="添加新任务...">
<button id="addBtn">添加</button>
</div>
<ul id="list"></ul>
</div>
<script>
const input = document.getElementById('input');
const addBtn = document.getElementById('addBtn');
const list = document.getElementById('list');
function createItem(text) {
const li = document.createElement('li');
const check = document.createElement('input');
check.type = 'checkbox';
const span = document.createElement('span');
span.textContent = text;
const del = document.createElement('button');
del.className = 'del';
del.textContent = '✕';
check.addEventListener('change', () => span.classList.toggle('done'));
del.addEventListener('click', () => li.remove());
li.append(check, span, del);
return li;
}
addBtn.addEventListener('click', () => {
const text = input.value.trim();
if (!text) return;
list.appendChild(createItem(text));
input.value = '';
input.focus();
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') addBtn.click();
});
</script>
</body>
</html>
🚀 扩展思路
掌握了基础版 To-Do List 之后,可以尝试以下扩展来巩固所学:
- 本地存储 — 用
localStorage保存待办数据,刷新页面不丢失。 - 分类标签 — 给每个待办添加「工作」「学习」「生活」等标签。
- 拖拽排序 — 用 HTML5 Drag & Drop API 让用户拖动调整顺序。
- 全部/活跃/已完成筛选 — 添加筛选按钮切换显示模式。
- 待办数量统计 — 实时显示「已完成 X / 共 Y 项」的统计信息。
🎯 总结
通过 To-Do List 项目,你已经掌握了 JavaScript 最核心的三个概念:DOM 操作(选中、创建、插入、删除元素)、事件监听(click、keydown 等交互响应)、函数封装(将逻辑抽象为可复用的代码块)。这些都是构建任何 Web 应用的基础能力。接下来可以挑战更复杂的项目:计算器、计时器、天气查询等。记住,动手做项目是学习编程最快的方式 — 哪怕一开始代码不够优雅,只要跑起来就是胜利。