Vue 3 开发实践技能。默认使用 <script setup> 加 Composition API。Vue 以外的技术栈(构建工具、CSS、状态库、TS 版本)跟随项目已有约定,不在本技能中指定。
核心约束:禁止凭训练数据写 API。必须先确定 Vue minor 版本,再读取对应参考文件。
定版本
先读取已安装的 vue 版本,取其 minor(3.4.x 记为 3.4),按下表打开对应文件,并按该文件写代码:
| minor | 文件 |
|---|---|
| 3.4 | references/3.4.md |
| 3.5 | references/3.5.md |
未列出的更新 minor:以已覆盖的最高 minor 为底,再查官方该 minor 的 changelog / docs。更旧的 minor:不要使用本技能里的新 API。
选响应式 API
不要一律使用 ref。根据是否整体替换、是否就地改字段、是否需要深层追踪来选择:
| API | 用在 |
|---|---|
| ref | 会被整体替换的值:原始类型、开关、当前 id、整份替换的对象 |
| reactive | 就地改字段的结构,尤其表单、草稿、一组相关字段 |
| shallowRef | 只关心 .value 替换:大列表、第三方实例、不可变快照。内部字段变更不通知 |
| shallowReactive | 只关心根属性;嵌套当不可变 |
| markRaw | 永不追踪 |
| triggerRef | 改了 shallowRef 内部后又必须通知时(优先考虑直接替换 .value) |
| customRef | 自己控制 track/trigger(如防抖) |
| computed | 默认不用,见下一节 |
| 普通变量 | 不驱动视图、不参与派生 |
ref(obj) 内部同样深层代理,只是多一层 .value。表单用 reactive,不要用 ref({ name, email })。
列表要追踪元素字段用 ref([]);只在替换整表时更新,用 shallowRef。
computed
结构固定、只嵌一段响应式(如配置里的 props)时,用对象字面量传引用,不要包 computed。否则依赖订在外层,一改外层整页重渲染。
例如:const field = { component: Input, label: "姓名", props: form };,不要写成 { ...form }。只有过滤/排序后的新列表、或昂贵且多处复用的派生,才用 computed。
组件与数据流
单文件不要涨到巨型(约 500 行);编排放路由/入口,UI 块和 useXxx 拆出去。
props 向下、事件向上。跨层使用 provide/inject 或项目已有 store。
响应式对象在组件间直传。不要拷贝后再自己同步;需要重置时另存一份初始快照。
子组件 v-model 用 defineModel,不要手写 modelValue + update:modelValue:
const model = defineModel<string>({ required: true });
const title = defineModel<string>("title");
const [value, modifiers] = defineModel({ set: (v) => (modifiers.trim ? v.trim() : v) });
同名绑定用简写:<img :id :src :alt>。
defineOptions / defineSlots / <script setup generic="T"> 直接用。
composable 入参用 MaybeRefOrGetter,内部 toValue()。副作用清在 onScopeDispose(不要只写 onUnmounted)。
更新成本
列表 :key 用稳定 id。
传给列表项的 props 尽量稳定:算好 active 再传,不要每个 item 都收会变的 activeId。
重、少用、折页下的组件:defineAsyncComponent(SSR 水合策略见 3.5)。
拖拽 / mousemove / 滚动:热状态隔离到小子组件或 shallowRef,不要让整页模板重跑。
本技能的官方文本与具体版本参考文件内容暂未提供,使用时需以项目实际安装的 Vue minor 与对应参考文件为准。