知

模块五 · AI 协作与表达

第 16 / 17 节19 分钟阅读型

AI 协作与代码评审:Vue 项目里怎么用、怎么审

Vue 的简洁语法让 AI 更容易写对"表面",也更容易写错"响应性"。这一节给出上下文四件套、Vue 专属的五个审查点、验证三道闸,以及一份能算清的账。

读完这一节,你能做到

  1. 说清 AI 在 Vue 项目里最擅长什么、最容易错在哪。
  2. 用「目标 / 现状 / 约束 / 验收」四件套写出能用的上下文。
  3. 按「类型 → composable → 组件 → 测试」的顺序拆任务。
  4. 用五个 Vue 专属检查点审出响应性丢失、v-model 绑 prop 这类问题。
  5. 用 vue-tsc + Vitest + 浏览器指标证明改动没有变坏。

一、AI 写 Vue 的强项与盲区

Vue 的 API 面比 React 窄,模板语法又规整,所以 AI 写出来的东西看起来特别像对的。问题恰恰在这里:它很容易通过"能跑"这一关,却在响应性上悄悄错。

它很擅长它经常错
模板结构、指令、修饰符响应性丢失(解构 reactive、把值存进普通变量)
<script setup> 的样板v-model 绑到 prop 上,破坏单向数据流
简单 composable 骨架缺 onUnmounted 清理、缺请求竞态处理
表单与列表的常规写法:key 用 index、v-if 与 v-for 同层混用
CSS 与过渡类名KeepAlive 不写 include、Teleport 在 SSR 下取不到目标

判断原则:语法对不等于语义对。 Vue 的响应式是隐式的,错了往往不报错,只在某个解构、某次赋值之后界面不动。这类 bug 靠"跑一遍看看"发现不了,只能靠审。

二、上下文是新的需求文档

模型不知道你的 Vue 是 3.4 还是 3.5、用不用 <script setup>、状态放 Pinia 还是 composable、有没有装 Element Plus、团队是否允许 defineModel。你不说,它就按最常见的写法猜。

四件套,Vue 版的具体内容:

  1. 目标:改哪个页面、哪个交互,验收看什么。
  2. 现状:Vue 与构建工具版本、相关文件路径、现有 composable 在哪、状态放在哪一层。
  3. 约束:必须 <script setup> + TS、不新增依赖、不许改子组件 props 签名、请求统一走 useRequest。
  4. 验收:具体到行为——输入停顿 300ms 才请求、切换 tab 不重复请求、空数据有空态、失败有重试。

反例与正例的差距,不在字数,在约束这一项。AI 默认会给你最"教科书"的写法,而教科书不等于你的项目:

反例:帮我写一个订单列表页。
正例:目标:订单列表,支持关键词搜索与分页。现状:Vue 3.4 + TS + Vite,
      Pinia 管理筛选,请求封装在 src/composables/useRequest.ts。约束:不新增依赖,
      搜索词进 URL query,不许改 OrderTable 的 props。验收:输入停顿 300ms 才发请求,
      翻页保留旧数据,失败显示重试。

三、拆任务:顺序比粒度更重要

Vue 项目有一个天然的优势:类型先行的成本很低。所以推荐固定顺序:

① 定 props / emit / composable 的签名
② 写 composable(纯逻辑,可单测)
③ 写组件(只负责渲染与事件绑定)
④ 补测试与边界

这样拆有三个好处:类型先定住,AI 后面写实现时幻觉字段会立刻报错;composable 是纯函数,能脱离组件测;组件层只剩渲染,审起来快。

粒度标准:这次 diff 我能在 10 分钟内逐行看完。 看不住就再拆。一次让它写"列表 + 搜索 + 分页 + 空态 + 单测",产出三四百行,你审不完,等于直接合并未知风险。

四、五个 Vue 专属检查点

按顺序过,前面不过后面不用看。

第一点:响应性有没有丢

这是 Vue 最高频、也最隐蔽的一类错误:

  • const { count } = reactive(state) —— 解构出来的是普通值,后续不再更新,要用 toRefs。
  • const total = list.length 写在 setup 里当"派生值",列表变了它不变,应该用 computed。
  • 把响应式对象整个存进普通变量再改,改的是副本。
  • ref 忘了 .value,或反过来在模板里多写了 .value。

第二点:有没有破坏单向数据流

  • v-model 直接绑在 prop 上 —— prop 只读,必须 emit。
  • 子组件直接修改父组件传下来的对象属性 —— 能跑,但调用方无从追踪。
  • defineModel 用了但没声明,或和 props 双写,形成两份真相。

第三点:生命周期与清理

  • onMounted 里开的定时器、监听、订阅,onUnmounted 里没清。
  • 请求没有取消,也没有"忽略过期响应"的标记,连续切换会显示错数据。
  • 在 onUpdated 里改状态做初始化,容易形成更新循环。

第四点:模板里的隐式坑

  • :key 用 index,插入或排序后节点复用错位。
  • v-if 与 v-for 写在同一元素上,优先级容易判断错,应该拆一层。
  • KeepAlive 不写 include,缓存了所有页面,内存白涨。

