Skip to content

注释规范

TIP

规定前端代码中注释的写法、粒度与维护要求,适用于 Vue 3 + TypeScript + Vite 技术栈。注释使用中文/英文书写,代码标识符仍遵循 命名规范

设计原则

原则说明
解释 Why,而非 What注释说明意图、约束、边界条件,不重复代码字面含义
保持同步修改逻辑时同步更新注释,过期注释比没有注释更有害
适度精简能靠清晰命名表达的不写注释;复杂逻辑才写
公开 API 必文档化对外暴露的函数、组件 Props、hooks 需完整说明
禁止无意义注释不写「定义变量」「调用接口」等显而易见的内容

注释类型

类型语法适用场景
单行注释//简短说明、行内补充
多行注释/* ... */禁止使用,优先用多个 // 或 JSDoc
文档注释/** ... */(JSDoc/TSDoc)函数、类型、组件、模块导出
区域注释// ===== 区块名 =====长文件内分区(尽量少用)
标记注释TODO / FIXME / NOTE待办、缺陷、重要说明

何时写 / 不写

✅ 应该写注释

  • 复杂业务规则、计算公式、状态流转
  • 非显而易见的 workaround、兼容性处理
  • 对外导出的 API(函数、组件、hook、类型)
  • 魔法数字、枚举值的业务含义
  • 安全、权限、性能相关的设计决策

❌ 不应写注释

typescript
// ❌ 重复代码含义
// 获取用户列表
const userList = await getUserList();

// ❌ 注释掉的废弃代码(应直接删除,由 Git 追溯)
// const oldLogic = () => { ... }

// ❌ 与实现不一致的过期注释
// 仅管理员可访问(实际已改为角色权限校验)

WARNING

禁止提交大段被注释掉的代码。若需保留参考,在 PR 描述或文档中说明,不要留在源码中。

TSDoc 规范

对外导出的函数、类型、接口使用 /** */ 文档注释。

函数

typescript
/**
 * @todo Subtracts the indicated percentage to the R, G or B of a HEX color\
 * @author andy.ten@tom.com & xukaixing@hotmail.com
 * @Date 2026-06-16 08:07:24
 * @param {string} color The color to change
 * @param {number} amount The amount to change the color by
 */
