代码规范
vue3-element-admin 的命名、文件、组件、导入、类型和注释约定。
命名规范
变量与函数
| 类型 | 规则 | 示例 |
|---|---|---|
| 变量 | camelCase | userName, isLoading |
| 常量 | UPPER_SNAKE_CASE | MAX_COUNT, API_BASE_URL |
| 函数 | camelCase,动词开头 | getUserInfo, handleSubmit |
| 类 / 枚举 / 类型 / 接口 | PascalCase | UserService, StatusEnum, UserInfo |
| 枚举值 | UPPER_SNAKE_CASE | StatusEnum.ACTIVE |
| 泛型参数 | 单字母大写或描述性 | T, TData |
布尔值使用 is / has / can / should 前缀:
typescript
// 推荐
const isLoading = ref(false);
const hasPermission = computed(() => true);
// 不推荐
const loading = ref(false);
const permission = ref(true);函数以动词开头。单一业务动作不加 handle,流程编排(组合多个动作)使用 handle:
typescript
// 推荐:单一动作
function openDialog() { dialogState.visible = true; }
function deleteUser(id: number) { return UserAPI.deleteByIds(String(id)); }
// 推荐:流程编排
async function handleSubmit() {
const valid = await validateForm();
if (!valid) return;
await submitForm(formData);
fetchList();
}CSS 类名
BEM 定义语义、UnoCSS 补充微调、SCSS 承载复杂样式。格式统一为 block__element--modifier:
| 类型 | 规则 | 示例 |
|---|---|---|
| Block | 页面/组件前缀 + 语义名 | profile-card, user-name-cell |
| Element | Block 下的组成部分 | profile-card__header, single-upload__image |
| Modifier | 状态或变体 | profile-card--compact, is-collapsed |
列表页、管理页优先复用 src/styles/page.scss 的 page-container、page-search、page-content、page-toolbar 骨架类。单属性微调用 UnoCSS,同一元素原子类不超过 3 个,超过提炼为 BEM 类。
文件命名
| 类型 | 规则 | 示例 |
|---|---|---|
| Vue 组件 | PascalCase | UserCard.vue, PageHeader.vue |
| 页面组件 | index.vue | views/system/user/index.vue |
| TS / JS 模块 | kebab-case | user-service.ts, tags-view.ts |
| 类型文件 | kebab-case | types.ts, common.ts |
目录结构
text
src/
├── api/ # API 接口,按模块拆分,类型放同级 types.ts
├── assets/ # 静态资源
├── components/ # 公共组件,复杂组件用目录
├── composables/ # 组合式函数
├── constants/ # 常量定义
├── directives/ # 自定义指令
├── enums/ # 枚举定义
├── lang/ # 国际化
├── layouts/ # 布局组件
├── router/ # 路由配置
├── stores/ # 状态管理
├── styles/ # 全局样式
├── utils/ # 工具函数
├── views/ # 页面组件
├── App.vue
├── main.ts
└── settings.ts组件规范
Props
优先使用 TypeScript 类型声明;需要运行时默认值时用对象声明,同一组件内不混用:
typescript
// 推荐:TS 类型声明
interface Props {
/** 用户ID */
userId: number;
/** 尺寸 */
size?: "small" | "medium" | "large";
}
const props = withDefaults(defineProps<Props>(), {
size: "medium",
});Emits
typescript
const emit = defineEmits<{
(e: "update:modelValue", value: string): void;
(e: "change", value: string, oldValue: string): void;
}>();结构顺序
SFC 块顺序 template → script → style,script 内部按 Vue 核心 → 第三方库 → 类型 → Store → API → 工具 → 相对路径组件 → Props/Emits → 响应式状态 → 计算属性 → 监听 → 生命周期 → 方法 排列。
导入顺序
typescript
// 1. Node 内置模块
import { resolve } from "path";
// 2. 第三方库
import { ref, computed } from "vue";
import { ElMessage } from "element-plus";
// 3. 类型导入
import type { RouteRecordRaw } from "vue-router";
import type { UserInfo } from "@/api/system/user";
// 4. 内部模块(绝对路径)
import { useUserStore } from "@/stores";
import UserAPI from "@/api/system/user";
// 5. 内部模块(相对路径)
import UserCard from "./components/UserCard.vue";
// 6. 样式
import "./styles/index.scss";接口与类型
前端类型不使用 DTO / VO / BO,用「语义 + 场景」命名:
| 语义 | 命名 |
|---|---|
| 创建 / 修改请求 | UserCreateRequest / UserUpdateRequest |
| 查询参数 | UserQueryParams |
| 列表项 | UserItem |
| 详情 | UserDetail |
| 分页结果 | PageResult<UserItem> |
对象结构用 interface,联合类型、函数类型、工具类型用 type:
typescript
interface UserInfo {
id: number;
name: string;
}
type Status = "pending" | "success" | "error";
type PartialUser = Partial<UserInfo>;API 模块用对象字面量组织,方法按 getPage / getFormData / create / update / deleteByIds 命名:
typescript
const UserAPI = {
getPage(queryParams: UserQueryParams) {
return request<unknown, PageResult<UserInfo>>({
url: "/api/v1/users",
method: "get",
params: queryParams,
});
},
create(data: UserForm) {
return request({ url: "/api/v1/users", method: "post", data });
},
};注释规范
注释只写有信息量的内容,类型/接口/属性用单行 JSDoc,函数/方法用多行 JSDoc:
typescript
/** 用户状态。 */
const userStatus = ref(1);
/**
* 格式化文件大小。
*
* @param bytes - 字节数。
* @param decimals - 小数位数,默认 2。
* @returns 格式化后的字符串,如 "1.50 MB"。
*/
export function formatFileSize(bytes: number, decimals = 2): string {
// 换算逻辑
}行内注释解释原因、约束或例外,不复述代码:
typescript
const timeout = 30000; // 后端接口响应较慢,需要较长超时时间
if (EXCLUDED_PATHS.includes(route.path)) return; // 跳过登录、错误页和重定向页