1 分钟

一步步构建简单待办应用(通俗易懂)

一份清晰的逐步指南,教你构建一个小型待办应用:规划功能、创建界面、添加逻辑、保存数据、测试并发布。

一步步构建简单待办应用(通俗易懂)

我们要做什么(以及你会学到什么)

在本指南里,当我说“应用”时,我指的是一个小型的网页应用:在浏览器中打开的单页,能响应你的点击和输入。不需要安装、不需要账户、也不需要复杂的设置——只是一个能在本地运行的小项目。

目标(完成后的功能)

到最后,你会得到一个待办应用,它可以:

  • 添加任务:从输入框添加任务
  • 标记任务为已完成(这样你可以看出哪些已完成)
  • 删除任务:移除不需要的任务
  • 在刷新后保留任务,使用 localStorage(这样关闭标签页不会丢失内容)

它不会很完美或“企业级”,这正是目的:这是为初学者设计的项目,教你基础知识而不会丢给你太多工具。

你会学到什么(通俗说明)

你将一步一步构建这个应用,并掌握前端网页应用的核心部分:

  • HTML:创建页面结构(输入、按钮、列表)
  • CSS:让界面可读且好用
  • JavaScript:处理点击、创建列表项并更新页面
  • localStorage:保存并加载任务,让它们持久化
  • 基本的测试与调试(发现小错误并修复)

开始前你需要准备的东西

保持简单。你只需要:

  • 一台电脑(Windows、Mac 或 Linux)
  • 一个现代浏览器(Chrome、Firefox、Safari 或 Edge)
  • 一个代码编辑器(VS Code 很受欢迎,但任何编辑器都可以)

如果你能创建文件夹并编辑几个文件,就可以开始了。

第 1 步:确定应用目标与功能

在写任何代码之前,先决定什么才算“成功”。本教程只做一个小应用、一个明确的工作:帮你跟踪你想做的任务。

选定应用的主要目标

写一句话的目标,构建时随手可见:

“这个应用让我把任务添加到列表里,以免忘记。”

就是这样。如果你想加日历、提醒、标签或账户功能,把它们先放到以后再做。

必须有 vs 可选功能

快速列两份清单:

必须有(本项目):

  • 添加任务(输入文字,点击按钮)
  • 在列表中查看任务
  • 标记任务为已完成
  • 删除任务
  • 在刷新后保留任务(稍后我们会用 localStorage)

可选(今天不需要):到期日、优先级、分类、搜索、拖放、云同步。

把“必须有”控制在小范围内能帮助你真正完成项目。

用通俗的话描述界面

这个应用可以是单页,包含:

  • 一个文本输入(“添加任务…”)和一个“添加”按钮
  • 下方的任务列表
  • 每个任务有一个“完成”切换和一个“删除”按钮

定义“已完成”是什么意思

明确一点,避免卡住:

  • “已完成” = 任务看起来被划掉(或变淡),并且在被删除之前它仍保留在列表中。

决定后,就可以设置项目文件了。

第 2 步:搭建项目文件

在写任何代码之前,先为应用创建一个干净的小“家”。从一开始就整理好文件会让后面的步骤更顺利。

1)创建项目文件夹

在电脑上新建一个文件夹,取名如 todo-app。这个文件夹会存放项目的所有内容。

在该文件夹中创建三个文件:

  • index.html(页面结构)
  • styles.css(外观与布局)
  • app.js(行为与交互)

如果你的系统隐藏文件扩展名(比如“.html”),确认你真的是创建了 index.html,常见的初学者错误是最后变成了 index.html.txt。

2)在编辑器和浏览器中打开文件夹

在代码编辑器(VS Code、Sublime Text 等)中打开 todo-app 文件夹,然后在浏览器中打开 index.html。

此时页面可能是空白的——没关系,下一步我们会添加内容。

3)如何查看修改效果

编辑文件时,浏览器不会自动更新(除非你使用自动刷新工具)。

基本流程是:

  1. 在编辑器保存文件
  2. 切到浏览器页签
  3. 刷新页面查看更新

如果出现“没反应”的情况,先尝试刷新。

可选:使用本地服务器(推荐但非必须)

你也可以通过本地服务器打开页面,这能避免一些后续的奇怪问题(尤其是开始保存数据或加载文件时)。

适合初学者的选项:

  • 在 VS Code 安装 Live Server,然后点击 “Go Live”
  • 如果电脑上已安装 Python,在项目文件夹中运行:
python -m http.server

