AI结对编程实战:用原生JavaScript构建待办清单应用

📅 2026/8/15 3:52:19
AI结对编程实战:用原生JavaScript构建待办清单应用
1. 项目概述从零到一让AI成为你的编程搭档如果你是一名刚接触前端开发的新手或者是一位想提升效率的熟手面对“用JavaScript写一个待办事项清单”这个看似简单的任务时可能还是会感到一丝迷茫从哪开始HTML结构怎么写JavaScript事件怎么绑定数据怎么存别担心这次我们换个玩法——让AI来当你的编程搭档。这不是一个关于AI取代程序员的恐怖故事而是一个关于如何利用AI工具如ChatGPT、Claude、Cursor等作为强大的辅助引导你高效、正确地完成第一个交互式Web项目的实践指南。我们将聚焦于JavaScript这个让网页“活”起来的语言通过构建一个功能完整的待办事项清单来亲身体验“AI结对编程”的魔力。你会发现AI不仅能帮你生成代码更能在这个过程中解释原理、提供优化思路甚至教你避坑让你在动手实现的同时真正理解每一行代码背后的逻辑。2. 核心思路与工具选型为什么是JavaScript与AI搭档在开始敲代码之前理清思路和选对工具至关重要。这个项目的目标是构建一个运行在浏览器端的、具有增删改查功能的待办事项清单。我们选择纯原生JavaScriptVanilla JS来实现而不是直接使用React、Vue等框架。原因有三第一对于初学者从原生JS入手能夯实DOM操作、事件处理等基础概念避免被框架的抽象层迷惑第二项目复杂度不高原生JS完全够用且更轻量第三在与AI协作时针对基础语法的提问和调试会更直接、准确。那么AI工具选谁目前主流的有ChatGPT、Claude、GitHub Copilot、Cursor等。对于这个项目我推荐使用ChatGPT或Claude的对话模式。因为它们擅长理解自然语言描述的需求并能给出详细的、带有解释的代码块。你可以这样开启对话“我想用原生JavaScript、HTML和CSS创建一个待办事项应用。请帮我规划一下需要哪些功能并给出基础的HTML结构。” 这种开放式提问能让AI为你搭建一个清晰的蓝图。核心思路拆解一个待办事项清单的本质是一个对任务项Item的集合进行管理的数据模型。每个任务项通常包含唯一ID、任务内容文本、完成状态。对应的操作就是创建添加、读取渲染列表、更新标记完成/未完成、编辑内容、删除移除。前端需要做的就是1. 用HTML提供输入和展示的界面2. 用CSS让界面美观3. 用JavaScript监听用户事件点击、回车操作DOM来更新界面并管理底层的数据数组。注意让AI写代码不等于完全不动脑。你的角色是“架构师”和“审查员”需要向AI清晰地描述需求并理解、验证它给出的每一段代码。这是学习的关键。2.1 定义项目功能范围与数据模型在让AI生成代码前你自己心里要有一份清晰的需求清单。这能帮助你更精准地向AI提问。一个基础的待办事项清单应包含以下功能添加任务通过输入框输入文本按回车或点击按钮添加。显示任务列表新添加的任务实时显示在列表中。标记任务完成/未完成点击任务前的复选框或直接点击任务文本切换完成状态通常伴有视觉变化如删除线。删除任务每个任务旁有一个删除按钮点击后移除该任务。数据持久化可选但推荐刷新页面后任务列表不丢失。这涉及到localStorage的使用。基于这些功能我们可以定义核心的数据结构。这是一个典型的由对象构成的数组。你可以这样向AI描述“请帮我设计一个用于存储待办事项的JavaScript数组结构。每个事项是一个对象应该包含id、text文本内容和completed完成状态。” AI可能会给出如下示例// 这是一个任务项的数据结构示例 let todos [ { id: 1, text: 学习JavaScript, completed: false }, { id: 2, text: 构建待办事项应用, completed: true }, // ... 更多任务 ];理解这个结构非常重要因为后续所有的JavaScript逻辑都将围绕操作这个todos数组展开。2.2 搭建基础的HTML与CSS骨架虽然AI可以一键生成完整的HTML但我建议分步进行。首先让AI生成一个最小可行的HTML结构。你可以提出如下请求“请为我生成一个待办事项清单的HTML骨架。需要一个标题h1一个输入框input和一个添加按钮button用于新增任务还需要一个无序列表ul作为任务列表的容器。请为关键元素加上有意义的id或class例如输入框id为‘todo-input’列表id为‘todo-list’。”AI生成的代码可能如下!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 classcontainer h1 我的待办清单/h1 div classinput-section input typetext idtodo-input placeholder输入新任务... button idadd-btn添加/button /div ul idtodo-list !-- 任务项将通过JavaScript动态添加到这里 -- /ul /div script srcscript.js/script /body /html拿到HTML后你可以继续让AI为它编写一份简洁美观的CSS。描述你的视觉需求“请为上面的HTML写一份CSS让容器居中输入框和按钮在一行任务列表清晰易读已完成的任务有删除线效果。” AI生成的CSS能立刻让你的页面像模像样。这一步的目的是快速获得一个可交互的界面原型将注意力集中在JavaScript逻辑上。3. 核心功能实现与AI协作编写JavaScript逻辑这是最核心的部分我们将分模块通过“提问-实现-理解”的循环让AI帮助我们完成JavaScript代码。3.1 模块一DOM元素获取与事件监听初始化一切交互的基础是获取到HTML中的元素并为它们绑定事件监听器。我们可以向AI提问“在script.js中我如何获取id为‘todo-input’的输入框、id为‘add-btn’的按钮和id为‘todo-list’的列表元素并如何为按钮添加点击事件监听为输入框添加键盘事件监听当按下回车时也触发添加”AI会给出类似下面的代码并附上解释// 获取DOM元素 const todoInput document.getElementById(todo-input); const addButton document.getElementById(add-btn); const todoList document.getElementById(todo-list); // 初始化任务数组尝试从本地存储加载 let todos JSON.parse(localStorage.getItem(todos)) || []; // 为添加按钮绑定点击事件 addButton.addEventListener(click, addTodo); // 为输入框绑定键盘事件回车键触发 todoInput.addEventListener(keypress, function(event) { if (event.key Enter) { addTodo(); } }); // 初始渲染一次列表 renderTodoList();这里有几个关键点需要你向AI追问或自行理解localStorage.getItem(todos)这是尝试从浏览器本地存储中读取之前保存的数据。JSON.parse用于将字符串转换回数组。如果之前没存过则返回null通过||操作符赋值为空数组[]。这是实现数据持久化的关键一步。addEventListener这是绑定事件的标准方法。注意addTodo是一个我们尚未定义的函数AI会提示你需要实现它。最后一行renderTodoList()这是一个渲染函数我们需要在初始化、添加、删除、更新任务后都调用它以更新界面。这体现了数据驱动的思想先修改数据todos数组再根据新数据重新渲染整个视图。3.2 模块二实现添加任务函数addTodo现在我们来实现核心的addTodo函数。向AI描述逻辑“请实现addTodo函数。它应该1. 获取输入框的值并去除首尾空格。2. 如果值为空则提示用户或直接返回。3. 如果不为空则创建一个新的任务对象包含自增id、文本和未完成状态将其push到todos数组中。4. 清空输入框。5. 调用renderTodoList重新渲染列表。6. 调用一个saveToLocalStorage函数稍后实现保存数据。”AI生成的函数可能如下function addTodo() { // 1. 获取并处理输入值 const todoText todoInput.value.trim(); // 2. 非空校验 if (todoText ) { alert(请输入任务内容); // 或者更友好的方式改变输入框边框颜色提示 // todoInput.style.borderColor red; // setTimeout(() { todoInput.style.borderColor ; }, 1000); return; } // 3. 创建新任务对象 const newTodo { id: Date.now(), // 使用时间戳作为唯一ID简单有效 text: todoText, completed: false }; // 4. 更新数据数组 todos.push(newTodo); // 5. 清空输入框 todoInput.value ; // 6. 保存到本地存储 saveToLocalStorage(); // 7. 重新渲染列表 renderTodoList(); }实操心得这里使用Date.now()生成ID是一个常见技巧因为它简单且几乎不可能重复对于此应用场景足够。你也可以让AI解释其他方案比如使用自增计数器。同时注意trim()方法的使用它能有效避免用户误输入空格导致创建空任务。3.3 模块三实现渲染函数renderTodoList渲染函数负责将todos数组中的数据“映射”为HTML列表项li并插入到ul中。这是一个典型的循环创建DOM元素的过程。询问AI“请实现renderTodoList函数。它应该1. 清空todoList容器的当前内容避免重复渲染。2. 遍历todos数组。3. 为每个todo对象创建一个li元素。4. li元素内部应包含一个复选框input type“checkbox”其checked状态与todo.completed绑定一个span显示todo.text一个删除按钮。5. 为复选框绑定change事件用于切换完成状态为删除按钮绑定click事件。6. 如果任务已完成为文本添加删除线样式例如通过一个‘completed’类。7. 最后将li添加到ul中。”AI可能会生成使用innerHTML或createElement的两种方案。我强烈推荐并让AI使用createElement方式因为它更安全避免XSS风险且更符合操作DOM的原生思维。以下是可能的结果function renderTodoList() { // 1. 清空现有列表 todoList.innerHTML ; // 2. 遍历todos数组 todos.forEach(todo { // 3. 创建li元素 const listItem document.createElement(li); listItem.setAttribute(data-id, todo.id); // 将id存储在data属性中便于查找 // 4. 创建复选框 const checkbox document.createElement(input); checkbox.type checkbox; checkbox.checked todo.completed; checkbox.addEventListener(change, () toggleTodo(todo.id)); // 绑定状态切换事件 // 5. 创建任务文本span const textSpan document.createElement(span); textSpan.textContent todo.text; if (todo.completed) { textSpan.classList.add(completed); // 添加完成样式类 } // 6. 创建删除按钮 const deleteButton document.createElement(button); deleteButton.textContent 删除; deleteButton.addEventListener(click, () deleteTodo(todo.id)); // 绑定删除事件 // 7. 将元素组装到li中 listItem.appendChild(checkbox); listItem.appendChild(textSpan); listItem.appendChild(deleteButton); // 8. 将li添加到ul中 todoList.appendChild(listItem); }); }注意事项这里我们为listItem添加了>function toggleTodo(id) { // 1. 查找对应任务 const todoIndex todos.findIndex(todo todo.id id); if (todoIndex -1) return; // 未找到直接返回 // 2. 切换完成状态 todos[todoIndex].completed !todos[todoIndex].completed; // 3. 保存并重新渲染 saveToLocalStorage(); renderTodoList(); }接着实现删除功能“请实现deleteTodo(id)函数。它接收一个任务id需要1. 确认是否删除使用confirm对话框。2. 如果用户确认则在todos数组中过滤掉filter该id对应的任务。3. 调用saveToLocalStorage保存。4. 调用renderTodoList重新渲染。”function deleteTodo(id) { // 1. 确认删除 const isConfirmed confirm(确定要删除这个任务吗); if (!isConfirmed) return; // 2. 过滤数组移除指定id的任务 todos todos.filter(todo todo.id ! id); // 3. 保存并重新渲染 saveToLocalStorage(); renderTodoList(); }常见问题这里findIndex和filter是处理数组的利器。findIndex找到特定条件的元素位置filter返回一个不包含特定元素的新数组。AI通常会很好地解释这些方法。如果你不理解一定要追问“请解释一下findIndex和filter方法在这里是如何工作的”3.5 模块五实现数据持久化saveToLocalStorage最后实现将数据保存到浏览器本地的功能。这个函数很简单“请实现saveToLocalStorage函数。它将todos数组转换为JSON字符串并使用localStorage.setItem保存到本地键名为‘todos’。”function saveToLocalStorage() { localStorage.setItem(todos, JSON.stringify(todos)); }原理说明localStorage只能存储字符串。JSON.stringify()方法将JavaScript对象或数组转换成JSON格式的字符串。反之在初始化时我们用JSON.parse()将字符串解析回数组。这就是整个持久化机制的基石。4. 功能增强与优化向AI提出进阶需求基础功能完成后你可以继续与AI合作为应用添加更多实用功能这能极大提升你的学习深度。4.1 添加任务计数与筛选功能你可以向AI提出“我想在页面顶部显示总任务数和未完成任务数。还想添加三个按钮‘全部’、‘未完成’、‘已完成’点击可以筛选显示对应的任务列表。请指导我如何修改代码。”AI会引导你在HTML中添加用于显示计数的元素如span idtodo-count和三个筛选按钮。在JavaScript中新增一个状态变量如let filter all;。修改renderTodoList函数使其在渲染前先根据filter状态对todos数组进行筛选filter方法。创建一个updateCounter函数计算并更新页面上的任务计数。为三个筛选按钮绑定点击事件改变filter变量并重新调用renderTodoList和updateCounter。这个过程会涉及更复杂的数组方法和状态管理是绝佳的学习机会。4.2 实现任务文本的编辑功能双击任务文本即可编辑这是一个提升用户体验的常见功能。向AI描述“我希望能够双击某个任务的文本来编辑它。双击后文本变成一个输入框编辑完成后按回车或失去焦点时保存修改。”AI的实现思路通常会包括在renderTodoList中为textSpan添加ondblclick双击事件监听。事件触发时将textSpan替换为一个input输入框其值为原文本。为这个输入框绑定blur失去焦点和keypress回车键事件。事件处理函数中获取新文本更新对应todo对象的text属性然后保存并重新渲染。这个功能会让你深入理解动态DOM操作和事件委托为避免为每个元素单独绑定可在父级监听。4.3 优化CSS与交互反馈你可以让AI为你的应用生成更现代、响应式的CSS比如加入Flexbox布局、CSS Grid、平滑过渡动画等。也可以要求AI为交互添加更友好的反馈例如添加任务时输入框有轻微的抖动动画提示成功。删除任务时项目先淡出再被移除。标记完成时复选框有一个勾选动画。通过描述这些视觉需求AI可以生成对应的CSS关键帧动画或过渡代码让你学习前端动效的基础。5. 调试、优化与常见问题排查即使有AI帮助代码也难免出错。学会调试和排查问题是程序员的核心能力。5.1 利用浏览器开发者工具这是你最好的朋友。打开Chrome的开发者工具F12Console控制台查看AI生成的代码是否有语法错误SyntaxError、运行时错误ReferenceError等。所有console.log()的输出都在这里。你可以在关键步骤添加console.log(todos)来打印数据状态这是最直接的调试手段。Elements元素查看DOM树是否按预期生成。可以检查动态创建的li元素是否被正确添加>问题现象可能原因解决方案点击按钮/回车无反应1. DOM元素获取失败id拼写错误2. 事件监听器绑定在了错误的位置或时机脚本在DOM加载前执行1. 检查getElementById的参数与HTML中的id是否完全一致。2. 将script标签放在body末尾或使用DOMContentLoaded事件包裹代码。任务重复渲染renderTodoList函数在每次调用时没有先清空容器innerHTML ‘’确保renderTodoList的第一行是todoList.innerHTML ‘’;。删除或切换状态错乱事件处理函数中获取的任务ID不对或查找数组元素逻辑有误检查是否为每个li正确设置了>本地存储不工作1.localStorage键名不一致2. 数据格式错误不是JSON字符串3. 浏览器隐私模式或设置禁用1. 确保setItem和getItem使用相同的键名。2. 使用JSON.stringify存JSON.parse取并用try…catch包裹parse以防错误数据。3. 在普通浏览模式下测试。双击编辑后输入框无法正常保存事件冒泡导致或编辑状态下的输入框事件与全局输入框事件冲突在编辑状态下可以考虑暂时禁用全局的回车添加事件。使用event.stopPropagation()防止事件冒泡。仔细检查编辑模式下输入框的blur和keypress事件逻辑。5.4 代码优化与最佳实践建议在项目基本完成后你可以让AI从代码质量和性能角度给出优化建议。例如提问“请评审我上面这份待办事项的JavaScript代码有哪些可以优化的地方比如性能、可读性或者潜在bug。”AI可能会给出如下建议减少DOM操作频繁调用renderTodoList会重绘整个列表。对于单一任务的增删改可以尝试只更新对应的li元素而不是全部重绘。但对于初学者项目当前方式更清晰易懂性能影响可忽略。使用事件委托可以为整个todoListul元素绑定一个点击事件监听器然后根据event.target来判断点击的是复选框还是删除按钮。这样可以避免为每个动态创建的子元素单独绑定事件性能更好代码更简洁。你可以让AI帮你重构这部分代码。防抖Debounce如果未来添加了实时搜索过滤输入框可以使用防抖技术来避免频繁触发过滤函数。模块化将不同的功能函数数据操作、DOM渲染、事件处理组织得更清晰甚至用ES6模块来拆分文件提高代码可维护性。通过这个完整的“AI辅助编程”流程你不仅得到了一个可运行的待办事项应用更重要的是你以实践的方式学习了原生JavaScript的核心概念DOM操作、事件处理、数组方法、数据持久化并且初步体验了如何将一个产品需求分解为具体的代码模块以及如何与AI工具进行有效沟通来辅助学习和开发。下次当你遇到新的编程想法时就知道如何让AI成为你的得力助手了。