AI实战:用AI实现前端功能增强的实践分享

两个真实案例,一个"需求清晰但技术水深",一个"需求清晰且落地顺畅"——从中窥见AI辅助开发的真实面貌。

引言

在前端开发的日常工作中,我们经常遇到两类需求:一类看似简单,做着做着才发现深处有暗礁;另一类需求清晰明确,只需要高效落地。这两类需求恰好代表了AI辅助开发中最典型的两种协作模式。

本文分享两个真实的AI辅助开发案例:Sheet界面关闭时的自动保存文件上传新增复制粘贴功能。两个案例都发生在同一个企业级前端项目中(基于Vue 3 + SpreadJS + Element Plus),前者经历了方案迭代、深度Debug、多轮人机协作,后者则是AI快速定位、一次性落地、自动补测试的流畅体验。

通过这两个案例的对比,希望能让读者看到AI辅助开发的真实能力边界——它既不是万能的银弹,也远不止简单的代码补全。


案例一:Sheet界面关闭时的自动保存

需求起点:一个"简单"的想法

最初的需求很朴素:Sheet界面关闭时,提醒用户保存。就像Word文档关闭前的"是否保存更改"一样,看起来是个再常见不过的功能。

我向AI描述了这个需求,AI的第一反应并不是直接给代码,而是先区分了两种"关闭"场景:

  • 应用内关闭(关闭tab、切路由、关弹窗):可以完整实现"确认→保存→关闭"的流程
  • 浏览器直接关页/刷新:受限于beforeunload机制,只能做到"提醒",不能可靠地在关闭前完成异步保存

AI还主动分析了项目现有代码,发现脏数据标记已经在记录了(SpreadJS的ValueChanged事件会写入valueChangedData),只是还没有接上关闭拦截。这种"先摸清家底,再出方案"的做法,避免了从零开始的浪费。

方案演进:从不可靠到可靠

需求的演进过程非常有意思:

第一轮:浏览器beforeunload提醒

AI指出当前项目的保存链路很"重"——需要从SpreadJS导出JSON → 生成zip → 包成FormData → 调接口上传。这种重量级操作放在beforeunload里完全不可靠:浏览器不会等你的await跑完就直接关页了。

所以最初落地的是"原生弹窗提醒"方案:有未保存内容时,浏览器弹原生提示,但不指望在关闭瞬间完成保存。

第二轮:30秒防抖服务端自动保存

为了真正"防丢数据",AI建议加入编辑后30秒防抖自动保存。逻辑是:用户停止编辑30秒后,静默调用saveOperateHandle({ silent: true }),将数据保存到服务端。

实现后我发现体验并不理想

  • 如果用户在30秒内关闭了页面,数据还是丢
  • 每次自动保存都要走一遍zip压缩+接口上传,资源消耗不小
  • 用户完全感知不到"已经保存了"

第三轮:IndexedDB浏览器草稿缓存

我跟AI说"30秒保存好像没什么用,能不能缓存到浏览器?"AI立刻给出了对比分析:

方案 防误关能力 实现成本
30s服务端自动保存 弱(30s窗口内丢失) 已有
IndexedDB本地草稿 强(2-5s防抖写入) 中等

最终方案变成了:

  • 编辑后3秒防抖写入IndexedDB(比等30秒服务端保存快得多)
  • 再次打开页面时,检测本地草稿是否比服务端新,弹窗让用户选择"恢复草稿"或"丢弃"
  • 手动保存成功后清除本地草稿

第四轮:移除beforeunload提醒

有了草稿缓存后,我发现每次刷新页面都弹原生提示反而很烦。AI分析后也认同这个判断——beforeunload无法区分"刷新"和"关闭",而草稿缓存已经覆盖了绝大部分场景(除了编辑后3秒内极端关闭的情况),弹窗的价值已经很低。

最终方案变成了:纯草稿缓存兜底,无弹窗干扰,体验最为流畅。

深度Debug:假设-埋点-验证方法论

方案设计很顺利,但真正的挑战来自运行时。实现完成后,我发现编辑内容后并没有自动缓存生效——这开启了一段精彩的Debug过程。

第一个Bug:Vue 3响应式失效

AI在HomeView.vue中用watch监听valueChangedData对象的key数量变化来触发自动保存。但实际运行时,Console中完全没有出现watch触发的日志。

AI提出了四个假设(H-A到H-D),其中最关键的H-C假设是:watch监听的值从未变化

通过我在浏览器DevTools中看到的日志确认了这个假设后,AI深入追踪了完整的数据流链路,最终发现了一个典型的Vue 3响应式陷阱