然后在浏览器中打开它打印的地址(通常是 http://localhost:8000)。

第 3 步:构建页面结构(HTML)

现在我们来做一个干净的骨架。这个 HTML 不会让页面变得“可交互”(交互是下一步的事),但它会为你的 JavaScript 提供清晰的读写位置。

我们需要的最小布局

包括:

  • 一个标题,让页面一目了然
  • 一个输入框用于任务文本
  • 一个添加按钮用以提交任务
  • 一个列表区域,用来显示新增任务

使用简单且可读的名称。良好的 id/class 会让后面 JavaScript 通过名称获取元素时更方便。

将下面内容粘到你的 index.html 中

\u003c!doctype html\u003e
\u003chtml lang=\"en\"\u003e
  \u003chead\u003e
    \u003cmeta charset=\"utf-8\" /\u003e
    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /\u003e
    \u003ctitle\u003eTo‑Do App\u003c/title\u003e
    \u003clink rel=\"stylesheet\" href=\"styles.css\" /\u003e
  \u003c/head\u003e
  \u003cbody\u003e
    \u003cmain class=\"app\" id=\"app\"\u003e
      \u003ch1 class=\"app__title\" id=\"appTitle\"\u003eMy To‑Do List\u003c/h1\u003e

      \u003cform class=\"task-form\" id=\"taskForm\"\u003e
        \u003clabel class=\"task-form__label\" for=\"taskInput\"\u003eNew task\u003c/label\u003e
        \u003cdiv class=\"task-form__row\"\u003e
          \u003cinput
            id=\"taskInput\"
            class=\"task-form__input\"
            type=\"text\"
            placeholder=\"e.g., Buy milk\"
            autocomplete=\"off\"
          /\u003e
          \u003cbutton id=\"addButton\" class=\"task-form__button\" type=\"submit\"\u003e
            Add
          \u003c/button\u003e
        \u003c/div\u003e
      \u003c/form\u003e

      \u003cul class=\"task-list\" id=\"taskList\" aria-label=\"Task list\"\u003e\u003c/ul\u003e
    \u003c/main\u003e

    \u003cscript src=\"app.js\"\u003e\u003c/script\u003e
  \u003c/body\u003e
\u003c/html\u003e

结构就这些。注意我们用了 id="taskInput" 和 id="taskList"——这两个元素将会在 JavaScript 中频繁使用。

第 4 步:做点样式让界面更清爽(CSS)

现在页面存在了,但可能看起来像一份普通文档。简单的 CSS 会让它更好用:间距更清晰、文字可读、按钮更像可点击的元素。

从一个居中的容器开始

居中的框能让应用更集中,防止内容在宽屏上拉得太开。

/* Basic page setup */
body {
  font-family: Arial, sans-serif;
  background: #f6f7fb;
  margin: 0;
  padding: 24px;
}

/* Centered app container */
.container {
  max-width: 520px;
  margin: 0 auto;
  background: #ffffff;
  padding: 16px;
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
}

让任务便于扫视

每个任务应该看起来像独立的一行,间距舒适。

ul { list-style: none; padding: 0; margin: 16px 0 0; }

li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid #e7e7ee;
  border-radius: 8px;
  margin-bottom: 10px;
}

.task-text { flex: 1; }

添加清晰的“已完成”样式

当任务完成时,应有明显的视觉变化,便于一眼识别。

.done .task-text {
  text-decoration: line-through;
  color: #777;
  opacity: 0.85;
}

按钮风格一致

保持按钮尺寸与样式一致,会让它们看起来像同一个应用的一部分。

button {
  border: none;
  border-radius: 8px;
  padding: 8px 10px;
  cursor: pointer;
}

button:hover { filter: brightness(0.95); }

这就足够让 UI 干净友好了——不需要花哨技巧。接下来我们用 JavaScript 接上交互。

第 5 步:添加任务(JavaScript 基础)

放心试验
在重大改动前保存可用版本,必要时可回滚。

既然页面上有输入框、按钮和列表,我们就需要让它们“动”起来。目标很简单:当有人输入任务并点击 Add(或按 Enter)时,列表里出现新项。

绑定按钮和 Enter 键

在你的 JavaScript 文件中,先获取需要的元素,然后监听两种动作:按钮点击和输入框内的 Enter。

const taskInput = document.querySelector('#taskInput');
const addBtn = document.querySelector('#addBtn');
const taskList = document.querySelector('#taskList');

function addTask() {
  const text = taskInput.value.trim();

  // Block empty tasks (including ones that are just spaces)
  if (text === '') return;

  const li = document.createElement('li');
  li.textContent = text;
  taskList.appendChild(li);

  // Clear the input and put the cursor back
  taskInput.value = '';
  taskInput.focus();
}