第五点:类型是否真的生效

  • defineProps 用运行时对象声明,没有类型,vue-tsc 管不到。
  • 出现 any、as、@ts-ignore,等于把类型闸门关掉。
  • emit 没写类型签名,调用方传错参数也不报错。

五、验证闭环:三道闸

  1. 静态闸:vue-tsc --noEmit + ESLint + vite build。能拦幻觉 API、类型不匹配、模板里写错的属性。
  2. 行为闸:Vitest + @vue/test-utils,按可访问名称查询,不测内部字段;再手测一次真实交互。
  3. 指标闸:首屏体积(构建产物对比)、交互延迟(Performance 面板)、渲染次数(Vue DevTools 的组件渲染统计)。

第三闸最容易被跳过,也最容易被面试追问。"没变慢"要有两个数,不能只有感觉。

六、算例:一个列表页的两种做法

任务:订单列表 + 搜索 + 分页 + 空态,以下是示意时长,用来演示记账方式。

做法 A:一次要完

项耗时
写提示词、等生成3 分钟
review 320 行30 分钟
发现筛选条件放在 Pinia、刷新即丢,重做25 分钟
空态与失败态缺失,补15 分钟
合计73 分钟

做法 B:拆四轮

轮次交给 AI 的自己做的耗时
① 签名props / emit / composable 类型定接口与数据形状8 分钟
② composable请求与分页逻辑补竞态与错误分支12 分钟
③ 组件模板与事件绑定空态、失败态、URL 同步12 分钟
④ 测试用例骨架补断言10 分钟
合计42 分钟
净收益 = 生成节省的时间 − (审查 + 返工 + 事故成本)

A 的"生成"更快,但返工把它吃光了。B 把 AI 放在"产出候选"的位置,判断留给自己,总额更小、风险更低。

七、常见坑

  1. 被"能跑"骗过去。 Vue 的响应性错误不报错,只表现为界面不动。
  2. 上下文只写目标不写约束。 结果它给你 Pinia + Element Plus + axios 的全家桶,你的项目一个都没装。
  3. 让它一口气写完整页。 diff 一大,你只能抽查,抽查等于没审。
  4. 测试测实现。 mock 掉 composable、断言 class 名,改实现就红,等于没保护。
  5. 把业务数据贴进公网模型。 客户手机号、订单号、内部接口地址都不该出现在提示词里。
  6. 团队各写各的。 没有约定时,AI 会按每个人的提示词生成各自的风格,三个月后没人认得出这是同一个项目。

八、面试怎么讲

面试官问"你平时怎么用 AI",他想确认三件事:你有没有判断、有没有验证、有没有踩过坑。

怎么用:按 类型 → composable → 组件 → 测试 的顺序拆,每轮只让它产出一屏能看完的 diff
怎么验:vue-tsc + Vitest + 浏览器指标,三闸都过才合
踩过什么坑:它把筛选条件放进 Pinia,刷新就丢;后来约定筛选一律进 URL
换来什么:同类页面从 73 分钟降到 42 分钟,返工从"两次一次"降到"五次一次"

三个不要:不要说"提效 50%"却没有口径;不要说"全交给它";不要为了显得前卫而贬低不用 AI 的团队。

九、动手任务:自写 → AI 写 → 对比 → 取舍

四步不跳:① 自己写(限时,关掉补全)→ ② 让 AI 写同一题 → ③ 逐条比对 → ④ 说出保留谁的写法。

① 自己写

  1. 写一个 usePagination composable:接受 fetcher,返回 list / page / loading / error / empty,并处理竞态。
  2. 用它做一个列表页,筛选条件进 URL query,刷新后能恢复。

② 让 AI 写同一题

把第 1 题交给 AI,补一句 Vue 3.4 + TS + <script setup>,不新增依赖,必须能处理快速翻页的竞态。

③ 对比要盯的点

检查面我的版本AI 版本差异说明
响应性(解构/computed)
清理与竞态
类型是否真生效
空态与失败态

④ 说取舍

  1. 它有没有解构 reactive 或把派生值写成普通变量?
  2. 连续快速翻三页时,它显示的是第几页的数据?
  3. 它的 composable 能不能脱离组件单测?不能的话你会怎么拆?

记录模板(一题一行,攒够十行就是面试案例库):

题目 | 我错在哪 | AI 错在哪 | 最终保留谁的写法 | 用时(我/AI/合计)

十、自测

  1. AI 写 Vue 时最容易"看起来对"的地方是什么?为什么危险?
  2. 上下文四件套缺哪一件最容易返工?
  3. 为什么推荐「类型 → composable → 组件 → 测试」的顺序?
  4. 五个 Vue 专属检查点分别是什么?
  5. 三道闸里哪一道最容易被跳过?跳过它会付出什么代价?
  6. 净收益怎么算?为什么"生成越快越赚"是错的?

参考答案要点:语法正确但响应性错,且不报错;缺"约束";类型与逻辑先定住、可单测、diff 小;响应性、单向数据流、清理、模板隐坑、类型生效;指标闸,面试追问时拿不出数字;生成节省减去审查、返工与事故成本。

配套题目

★ 越多越该先背;点题目可看完整答案与深入版。

提示:读完可以顺手做几道对应题目,检验是否真的理解