返回文章列表 →

Note

vue-code-standards

vue项目代码规范

发布于 更新于

Vue 项目代码规范

执行方式

  1. 修改前读取适用的项目指令、package.json、现有目录、格式与类型配置,以及邻近同类代码。确认 Vue 版本、包管理器、请求封装、路由、状态管理和组件库。
  2. 遵守用户当前要求和项目明确规定;未约定的部分采用本规范。存在不同风格但无明确规定时,新模块使用本规范,局部修改保持邻近代码一致,不附带全项目迁移。
  3. 新建 Vue 3 组件默认使用 TypeScript 和 <script setup lang="ts">。修改已有 Vue 2、JavaScript 或 Options API 文件时保持兼容,不擅自升级、改写架构或新增依赖。
  4. 只创建当前任务需要的目录与文件。复用已有组件、类型、工具和请求封装,不为目录完整而生成空壳,不把示例业务当作产品需求。
  5. 完成实现后检查变更范围内的规范,并运行适用的现有检查。将变更说明、取舍和验证结果留在回复中,不写入业务代码或新建说明文档,除非用户要求。

目录划分

项目无既定结构时采用以下默认路径;orders 仅作为业务命名示例,替换为实际业务名。

路径 放置内容
public/ 需要固定名称或固定地址访问的静态资源
src/assets/images/src/assets/icons/ 通过构建工具引用的图片和图标
src/components/base/ 跨业务基础组件,不依赖业务 API 或业务 Store
src/components/business/ 跨页面复用的业务组件
src/layouts/ 页面布局壳
src/views/orders/ 对应业务的路由页面
src/views/orders/components/ 该业务页面私有组件
src/views/orders/composables/ 该业务页面私有响应式逻辑
src/views/orders/order-view.types.ts 多个文件共用的页面展示类型
src/api/http.ts HTTP 实例、通用请求配置与错误转换
src/api/order.api.ts 业务接口函数
src/api/order.types.ts 对应接口的请求与响应类型
src/api/common.types.ts 共享接口响应结构、分页契约
src/router/index.ts 创建路由实例
src/router/routes/order.routes.ts 业务路由定义,路由较少时不必拆分
src/router/guards.ts 路由守卫
src/stores/user.store.ts 跨页面共享状态
src/composables/ 跨业务复用的响应式逻辑
src/utils/ 不依赖 Vue 实例与页面状态的普通工具函数
src/constants/ 多处使用的常量与枚举映射
src/types/ 非接口专属的跨模块共享类型
src/styles/ 全局样式、重置样式、设计变量
src/directives/src/plugins/ 按需创建的自定义指令、插件初始化
src/App.vuesrc/main.ts 根组件与应用初始化入口
tests/e2e/ 已采用端到端测试时的场景测试
  • 仅被当前文件使用的小函数、类型和常量就近保留;复杂度或真实复用需要时再拆分。
  • 页面临时状态保留在页面,不因多个子组件使用就立即放入全局 Store。
  • 页面私有模块不被其他页面直接引用;真实复用出现后提升到共享目录。
  • 基础组件不得反向依赖业务页面;API 层不得依赖组件与路由;工具函数不得依赖页面或 Store。
  • 按职责细分工具文件,如 date.tsmoney.ts;不将所有内容堆入 common.tsindex.ts
  • main.ts 只处理初始化,不承载业务流程。避免循环依赖与过量转导出。
  • 已采用 features/<业务>/ 的项目延续其结构;只在任务需要时迁移完整业务模块,不同时创建两套平行组织方式。

文件与标识符命名