addBtn.addEventListener('click', addTask);

taskInput.addEventListener('keydown', (event) => {
  if (event.key === 'Enter') {
    addTask();
  }
});

这段代码做了什么(通俗说明)

  • 读取输入框里的文本并用 trim() 去掉首尾多余空格。
  • 如果是空文本就阻止添加,避免出现空项。
  • 创建一个新的 <li>,设置它的文本并加入列表中。
  • 清空输入框并把焦点放回输入框,方便快速继续输入下一个任务。

如果没有反应,先检查 HTML 中的元素 id 是否与 JavaScript 里的选择器完全对应(这是初学者常踩的坑)。

第 6 步:标记完成与删除任务

现在你可以添加任务了,接下来让任务可操作:可以标记为已完成,也可以删除它们。

将任务存成简单的数据结构

不要只把任务当字符串保存,用对象更灵活。这样每个任务都有稳定的身份和“已完成”状态:

  • text:任务内容
  • done:true 或 false
  • id:唯一编号,用来定位或删除特定任务

示例:

let tasks = [
  { id: 1, text: "Buy milk", done: false },
  { id: 2, text: "Email Sam", done: true }
];

添加“完成”控件和删除按钮

渲染每个任务时,包含一个复选框或“完成”按钮,以及一个“删除”按钮。

事件监听器(event listener)就是用来响应点击的。你把监听器挂到按钮(或整个列表容器)上,当用户点击时,对应的代码就会运行。

对初学者友好的做法是使用事件委托:在任务列表容器上放一个点击监听器,然后根据被点击的元素判断操作。

function toggleDone(id) {
  tasks = tasks.map(t => t.id === id ? { ...t, done: !t.done } : t);
  renderTasks();
}

function deleteTask(id) {
  tasks = tasks.filter(t => t.id !== id);
  renderTasks();
}

document.querySelector("#taskList").addEventListener("click", (e) => {
  const id = Number(e.target.dataset.id);
  if (e.target.matches(".toggle")) toggleDone(id);
  if (e.target.matches(".delete")) deleteTask(id);
});

在你的 renderTasks() 函数中:

  • 给每个按钮加上 data-id="${task.id}"。
  • 用 .done 类来在视觉上标注已完成的任务。

第 7 步:保存任务以便持久化(localStorage)

现在你的待办清单有个烦恼:刷新页面或关闭标签页后,所有内容都消失了。

原因是任务只存在于 JavaScript 的内存里,页面重载后内存会被清空。

localStorage = 浏览器内一个小“储物箱”

localStorage 内置于浏览器。把它想象成一个可以按键(key)存放文本的小盒子。它适合初学者项目,因为不需要服务器或账号系统。

我们会把整个任务数组转为 JSON 文本保存,然后在页面打开时再读回来。

1)每次变更后保存

每当你添加、标记完成或删除任务时,都调用 saveTasks()。

const STORAGE_KEY = "todo.tasks";

function saveTasks(tasks) {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(tasks));
}

无论何处更新了 tasks 数组,紧接着执行:

saveTasks(tasks);
renderTasks(tasks);

2)页面启动时加载并渲染

页面加载时读取保存的值。如果没有保存过,就回退到空数组。

function loadTasks() {
  const saved = localStorage.getItem(STORAGE_KEY);
  return saved ? JSON.parse(saved) : [];
}

let tasks = loadTasks();
renderTasks(tasks);

就这样:你的应用现在能在刷新后记住任务。

提示:localStorage 只能存字符串,所以用 JSON.stringify() 把数组变成文本,用 JSON.parse() 在读取时再把文本变回数组。

第 8 步:测试并修复常见错误

让它更像真实产品
准备展示时,为你的应用设置自定义域名。

测试听起来无聊,但它是把你的待办应用从“在我机器上能用”变成“在任何时候都能用”的最快方法。在每次小改动后做一次快速检查。

快速测试流程(60 秒)

按下面顺序试一遍主要流程:

  • 添加一个任务
  • 标记为完成
  • 删除它
  • 刷新页面(确认 UI 行为仍正确)

如果某一步出问题,先修复再做新功能。把问题堆在一起会让小应用变得难以维护。

常见会搞坏初学者应用的边界情况

边界情况是你没有特意设计但用户会做的操作:

  • 很长的文本(会不会溢出或把按钮挤走?)
  • 重复任务(你是否删除了正确的那个?)
  • 空输入(会不会添加空任务?)