const subtractLight = (color: string, amount: number): string => {
  const cc = parseInt(color, 16) - amount;
  const c = cc < 0 ? 0 : cc;
  return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`;
};

常用标签

标签用途
@todo函数用途
@author作者信息
@Date日期信息
@param参数说明,格式 @param name - 说明

类型与接口

typescript
/**
 * @todo 用户信息接口
 * @author andy.ten@tom.com & xukaixing@hotmail.com
 * @Date 2026-06-16 08:07:24
 */
export interface UserInfo {
  // 用户 ID
  id: string;
  // 用户名
  userName: string;
  // 用户状态
  status: UserStatus;
}

/**
 * @todo 订单状态枚举类型
 * @author andy.ten@tom.com & xukaixing@hotmail.com
 * @Date 2026-06-16 08:07:24
 */
export enum OrderStatus {
  // 待支付
  Pending = 'PENDING',
  // 已完成
  Completed = 'COMPLETED'
}

泛型

typescript
/**
 * @todo 分页响应结构
 * @author andy.ten@tom.com & xukaixing@hotmail.com
 * @Date 2026-06-16 08:07:24
 * @param T - 列表项类型
 */
export interface PageResult<T> {
  // 数据列表
  list: T[];
  // 总条数
  total: number;
}

文件头注释

每个业务模块的核心文件(页面、hook、复杂工具)建议添加简要文件头,说明职责与关联模块。

typescript
<!--
 * @title:  user mng component
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2023-12-16 08:07:24
 * @LastEditors: andy.ten@tom.com
 * @LastEditTime: 2026-06-17 17:45:52
 * @version: 1.1.4
-->
<script setup lang="ts">
</script>
<style scoped lang="scss">
</style>

TIP

简单、职责单一的组件(如纯展示型 Status.vue)可省略文件头。

文件内容注释

本项目为方便管理vue文件内变量、方法、事件、生命周期等,特进行归类管理,增加项目特殊注释内容,在分类前添加注释。 例如在data部分,需添加注释 // @data

vue
<script setup lang="ts">
// @define name
defineOptions({name: 'moduleName' }),

// @props
const props = defineProps({
  visible: propTypes.bool.def(false),
  // ...
});

// @emit
const emit = defineEmits(['update:visible', 'saved']);

// @hook
const appStore = useAppStore();

// @data
const userEditList = ref<FormItem[]>([]);

// @computed
const isShow = computed({
  get: () => props.visible,
  set: (value) => emit('update:visible', value),
});

// @watch
watch(
  () => ({
    visible: props.visible,
    rowId: props.rowData?.id,
    operateType: props.operateType,
  }),
  ({ visible }) => {
    if (visible) init();
  },
);

// @methods
 /**
 * @todo: edit user
 * @author: andy.ten@tom.com & xukaixing@hotmail.com
 * @Date: 2026-06-03 08:56:40
 * @param {*} row
 * @param {*} _index
 */
const editUser = (row: Recordable<any>, _index: number) => {
  operateType.value = 'update';
  rowData.value = row;
  dialogVisible.value = true;
};

// @onMounted
onMounted(() => {
  init();
});
</script>

注意

// @XXX 有内容时,必须需添加。 // @XXX 无内容时,无需添加。

组件注释

Props

使用 defineProps 时,如无必要不要添加注释,仅在必要时添加注释,使用// 说明格式:

vue
<script setup lang="ts">
// @props
const props = defineProps({
  visible: propTypes.bool.def(false),
  // 行数据
  rowData: propTypes.object,
  operateType: propTypes.string
});
</script>

Emits

使用 defineEmits 时,如无必要不要添加注释:

typescript
// @emit
const emit = defineEmits(['update:visible', 'saved']);

如果事件过多需要添加注释,使用// 说明格式:

typescript
// @emit
const emit = defineEmits<{
  // 更新 visible 状态
  'update:visible': [visible: boolean];
  // 保存成功回调,携带后端返回的数据对象
  saved: [payload: Recordable<any>];
}>();

模板内注释

vue
<template>
  <!-- ** 仅用于解释复杂布局或非语义结构,尽量少用 ** -->
  <div class="user-list">
    <GvTable ref="userTableList" ref-table="userTableList" :table-head="tableHeadList" :table-data="searchUserData" />
  </div>
</template>

模板注释

<template> 中避免大段注释;复杂交互逻辑应抽到 ts 中并在 TS 中注释。

Composables 注释

组合式函数是重点文档化对象,需说明用途、参数、返回值及副作用。

typescript
/**
 * @todo 样式工具函数
 * @author andy.ten@tom.com & xukaixing@hotmail.com
 * @Date 2026-06-16 08:07:24
 * @param scope 类名
 * @returns 返回namespace-className
 */
export const useStyle = (): IStyle => {
  const getPrefixCls = (className: string): string => `${variables.namespace}-${className}`;
  return {
    variables,
    getPrefixCls
  };
};

行内注释

业务逻辑说明

typescript
// 后端 status 为字符串枚举,前端映射为 Tag 颜色
const statusColorMap: Record<OrderStatus, string> = {
  [OrderStatus.Pending]: 'warning',
  [OrderStatus.Completed]: 'success'
};

// 兼容 Safari 15:不支持 Intl 某 API,降级为手动格式化
const formattedDate = formatDateCompat(date);

分步说明(复杂流程)

typescript
const submitOrder = async () => {
  // 1. 校验表单
  await validateForm();

  // 2. 锁定库存(失败则中断,避免超卖)
  await lockInventory(orderItems.value);

  // 3. 创建订单
  const orderId = await createOrder(buildOrderPayload());

  return orderId;
};

单行注释

  • // 后加一个空格
  • 注释放在被说明代码上方,而非行尾(行尾注释仅用于极短补充)
typescript
// ✅
// 最大重试 3 次,间隔由 axios 拦截器统一处理
await requestWithRetry(fetchData);

const count = 3; // ❌ 仅当行尾注释足够短且必要时才使用

标记注释

标记含义要求
TODO计划中的功能或优化明确说明任务内容及关联
FIXME已知缺陷或临时方案需说明原因与修复计划
NOTE重要提醒,易被人忽略解释非显而易见的约束
HACK不得已的 workaround(临时解决方案)必须说明原因与移除条件
typescript
// TODO(#1234): 接入真实导出接口,当前为 Mock
// FIXME: Safari 下弹层定位偏移,待 Guava UI 升级后移除
// NOTE: 该字段只读,后端不允许通过此接口修改
// HACK: 第三方 SDK 未暴露 Promise,仅能用回调包装,后续需替换

WARNING

TODO / FIXME 不得长期遗留;每个迭代应清理或转为正式任务。

API 注释

typescript
// 查询部门
export const listDeptsApi = (datas: Recordable<any>) => {
  const { fetch } = useFetch();
  if (import.meta.env.VITE_NODE_ENV !== 'production') fetch.getInstance().defaults.baseURL = baseUrl;
  return fetch.post(`${server.gateway_admin}/sysdept/listDepts`, datas);
};
  • 标注该Api的功能

样式注释

scss
// 列表页顶栏:固定高度
.user-list-header {
  height: var(--layout-header-height);
}

// BEM: 激活态行背景
.user-list__row--active {
}
  • 说明与设计稿或布局的对应关系
  • 避免注释每一行 CSS 属性

反例与正例

重复代码

typescript
// ❌
// 循环用户列表
userList.forEach((user) => { ... })

// ✅(命名已足够清晰,无需注释)
userList.forEach((user) => { ... })

解释业务

typescript
// ❌
if (user.status === 'LOCKED') return;

// ✅
// 锁定账号不允许登录,需走管理员解锁流程
if (user.status === UserStatus.Locked) return;

文档完整性

typescript
// ❌ 对外导出但无文档
export const usePermission = () => { ... }

// ✅
/**
 * @todo 权限校验
 * @author andy.ten@tom.com & xukaixing@hotmail.com
 * @Date 2026-06-16 08:07:24
 * @returns hasPermission - 检查是否拥有指定权限码
 */
export const usePermission = () => { ... }

设置注释模版

  • 依赖插件工具: koroFileHeadervscode/trae 左侧插件市场搜索插件名称,安装即可
  • 打开编译器(vscode/trae)setting.json 文件, 按 Ctrl + Shift + P/ Commond + Shift + P,输入并选择 Preferences: Open Settings (JSON)
  • 将以下配置粘贴到 setting.json 文件中,保存关闭,重启编译器(vscode/trae)即可生效
json
// 将 author 与 LastEditors 的值替换为自己的姓名
```json
{
  // ... 其他配置项
  "fileheader.configObj": {
    "autoAdd": false,
    "prohibitAutoAdd": ["md", "json"]
  },
  "fileheader.customMade": {
    "title": "TODO",
    "author": "Author",
    "Date": "Do not edit",
    "LastEditors": "Author",
    "LastEditTime": "Do not edit",
    "version": "1.0.1"
  },
  "fileheader.cursorMode": {
    "todo": "TODO",
    "author": "Author",
    "Date": "Do not edit"
  }
}
  • koroFileHeader 默认快捷键
    • 生成文件头注释: Ctrl + Alt/Option + i
    • 生成方法注释: Ctrl + Alt/Option + t
  • koroFileHeader 查看并修改快捷键方式,Cmd/Ctrl + Shift + P 输入:打开键盘快捷键,再次输入 fileheader 查看并修改对应快捷键

注释 Checklist

提交代码前自查:

  • 是否有 // @XXX 注释
  • 对外 API(组件 Props、Composables、utils)有 JSDoc/TSDoc 说明
  • 复杂业务逻辑有「为什么」层面的注释
  • 无重复代码含义的无用注释
  • 无大段注释掉的废弃代码
  • TODO / FIXME 带有任务编号或修复计划描述
  • 修改逻辑后已同步更新相关注释
  • 页面注释更新人、更新时间及版本号是否更新

相关规范