Files
2026-07-25 23:45:09 +08:00

7.6 KiB

Vue 核心代码规范

目录

  • 技术风格与版本适配
  • 命名与文件
  • SFC 结构
  • Props、Emits、Slots 与组件 API
  • 响应式状态
  • 模板
  • TypeScript
  • 异步与副作用
  • 样式
  • 注释与日志
  • 官方依据

技术风格与版本适配

  • 新建现代 Vue 3 SFC 时,优先使用 Composition API 与 <script setup lang="ts">
  • 修改既有文件时,保持该模块的 API 风格;不要在一次无关功能变更中混合 Options API 和 Composition API。
  • 使用 defineModel、响应式 props 解构、useTemplateRef 等能力前,核实项目 Vue 版本与团队惯例。
  • 不使用实验性功能完成核心业务,除非项目已采用且存在回退或验证方案。

命名与文件

  • 使用多单词组件名,避免与原生 HTML 元素冲突。
  • 组件文件使用 PascalCase.vue,例如 UserProfileCard.vue
  • 页面按项目约定使用 *View.vue*Page.vue,不要在同一目录混用。
  • composable 使用 useXxx.ts,并导出同名 useXxx 函数。
  • Pinia store 使用 useXxxStore,每个 store 独立文件。
  • 布尔变量使用 ishascanshould 等前缀。
  • 事件处理函数使用 handleXxx;传给 props 的回调可按项目约定使用 onXxx
  • 类型、接口和泛型使用 PascalCase;不要默认增加 I 前缀。
  • 常量使用项目既有约定;仅真正跨模块、不可变的常量使用全大写形式。
  • 测试文件放在目标代码旁或项目统一测试目录,命名保持 .spec.ts.test.ts 的既有选择。

SFC 结构

默认保持以下顶层顺序:

<script setup lang="ts">
// imports
// types and component contracts
// injected dependencies, router and stores
// state
// computed values
// watchers and lifecycle
// handlers
</script>

<template>
  <!-- declarative UI -->
</template>

<style scoped>
/* component-owned styles */
</style>
  • 服从项目的 block 顺序和 import 排序规则。
  • 仅在模板或组件逻辑实际需要时创建变量;不要为了分区制造空注释。
  • 组件私有样式优先 scoped 或项目 CSS Modules 方案;主题、reset、tokens 和工具类保持全局。
  • 避免使用 :deep() 穿透第三方或子组件内部;无法通过公开 API 定制时,记录耦合原因。

Props、Emits、Slots 与组件 API

  • 用类型声明组件契约,为可选 props 明确默认行为。
  • props 名表示数据或状态;emits 名表示已发生的业务动作,例如 submitupdate:modelValue
  • 不以 emit 冒充命令式调用;父组件需要控制子组件时,优先 props 和状态驱动。
  • 仅在确有命令式能力时使用 defineExpose,并保持暴露面最小。
  • 为有双向语义的表单值使用 v-model/defineModel;普通业务数据继续使用 props + emits。
  • 不直接解构会丢失响应性的对象。解构 Pinia 状态时使用 storeToRefs;解构一般响应式对象时按需使用 toRefs
  • 为 slots 定义清晰语义;不要让父组件依赖子组件内部 DOM 结构。
  • 可变对象或数组默认值必须保证实例隔离,并符合当前 Vue 版本支持的写法。

响应式状态

  • 对基本类型和可整体替换的值使用 ref
  • 对语义内聚且主要按属性更新的对象使用 reactive;不要创建巨大、无边界的响应式对象。
  • 使用 computed 表达派生值,不将可推导数据复制进 state。
  • 不在 computed 中发送请求、写 store、修改其他 state 或触发日志等副作用。
  • 监听明确来源,避免无边界 deep watch;大型对象优先监听必要字段或规范化后的签名。
  • 在 watcher 中处理异步时,取消或忽略过期结果,防止旧请求覆盖新状态。
  • 对第三方实例、大型不可变结构或不需要深层代理的数据,评估 shallowRef/markRaw,但先用性能证据证明需要。
  • composable 返回值需保持稳定且易解构;需要保护写入口时向外暴露 readonly state 与显式 mutation 函数。

模板

  • 保持模板表达式简短且无副作用。
  • v-for 提供稳定业务键;只有完全静态、永不重排的展示列表才可评估使用索引。
  • 不在同一元素上组合 v-ifv-for;先计算筛选结果或使用外层 <template>
  • 频繁切换且初始渲染可接受时评估 v-show;条件低频或初始成本高时使用 v-if
  • 原生交互使用原生元素:动作使用 <button>,导航使用 <a>/RouterLink,不要用可点击 <div> 代替。
  • 表单控件提供关联的 <label>、名称、错误提示和 disabled/loading 状态。
  • 仅在确有 HTML 内容需求且输入经过可信净化时使用 v-html
  • 对异步列表和页面显式渲染 loading、empty、error 和 success 状态。
  • 使用 CSS 处理纯展示状态;不要用 JavaScript 复制 CSS 已能表达的响应式布局。

TypeScript

  • 遵守项目 strict 配置;新代码不得主动弱化类型检查。
  • 优先类型推断,仅在公共边界、复杂返回值和可能误推断处显式标注。
  • 使用 unknown 接收不可信值,并通过 schema、type guard 或判别字段收窄。
  • 使用 import type 引入纯类型,避免无意义运行时依赖。
  • 在 API、路由参数、storage、postMessage 等外部边界做运行时校验;TypeScript 类型不能验证运行时数据。
  • 区分传输 DTO、领域模型和表单模型;存在语义差异时显式映射。
  • 优先判别联合表达有限状态,避免多个互相矛盾的布尔值。
  • 本地封闭集合优先联合类型或 as const 对象;是否使用 enum 服从项目约定。
  • 避免 as!@ts-ignore。若第三方类型确有缺陷,局部封装并说明依据。
  • 为泛型设置能表达用途的约束,不创建只为“显得通用”的泛型。

异步与副作用

  • 让异步动作表达 loading、error 和 retry/恢复策略。
  • 使用 try/catch/finally 保证状态复位;不要将所有异常统一转换为无信息的“失败”。
  • 区分可展示业务错误、认证/权限错误、网络错误和程序缺陷。
  • 搜索、联想和切页请求处理取消、去抖或响应顺序,防止竞态。
  • onUnmounted 或 watcher cleanup 中释放事件监听、observer、timer、subscription 和请求。
  • 不在模块顶层执行依赖浏览器、用户或实例生命周期的副作用。
  • 对 SSR 项目避免在服务端路径直接访问 windowdocumentlocalStorage

样式

  • 优先复用项目设计 tokens、组件库变量和现有布局原语。
  • 不硬编码已有 token 表达的颜色、层级、间距、圆角或字号。
  • 类名遵循项目既有 BEM、utility、CSS Modules 或其他约定。
  • 避免高特异性、!important 和依赖 DOM 深度的选择器。
  • 同时验证窄视口、文本放大、长内容、空内容和交互焦点。
  • 尊重 prefers-reduced-motion,动画不应阻止操作或传达唯一信息。

注释与日志

  • 注释解释“为什么、约束和权衡”,不要复述代码。
  • 为公共 composable、复杂协议和非直观兼容性补充必要说明。
  • 删除调试日志和断点。生产日志不得包含 token、个人信息、完整请求体或敏感业务数据。
  • TODO 必须包含可操作条件或关联任务;不要留下无主 TODO。

官方依据