对象 规则 示例
普通目录 kebab-case user-settings/
Vue 组件 PascalCase,使用多单词语义名 OrderTable.vue
路由页面 PascalCase + View OrderListView.vue
布局组件 PascalCase + Layout DefaultLayout.vue
基础组件 Base + PascalCase BaseDialog.vue
业务组件 业务名 + 职责 OrderFilter.vue
composable 文件及函数 use + PascalCase usePagination.tsusePagination
普通 TS 文件 kebab-case format-date.tsmoney.ts
API / 类型 / Store / 路由模块文件 业务名 + 职责后缀 order.api.tsorder.types.tsuser.store.tsorder.routes.ts
图片、图标、样式文件 kebab-case empty-orders.svgtokens.css
单元与组件测试 被测文件主体名 + .test.ts money.test.tsOrderTable.test.ts
端到端测试 场景名 + .spec.ts order-create.spec.ts
变量、参数、对象属性 camelCase selectedCategoryId
集合 复数名词或明确集合含义 ordersselectedIds
索引映射 表明索引关系 userById
布尔值 is / has / can / should 开头 isLoadingcanSubmit
函数 动词 + 对象 formatAmountcreateOrder
UI 事件处理函数 handle + 行为 handleSubmit
Store 工厂函数 use + 业务名 + Store useUserStore
类型、接口、类 PascalCase UserCreateOrderBody
模块级固定常量 UPPER_SNAKE_CASE DEFAULT_PAGE_SIZE
props camelCase 声明,kebab-case 传入 pageSize:page-size
自定义事件 kebab-case,模型更新遵循框架命名 submit-successupdate:modelValue
路由 name / path kebab-case order-detail/orders/:id
CSS 类名 kebab-case;复杂组件采用 BEM order-card__titleorder-card--selected
  • 保留 App.vuemain.ts、工具配置及框架要求的名称;显式页面名优先于大量 index.vue
  • import 路径大小写必须与实际文件一致。仅在提供公开入口时创建 index.ts
  • 不使用拼音、data1flagnew2final 等含糊名称;小范围回调可使用 itemindex
  • 将单位写入可能混淆的名称:timeoutMsamountInCents。区分业务日期 orderDate 与时间点 createdAt
  • 不因使用 const 就将变量大写;不强制类型前缀 I / T,也不强制异步函数加 Async。
  • 按接口契约保留字段与枚举值;如需字段转换,集中在 API 适配层,不在页面重复转换。

TypeScript 与函数

  • 新项目启用 strict;现有项目不为局部任务随意改动编译选项。
  • 为公共函数、API 和模块边界提供明确参数与返回类型;局部简单值允许推断。
  • 使用 import type 导入纯类型。对象结构默认 interface,联合类型默认 type;不机械改写现有类型。
  • 未知数据使用 unknown 并缩小类型;不用 any、非空断言、双重断言或 @ts-ignore 掩盖问题。
  • 类型断言不能代替运行时校验;外部数据按实际风险在边界验证。
  • 默认 const,需重新赋值时用 let;不用 var。使用严格相等。
  • 区分 null、undefined、空字符串、0 和 false;保留有效零值时使用 ?? 而不是 ||
  • 函数聚焦单一职责,优先提前返回;避免重复状态、过深嵌套和与任务无关的抽象。
  • 明确 await、返回或 catch Promise;void promise 不能代替错误处理。
  • 金额、日期、枚举和 ID 遵守后端契约,不擅自更换字段、单位或响应包装。大整数 ID 采用接口约定的字符串,不经 number 中转。
  • 金额计算遵循明确精度方案;业务日期不随意转换为 UTC 时间点再截取日期。

Vue 组件

单文件组织

  • 新 SFC 使用 script setup → template → style scoped 的顺序。
  • 脚本按 import、类型、props / emits、状态、computed、业务函数、watch / 生命周期组织;复杂组件可按完整业务职责聚合相关代码。
  • 组件达到可独立命名的职责时拆分,如筛选栏、列表、编辑弹窗;不机械按照行数拆分。
  • 优先复用项目组件库,不创建行为相同的重复基础组件。

数据与通信

  • 为 props、emits 提供类型;不直接修改 props 及其嵌套对象。通过事件提交变更意图。
  • 编辑表单建立独立草稿,按结构处理嵌套引用;不滥用 JSON 序列化充当通用深拷贝。
  • 独立状态默认 ref,稳定关联对象可用 reactive;派生状态使用 computed,computed 不产生副作用。
  • watch 用于外部同步与副作用;监听属性使用 getter,不默认 deep。
  • 不直接解构 reactive 的基本类型字段后期待其继续响应式;需要时使用 toRefs。
  • 只有确认安装版本支持时才使用响应式 props 解构、defineModel 等特性;未知版本时使用 props.xxx 等兼容方式。
  • withDefaults 中可变数组或对象默认值使用工厂函数。
  • 生命周期内创建的定时器、事件监听、订阅和连接负责清理;KeepAlive 按业务处理停用状态。
  • defineExpose 仅暴露明确需要的命令式能力,常规通信使用 props / emits。

