← 返回首页 / JavaScript 入门项目

⚡ JavaScript 入门小项目:To-Do List

没有什么比动手做一个真实项目更能学会 JavaScript 了。本教程带你从零开始,用纯 JavaScript 构建一个功能完整的待办事项应用(To-Do List),在实战中掌握变量、函数、DOM 操作、事件处理和数组方法等核心概念。

JavaScript · DOM 操作 · 事件处理

🧪 在线演示 — 试试这个 To-Do List

💡 点击复选框标记完成,点击 ✕ 删除

🧠 为什么要从项目学 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 结构的关键是给需要操作的元素加上 idclass,这样 JavaScript 才能准确找到它们。这里 todoInputaddTodoBtn 用 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 之后,可以尝试以下扩展来巩固所学:

🎯 总结

通过 To-Do List 项目,你已经掌握了 JavaScript 最核心的三个概念:DOM 操作(选中、创建、插入、删除元素)、事件监听(click、keydown 等交互响应)、函数封装(将逻辑抽象为可复用的代码块)。这些都是构建任何 Web 应用的基础能力。接下来可以挑战更复杂的项目:计算器、计时器、天气查询等。记住,动手做项目是学习编程最快的方式 — 哪怕一开始代码不够优雅,只要跑起来就是胜利。

← 返回所有教程