常见的解决是阻止空任务:

const text = input.value.trim();
addButton.disabled = text === "";

(可以在每次 input 事件时执行,也可以在添加前再次检查。)

快速排查“没有反应”的清单

当点击没有反应,通常是因为:

  • 选择器不匹配(HTML 的 id/class 与 JS 不一致)
  • 脚本未加载(文件名/路径错误,或 app.js 找不到)
  • 有 JavaScript 错误阻止了后面的代码执行

用控制台查看实际发生了什么

当问题看起来随机时,打日志:

console.log("Adding:", text);
console.log("Current tasks:", tasks);

在浏览器的 Console 查看错误(红色文字)。问题解决后记得删掉这些日志,避免把项目搞得杂乱。

第 9 步:提升可用性(无障碍与移动端)

当一个待办应用“完成”的标准之一是:在手机上、用键盘以及使用无障碍工具(如屏幕朗读器)时都让人感觉舒适。

让移动端易于点击

在小屏幕上,太小的按钮会让人很烦。确保可点击元素有足够空间:

  • 按钮使用更大的内边距(高度目标约 44px)
  • 完成 与 删除 按钮之间留出间距,避免误触
  • 在移动端让输入框占满宽度,打字更自然

在 CSS 中,增加 padding、font-size 与 gap 经常能带来明显改善。

添加标签与 ARIA(是什么与为什么)

屏幕朗读器需要清晰的控件名字:

  • 文本输入应有真实的 <label>(这是最佳做法)。如果你不想显示它,可以用 CSS 将其视觉隐藏,但保留在 HTML 中。
  • 仅靠图标的按钮(比如垃圾桶图标)应包含 aria-label="Delete task",这样屏幕朗读器不会只读出“按钮”而没有上下文。

这能帮助使用辅助工具的人理解每个控件的作用。

键盘支持:Tab + Enter

确保可以不靠鼠标也能操作应用:

  • 使用 Tab 能切到输入框和按钮
  • 在输入框按 Enter 应该能添加任务(使用 <form> 可以让 Enter 自然工作)
  • 添加任务后考虑把焦点返回到输入框,方便连续添加

可读性:对比度与字体大小

使用可读的字体大小(16px 是个好基线)和充足的颜色对比(深色文字配浅背景或反之)。不要只用颜色来表示“已完成”这一状态——加上线穿或其他明确样式更好。

第 10 步:整理与优化代码

添加简单后端
描述你的任务端点,让 Koder.ai 生成 Go API 和数据库。

功能都实现后,花 10–15 分钟把代码整理一下,这会让未来的修复更容易,也让你下次回来时更容易理解自己的项目。

简单的文件结构

保持小而可预测:

  • /index.html — 页面结构(输入、按钮、列表)
  • /styles.css — 界面样式(间距、字体、已完成样式)
  • /app.js — 行为(添加、切换完成、删除、保存/加载)
  • /README.md — 给“未来的你”的快速说明

如果你喜欢子文件夹,也可以:

  • /css/styles.css
  • /js/app.js

只要确保你的 <link> 和 <script> 路径一致。

让 JavaScript 更易读

几个快速改进:

  • 用清晰的名字:taskInput、taskList、saveTasks()
  • 保持函数短小:每个函数只做一件事
  • 仅在代码不明显时添加简短注释(避免每行都注释)

例如,以下一目了然:

  • renderTasks(tasks)
  • addTask(text)
  • toggleTask(id)
  • deleteTask(id)

添加简短的 README

你的 README.md 可以很简单:

  • 功能说明(一句:一个会保存任务的待办列表)
  • 如何运行(在浏览器中打开 index.html)
  • 可选:已知的限制

备份你的项目

至少在完成一个里程碑后压缩备份一次(例如“localStorage 生效”时)。如果想要版本历史,Git 很好用,但不是必须。哪怕一份备份也能防止误删造成的损失。

第 11 步:发布并分享你的应用

发布就是把应用文件(HTML、CSS、JavaScript)放到互联网上,让别人打开链接就能使用。由于这个待办应用是静态站点(在浏览器运行,不需要服务器),你可以免费托管在多个服务上。

选项 1:GitHub Pages(适合静态站点)

大致步骤:

  1. 注册 GitHub(如果还没有)
  2. 新建仓库并上传文件(或用 Git 推送)
  3. 在仓库的 Settings → Pages 中设置
  4. 选择要发布的分支(通常是 main)和文件夹(通常是根目录 /)
  5. 保存后,GitHub 会给你一个公开的 URL