editValueChangedData → toRaw() 取出原始对象 → 在raw上写数据 → Object.assign(reactiveProxy, rawObject)

问题在于:toRaw()取到的原始对象被直接修改后,传给Object.assign时,Vue的set拦截器发现key已存在且值引用未变(hasChanged(sameRef, sameRef) = false),于是不触发响应式更新,watch永远不执行。

修复方案非常精巧:在store中加一个版本号计数器,每次setValueChangedData被调用时递增,watch改为监听这个版本号。零侵入现有数据逻辑,只增加一个触发信号。

第二个Bug:IndexedDB序列化失败

修复第一个问题后,草稿保存流程能触发了,但Console中出现了新错误:

DataCloneError: Failed to execute 'put' on 'IDBObjectStore': 
function toString() { [native code] } could not be cloned.

根因是SpreadJS的spread.toJSON()方法返回的对象内部包含native function引用。IndexedDB使用结构化克隆算法存储数据,该算法无法序列化函数类型。

修复同样简洁:写入IndexedDB之前,先用JSON.parse(JSON.stringify(spreadJson))做一次JSON round-trip,自动去除所有不可序列化的字段(函数引用、undefined等),得到纯数据对象。

人机协作的关键模式

回顾这个案例的Debug过程,人和AI的分工非常清晰:

  • AI的角色:建立假设矩阵、设计埋点方案、分析日志输出、定位根因、给出修复代码
  • 人的角色:在浏览器中执行操作、观察Console日志、将运行时信息反馈给AI

关键点在于:给AI提供精准的运行时信息。当我把完整的Console日志(包括错误堆栈)粘贴给AI时,它能在几秒钟内定位到DataCloneError的确切原因。如果我只描述"保存失败了",排查效率会大打折扣。


案例二:文件上传新增复制粘贴功能

需求一句话说清

需求很直接:在附件上传对话框中,添加文件拖拽和Ctrl+V粘贴功能。这是一个典型的"功能增强"需求——在已有上传组件基础上扩展交互方式。

AI的处理方式:知识图谱 + 代码复用

AI收到需求后的第一个动作不是写代码,而是通过知识图谱定位相关代码

图谱:上传附件 | 命中 | src/components/spreadOperate/

接着,AI做了一件让我印象深刻的事——它在项目中搜索是否已有拖拽/粘贴的实现,结果发现PenToolDialog.vue中已经有类似的功能。这意味着AI可以复用已有的模式和经验,而不是从零实现。

有了参考实现后,AI制定了一个完整的计划,然后一次性完成所有改动

  • 重构模板,添加拖拽容器
  • 在script中补充拖拽/粘贴状态管理和事件处理
  • 验证逻辑复用现有的beforeUpload函数
  • 追加样式定义

实现细节的考究

虽然落地很快,但AI在实现质量上并不马虎:

功能点 实现方式
拖拽区域 upload-drop-zone容器监听dragover/dragleave/drop
粘贴上传 全局paste事件监听,仅在对话框可见时响应
数量限制 拖拽/粘贴时检查已有文件数+新文件数是否超限
类型/大小验证 复用现有beforeUpload,保持与点击上传一致
视觉反馈 拖拽悬停时高亮蓝色虚线边框+浅蓝背景
内存管理 onUnmounted时移除全局paste监听,无泄漏

特别值得一提的是,AI主动将纯逻辑提取到独立辅助模块attachmentUploadHelpers.js),并为其编写了13个单元测试全部通过。这不是我要求的,而是AI基于代码质量的考量自主完成的。

用户体验的微调

功能实现后,我提了一个体验优化:“粘贴、拖拽位置边框希望在没有操作前就浅显一点,方便用户知道拖到哪个位置。”

AI的响应非常迅速——将默认边框从transparent改为Element Plus的标准浅灰色#dcdfe6,让拖拽区域在非悬停状态下也有视觉边界提示。效果:

  • 默认状态:浅灰虚线边框,用户一眼看出可拖拽区域
  • 拖拽悬停:蓝色边框+浅蓝背景,交互反馈清晰

整个案例从需求到完成,包括代码实现、逻辑提取、13个单元测试、样式微调,一气呵成。


两个案例的对比分析