模板

  • SFC 内自定义组件使用 PascalCase,原生标签使用小写。
  • v-for 提供稳定唯一 key;可增删或排序的列表不用数组下标做 key。
  • 不在同一元素混用 v-if 与 v-for;先计算筛选结果或调整容器层级。
  • 模板只保留简单表达式,复杂逻辑进入 computed 或函数,不在渲染表达式中产生副作用。
  • 非提交按钮写明 type="button";输入关联 label;图标按钮提供可访问名称,图片提供合适的 alt。
  • 使用语义化交互元素,保留键盘操作和焦点可见性。

注释

  • 使用中文说明、英文标识符,采用 JSDoc 风格。
  • 公共函数、API、公共 composable 和复杂业务函数写明用途、参数含义、返回语义;有异常、单位、限制或副作用时一并说明。
  • TS 类型由签名提供,注释解释字段语义,不重复维护 {number} 等类型;JS 中可用 JSDoc 补充类型。
  • 参数及响应字段的详细说明放在对应类型声明旁;API 函数注释引用类型,并说明 HTTP 方法、路径和业务契约。
  • 短状态说明优先行尾,computed / watch 的必要说明放上方;长说明及公共类型字段使用上方注释。
  • template 的主要业务区域添加说明;简单包装元素不逐个注释。
  • CSS 注释说明业务区域、特殊布局与覆盖原因,不给含义清晰的选择器重复写标签。
  • 每个新建且支持注释的源文件必须包含文件元数据;修改已有文件时补齐缺失项,具体遵守下方“文件元数据”规则。
  • 注释解释原因和约束,不复述语法。移除失效注释与大段被注释掉的代码。
  • TODO 写明具体事项与解决条件,不留下无信息的“待优化”。
/**
 * 格式化金额显示。
 * @param amountInCents - 安全整数金额,单位:分
 * @returns 保留两位小数的元金额字符串,不附加货币符号
 */

将这类注释写在实际函数上,按真实实现调整契约,不把注释示例或缺失实现的占位内容写入交付代码。

文件元数据(必须)

  • 对每个新建的 Vue、JS、TS、CSS、SCSS、HTML 等支持注释的源文件,以及支持注释的配置文件,添加文件头元数据,统一使用 @author@date@description,不得因文件短小而省略。
  • @author 表示文件作者。新建文件默认填写用户指定的作者 Brave;用户或项目明确指定其他作者时采用其指定值。修改已有文件时保留原作者,不将其统一替换为 Brave 或 agent 名称。
  • @date 表示创建时间,不是最近修改时间。新建文件使用创建时的实际日期与时间,采用带时区偏移的 ISO 8601 格式,例如 2026-09-20T15:30:00+08:00。使用项目明确的时区;未指定时使用 UTC 并以 Z 结尾。读取实际系统时间,不复制示例时间,也不将会话日期冒充准确创建时间。
  • @description 使用中文简述文件职责、主要用途或边界,按实际内容填写,不写“这是一个组件”等空泛描述;职责变化时同步更新。
  • 修改已有文件时检查并补齐元数据,保留已有且有效的创建信息。缺失作者或创建时间时,优先查找可信历史记录;版本控制首次新增记录可作为依据,但重命名、导入或复制的提交时间不得直接冒充创建时间。无法确认时分别填写 未知(历史未记录),不使用当前时间或默认作者伪造历史信息。
  • Vue SFC 在 <script setup><script> 块开头添加一份 JSDoc 文件头;没有 script 的 SFC 在文件顶部使用 HTML 注释,不为文件头额外创建 script。无需在 template 与 style 中重复整份元数据。
  • JS、TS 使用 JSDoc;CSS、SCSS 使用块注释;HTML 使用 HTML 注释;YAML、Shell 等采用合法的行注释。保留 shebang、编码声明、许可证等必须前置的内容及框架语法要求,将元数据放在其后的最早合法位置。
  • 不向严格 JSON、图片、字体、二进制文件等不支持注释的格式插入文件头;不修改依赖、锁文件、构建产物或自动生成文件来添加元数据。无需为这些例外创建额外的元数据文件。

Vue 文件头示例(作者和时间按上述规则确定):

<script setup lang="ts">
/**
 * @author Brave
 * @date 2026-09-20T15:30:00+08:00
 * @description 用户搜索页面,负责搜索条件、请求状态与结果展示。
 */
</script>

JS / TS / CSS / SCSS 文件头格式:

