【新手必看】从零到一:HTML+CSS+JS 打造你的首个响应式待办清单(To-Do List)

张开发
2026/5/18 15:52:56 15 分钟阅读
【新手必看】从零到一:HTML+CSS+JS 打造你的首个响应式待办清单(To-Do List)
前言对于前端初学者来说看了再多的视频教程如果不亲手写一个项目永远无法理解“数据驱动”和“DOM 操作”的魅力。今天我们就用前端“三剑客”——HTML5、CSS3 和 JavaScript (ES6)从零开始构建一个既美观又实用的个人待办清单。这个项目不仅能帮你巩固基础还会涉及到前端开发中非常重要的**本地存储LocalStorage**概念让你的数据在刷新页面后依然存在1. 问题背景 / 需求说明作为新手我们经常面临以下困惑HTML 标签写了一堆但页面看起来还是很乱。CSS 的布局尤其是居中和对齐总是调不好。JavaScript 到底怎么跟 HTML 元素互动本项目目标实现任务的添加、删除、勾选完成。页面适配手机和电脑端响应式。即使关闭浏览器下次打开任务依然在持久化存储。2. 实现思路HTML (骨架)使用语义化标签定义输入框、按钮和任务列表容器。CSS (皮肤)利用 Flexbox 进行垂直居中布局通过transition实现丝滑的交互动画。JS (灵魂)监听按钮点击或回车事件。动态创建li标签并插入到ul中。将任务数组转化为 JSON 字符串存入localStorage。3. 操作步骤与完整代码第一步HTML 结构设计我们需要一个主容器.container内部包含标题、输入区域和列表区域。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title我的待办清单 - 简约版/title link relstylesheet hrefstyle.css /head body div classtodo-app h2待办事项 img src[https://cdn-icons-png.flaticon.com/512/4697/4697260.png](https://cdn-icons-png.flaticon.com/512/4697/4697260.png) width30/h2 div classinput-section input typetext idinput-box placeholder添加你的新任务... button onclickaddTask()添加/button /div ul idlist-container !-- 任务动态生成在此处 -- /ul /div script srcscript.js/script /body /html第二步CSS 样式美化这里使用了渐变背景和阴影让 UI 看起来更有“高级感”。注意.checked类的写法这是实现点击划线效果的关键。* { margin: 0; padding: 0; box-sizing: border-box; font-family: Poppins, sans-serif; } body { background: linear-gradient(135deg, #153677, #4e085f); min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 20px; } .todo-app { width: 100%; max-width: 540px; background: #fff; padding: 40px 30px 70px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); } h2 { color: #002765; display: flex; align-items: center; margin-bottom: 20px; } .input-section { display: flex; align-items: center; justify-content: space-between; background: #edeef0; border-radius: 30px; padding-left: 20px; margin-bottom: 25px; } input { flex: 1; border: none; outline: none; background: transparent; padding: 10px; font-size: 16px; } button { border: none; outline: none; padding: 16px 50px; background: #ff5945; color: #fff; font-size: 16px; cursor: pointer; border-radius: 40px; transition: background 0.3s; } button:hover { background: #e64e3a; } ul li { list-style: none; font-size: 17px; padding: 12px 8px 12px 50px; user-select: none; cursor: pointer; position: relative; transition: 0.2s; } /* 自定义选框图标使用伪元素 */ ul li::before { content: ; position: absolute; height: 28px; width: 28px; border-radius: 50%; border: 1px solid #ccc; left: 8px; top: 50%; transform: translateY(-50%); } /* 完成状态 */ ul li.checked { color: #555; text-decoration: line-through; } ul li.checked::before { background-color: #ff5945; border: none; } /* 删除按钮 */ ul li span { position: absolute; right: 0; top: 5px; width: 40px; height: 40px; font-size: 22px; color: #555; line-height: 40px; text-align: center; border-radius: 50%; } ul li span:hover { background: #edeef0; }第三步JavaScript 逻辑处理这是最核心的部分。我们通过监听click事件来判断用户是想“完成任务”还是“删除任务”。const inputBox document.getElementById(input-box); const listContainer document.getElementById(list-container); // 1. 添加任务函数 function addTask() { if (inputBox.value ) { alert(亲请输入一些内容哦); } else { let li document.createElement(li); li.innerHTML inputBox.value; listContainer.appendChild(li); // 添加删除叉叉 let span document.createElement(span); span.innerHTML \u00d7; // Unicode 乘号 li.appendChild(span); } inputBox.value ; saveData(); // 每次操作后保存数据 } // 2. 监听点击事件完成任务/删除任务 listContainer.addEventListener(click, function(e) { if (e.target.tagName LI) { e.target.classList.toggle(checked); saveData(); } else if (e.target.tagName SPAN) { e.target.parentElement.remove(); saveData(); } }, false); // 3. 本地存储保存数据 function saveData() { localStorage.setItem(data, listContainer.innerHTML); } // 4. 页面加载时读取数据 function showTask() { listContainer.innerHTML localStorage.getItem(data); } showTask();4. 运行效果与个人理解运行效果输入内容点击添加下方立刻出现带删除按钮的任务项。点击任务文字会有一个漂亮的划线效果和颜色变化。刷新页面后之前输入的任务依然整齐地排列在那里。完整项目代码参考为了方便大家“一键三连”直接运行这里给出整合后的代码参考!-- index.html 完整整合版 -- !DOCTYPE html html head meta nameviewport contentwidthdevice-width, initial-scale1.0 titleTo-Do List Project/title style /* 这里放入上面的 CSS 代码 */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: sans-serif; } body { background: #153677; display: flex; justify-content: center; align-items: center; min-height: 100vh; } .todo-app { width: 90%; max-width: 500px; background: #fff; padding: 30px; border-radius: 10px; } .input-section { display: flex; background: #edeef0; border-radius: 30px; margin-bottom: 20px; } input { flex: 1; border: none; outline: none; padding: 15px; background: transparent; } button { border: none; padding: 15px 30px; background: #ff5945; color: #fff; border-radius: 30px; cursor: pointer; } ul li { list-style: none; padding: 10px 40px; cursor: pointer; position: relative; } ul li.checked { text-decoration: line-through; color: #888; } ul li span { position: absolute; right: 0; top: 5px; width: 30px; height: 30px; text-align: center; } /style /head body div classtodo-app h2待办事项/h2 div classinput-section input typetext idinput-box placeholder添加任务... button onclickaddTask()添加/button /div ul idlist-container/ul /div script /* 这里放入上面的 JS 代码 */ const inputBox document.getElementById(input-box); const listContainer document.getElementById(list-container); function addTask() { if(inputBox.value ) return; let li document.createElement(li); li.innerHTML inputBox.value; let span document.createElement(span); span.innerHTML \u00d7; li.appendChild(span); listContainer.appendChild(li); inputBox.value ; saveData(); } listContainer.addEventListener(click, function(e){ if(e.target.tagName LI) e.target.classList.toggle(checked); else if(e.target.tagName SPAN) e.target.parentElement.remove(); saveData(); }); function saveData() { localStorage.setItem(data, listContainer.innerHTML); } function showTask() { listContainer.innerHTML localStorage.getItem(data) || ; } showTask(); /script /body /html个人感悟在写 JS 逻辑时我起初想给每个li都绑定点击事件后来发现这样性能很差。通过事件委托Event Delegation我只需要给外层的ul绑定一个监听器就能管理所有动态生成的li。这让我深刻理解了 DOM 事件流的机制。5. 常见问题 / 踩坑点回车无法提交新手常忘给 input 绑定键盘事件。建议改进监听keydown事件如果event.key Enter则调用addTask()。本地存储丢失localStorage只能存字符串。在这个 Demo 中我们直接存了innerHTML虽然方便但在大型项目中建议存储Array对象。移动端适配如果发现按钮在手机上太窄请检查 HTML 头部是否加了viewport元标签。6. 优化建议分类功能可以增加“已完成”和“进行中”的筛选按钮。编辑功能双击任务文字可以进行二次修改。美化加入动画库如 Animate.css让删除任务时有一个淡出效果。总结这个小小的待办清单虽然逻辑不复杂但它跑通了**“数据 - 视图 - 持久化”**的完整流程。作为新手不要怕报错多翻翻 MDN 文档。希望这篇教程能帮你开启前端开发的大门如果你觉得有用欢迎点赞、收藏、评论我们一起进步

更多文章