维度 案例一:自动保存 案例二:拖拽粘贴
需求明确度 初始模糊,逐步迭代 一开始就很清晰
方案演进次数 4次(提醒→30s保存→IndexedDB→去掉提醒) 1次(直接落地)
核心挑战 运行时环境Bug(Vue响应式、序列化) 无明显技术障碍
Debug耗时 多轮对话+埋点验证 无需Debug
AI角色侧重 方案引导 + 假设验证 + Bug定位 代码复用 + 快速实现 + 质量保障
人的角色侧重 需求迭代 + 运行时验证 + 体验判断 需求提出 + 体验微调
最终产出 2个新文件 + 2个改动文件 + 9个测试 2个新文件 + 1个改动文件 + 13个测试

这个对比揭示了一个重要事实:AI辅助开发的效率不仅取决于AI本身的能力,更取决于需求的技术深度和运行时环境的复杂度

案例一中,AI在方案设计阶段表现优秀——能够分析浏览器API限制、评估不同存储方案的优劣、给出清晰的迭代路径。但到了运行时Debug阶段,AI必须依赖人提供的真实环境信息(Console日志、错误堆栈)才能继续工作。

案例二中,AI几乎独立完成了全部工作——从代码定位、模式复用、逻辑实现到测试编写,人只需要提需求和做最终的体验验收。


实践感悟与经验总结

1. AI擅长的与不擅长的

AI擅长:方案设计、代码生成、模式识别、逻辑提取、测试编写、快速响应变更需求。

真正的难点往往在运行时环境:Vue 3响应式系统的隐式规则(toRaw()导致的reactivity丢失)、浏览器API的安全限制(beforeunload不能可靠执行异步操作)、第三方库的序列化陷阱(SpreadJS的toJSON()返回含native function的对象)——这些问题在代码层面看不出来,必须在真实运行环境中才会暴露。

2. Debug方法论:假设-埋点-验证-定位

案例一的Debug过程展示了一套高效的方法论:

  1. 建立假设矩阵:AI一次性列出H-A到H-D四个可能的原因
  2. 设计埋点方案:在关键节点插入console.log,一次覆盖所有假设
  3. 人执行验证:在浏览器中操作并收集日志
  4. AI分析定位:根据日志输出确认或排除假设,锁定根因
  5. 给出修复:针对性修复,不引入额外复杂度

这套流程中,AI和人各司其职——AI负责"想"(建立假设、分析日志、给出修复),人负责"做"(执行操作、观察结果、反馈信息)。

3. 精准的运行时信息是加速排查的关键

当我只告诉AI"没有自动缓存"时,它能做的有限;但当我把完整的Console日志(包含DataCloneError的完整堆栈和触发链路)粘贴过来时,AI在几秒内就锁定了根因。

经验法则:给AI提供的运行时信息越精准越完整,Debug效率越高。Console日志、网络请求、错误堆栈、Vue Devtools的状态快照——这些都是"喂给AI的燃料"。

4. AI会主动考虑代码质量

案例二中,AI在实现功能后主动将纯逻辑提取到独立模块并补充单元测试,这不是我额外要求的。这种行为体现了AI在代码质量上的自觉性——可测试的代码结构、关注点分离、lint检查,这些都是AI"内置"的工程习惯。

5. 好的人机协作模式

经过这两个案例,我总结出的协作模式是:

  • 用户负责:需求判断(什么值得做)、运行时验证(在真实环境跑)、体验评审(好不好用)
  • AI负责:方案迭代(怎么做最合理)、代码实现(写出可运行的代码)、质量保障(提取模块、补测试、检查lint)

这是一种互补关系:人有对业务和用户体验的直觉判断力,AI有对代码和工程实践的高效执行力。

6. 需求迭代是常态

案例一的需求从"关闭提醒"→"自动保存"→"浏览器缓存"→"移除提醒",经历了四次方向调整。AI在每一次转向时都能快速跟上:理解新方向的合理性、分析对已有实现的影响、给出最小改动方案。

这种"跟随用户思路演进"的能力,在实际开发中比"一次性写出完美代码"更有价值——因为需求本身就是在探索中逐渐清晰的。


结语

两个案例,两种风格。一个是在技术深水区中摸索前行,一个是在平坦道路上高速奔跑。但无论哪种,AI辅助开发的核心价值始终是:让开发者可以把更多精力放在"思考该做什么"上,而不是"研究怎么写"上

当然,AI不是万能的。运行时的魑魅魍魉(响应式陷阱、浏览器限制、第三方库quirks)仍然需要人去发现和确认。但有了AI作为搭档——它帮你分析假设、写埋点代码、定位根因、实现修复——整个排查过程从"一个人对着屏幕挠头"变成了"两个人高效协作"。

这大概就是AI辅助开发的真正意义:不是替代开发者,而是让开发者的每一分钟都更有价值。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