/**
 * @author Brave
 * @date 2026-09-20T15:30:00+08:00
 * @description 用户接口模块,负责请求发送与响应适配,不处理页面提示。
 */

HTML 或无 script 的 Vue 文件头格式:

<!--
@author Brave
@date 2026-09-20T15:30:00+08:00
@description 用户信息展示模板。
-->

API、异步与状态管理

  • 复用现有 HTTP 封装,先确认返回 AxiosResponse、响应体还是业务 data,再声明类型和解包;禁止凭经验重复取 .data
  • HTTP 层处理连接配置和通用错误转换,业务 API 层负责路径、参数及响应适配,调用层负责 loading、业务提示和页面流程。
  • 原生 Axios GET 查询参数写入配置的 params;自定义封装严格按现有签名调用。
  • 从真实接口文档、后端代码或已有类型获取契约,不虚构 URL、成功码、字段与认证方案。关键契约缺失时提出最小问题;允许先实现独立 UI,并明确待接入部分。
  • 错误提示明确归属,避免全局与页面重复提示;不吞异常并返回假成功或空列表。
  • 请求覆盖 loading、失败、空结果与成功状态;提交设置防重复触发状态,严格幂等由后端配合。
  • 搜索和筛选请求采用取消或请求序号,防止旧响应覆盖新结果;finally 也必须确认请求仍有效后更新共享 loading。
  • 页面卸载后避免写入失效状态;主动取消不作为普通失败提示。
  • 不自动重试可能产生重复写入的操作,除非契约提供幂等保障。
  • 响应式复用行为放 composable,纯计算放 utils;composable 默认在函数内创建状态,以普通对象返回 ref 与方法。
  • 不在模块顶层意外共享 composable 状态;共享必须明确设计。
  • Store 仅保存确需跨页面同步的状态,业务修改推荐 actions,派生数据使用 getters / computed。
  • Pinia 状态解构使用 storeToRefs;actions 可直接解构。退出登录清理用户相关状态与缓存。

样式、路由与资源

  • 组件样式默认 scoped,全局 reset 和设计变量集中管理。
  • 使用语义 class;避免 ID 选择器、过深嵌套、泛化全局覆盖和随意 !important。
  • 简单类使用 kebab-case,复杂组件使用一致的 BEM 命名;颜色、间距、圆角、层级复用项目变量。
  • 优先通过组件库公开 API 或变量改样式;必须使用 :deep 时限定在当前组件根类并说明原因。
  • 静态样式使用 class,真正动态值使用样式绑定或 CSS 变量;按产品要求适配尺寸,不擅自改动设计系统。
  • 路由 name 唯一,页面默认懒加载;解析并校验 route params / query,不用断言代替转换。
  • 路由守卫仅控制前端流程,真实权限依赖服务端;URL 不承载密码或令牌。
  • 跨目录使用现有别名,模块内使用相对路径;新增别名时保证构建与 TS 配置一致。
  • 普通模块优先具名导出,SFC 和工具配置遵循框架要求。
  • 资源路径兼容部署 base;public 资源路径不带 /public 前缀,不靠不可分析的任意路径拼接收集构建资源。
  • 不导入依赖包未公开的内部文件。

配置与交付检查

  • 格式以现有工具为准;无配置时默认两空格、单引号、分号、LF、末尾换行。仅在配置任务范围内新增格式工具,不为普通功能强制安装工具链。
  • 使用现有包管理器及锁文件,不生成第二种锁文件。敏感配置不写进客户端环境变量;VITE 前缀不具备保密能力。
  • 不记录密码、验证码、令牌或完整敏感响应;不将不可信 HTML 直接传给 v-html。
  • 检查本次新增或修改的可注释源文件是否包含 @author、@date、@description,作者与创建时间是否真实或明确标注未知,修改时是否保留原始创建信息。
  • 审查文件位置、命名、类型、注释和模块依赖是否一致,检查 props 修改、key、请求竞态及副作用清理。
  • 运行适用的现有 lint、类型检查、构建和相关测试;识别 Vite 转译不等于 Vue / TS 类型检查。检查缺失或环境受限时如实说明,不声称通过。
  • 为关键逻辑变更与缺陷修复选择有价值的验证,不为简单可逆展示变更机械增加测试,不为满足测试修改无关代码。
  • 不自动提交、部署或生成规范说明文档;交付用户要求的实现,简述实际修改与验证结果。