如果有多个文件,记得检查文件名与引用是否完全一致(例如 styles.css 与 style.css 的区别)。

选项 2:Netlify 或 Vercel(拖拽式更简单)

如果你想最省事的“上传并使用”方式:

  1. 在 Netlify 或 Vercel 注册账号
  2. 找到 Deploy / Add New Project
  3. 把项目文件夹拖放上去(或连接 GitHub 仓库)
  4. 等待上传/构建完成
  5. 打开生成的 URL 并测试

分享前的快速检查清单

  • 刷新页面:任务仍然保留(localStorage 生效)
  • 添加、完成与删除任务:没有坏掉的按钮
  • 在手机上打开(或缩小浏览器窗口):没有溢出的内容

通过这些检查后,把链接发给朋友,让他们试一试——新鲜的眼睛常能发现问题。

后续可尝试的简单升级

你已经做出了一个可用的待办应用。如果想在不跳跃到巨型项目的情况下继续学习,这些升级既实用又能教到额外的模式。

1)编辑任务文本

给每个任务加一个“编辑”按钮。点击时把任务标签替换成一个小的输入框(预填当前文本),并显示“保存/取消”按钮。

提示:保持任务数据为带 id 和 text 的对象。编辑时就是按 id 找到任务、更新 text、重新渲染并保存。

2)筛选:全部 / 未完成 / 已完成

在顶部加三个按钮:All、Active、Done。

把当前过滤器存在变量里,例如 currentFilter = 'all'。渲染时根据过滤器显示:

  • All:所有任务
  • Active:未完成任务
  • Done:已完成任务

3)到期日或简单分类

保持轻量:

  • 加一个可选的到期日(格式 YYYY-MM-DD),并显示在任务旁边
  • 或用下拉菜单加一个“Work / Home / School”之类的分类

哪怕只加一个字段,也能教你如何同时更新数据模型和界面。

4)进阶:从 localStorage 迁移到简单后端

当你准备好了,核心思路是:不再把任务保存到 localStorage,而是通过 fetch() 发送到 API(服务器)。服务器把它存到数据库,这样不同设备间就能同步任务。

如果你想在不重写全部代码的情况下尝试这个跳跃,一些生成/原型平台可以帮你快速试错并导出代码。

5)下一个适合初学者的项目

试试做一个笔记应用(带搜索)或一个习惯追踪器(每日打卡)。它们复用相同技能:列表渲染、编辑、保存与基础 UI 设计。

常见问题

构建这个待办应用需要什么?

你只需要一台电脑、现代浏览器和代码编辑器。创建一个文件夹,包含 index.html、styles.css 和 app.js,然后在浏览器中打开 HTML 文件。

适合初学者的待办应用应包含哪些功能?

先实现四个操作:添加任务、在列表中查看任务、将任务标记为完成,以及删除任务。截止日期、分类和账户等附加功能可以以后再加。

项目中的每个文件分别做什么?

HTML 用于创建输入框、按钮和任务列表。CSS 控制间距和外观。JavaScript 读取用户操作、更新列表并保存任务数据。

如何防止添加空白任务?

使用包含文本输入框和提交按钮的表单。JavaScript 应去除输入值两端的空白,拒绝空结果,创建列表项,然后清空输入框并让它重新获得焦点。

为什么任务应使用对象而不是纯文本?

使用包含 id、text 和 done 值的任务对象。即使两个任务的文本相同,ID 也能让代码更新或删除准确的那个任务。

如何将任务标记为已完成?

为每个任务添加复选框或“完成”按钮。用户点击后,修改该任务的 done 值,并添加一个 CSS 类来应用删除线或淡化样式。

应用如何在刷新后记住任务?

使用 JSON.stringify() 将任务数组存储在 localStorage 的一个名称下,并在页面启动时用 JSON.parse() 读取。添加、完成、编辑或删除任务后,都要再次保存。

为什么我的“添加”按钮没有任何反应?

先刷新页面,并打开浏览器控制台查看红色错误信息。然后检查 HTML ID 是否与 JavaScript 选择器匹配,以及脚本文件名是否与 index.html 中的路径一致。

如何让应用在手机上和使用键盘时更易用?

为任务输入框使用真正的标签,确保控件足够大,方便点击,并用 Tab 和 Enter 测试应用。已完成的任务不应只靠颜色区分,还应使用删除线和清晰的文本等提示。

发布待办应用前应测试什么?

测试添加任务、将其标记为完成、删除任务以及刷新页面。分享应用前,还要尝试空输入、较长的任务名称和重复的任务文本。

Related posts