前端开发规范
一、命名规范
1.1 文件命名
| 类型 | 规范 | 示例 |
|---|---|---|
| 组件文件 | PascalCase | UserProfile.vue、NavBar.vue |
| 工具函数文件 | camelCase | formatDate.ts、request.ts |
| 样式文件 | kebab-case | global-style.css、user-card.scss |
| 常量文件 | UPPER_SNAKE_CASE | API_CONSTANTS.ts |
| 页面文件 | kebab-case | user-list.vue、login-page.vue |
1.2 变量命名
typescript
// ✅ 正确
const userName = 'John' // 普通变量:camelCase
const MAX_RETRY = 3 // 常量:UPPER_SNAKE_CASE
const isLogin = true // 布尔值:is/has/can 前缀
const getUserList = () => {} // 函数:camelCase,动词开头
const UserComponent = {} // 组件/类:PascalCase
// ❌ 错误
const user_name = 'John'
const maxretry = 3
const login = true1.3 CSS 命名
css
/* ✅ 推荐使用 BEM 命名规范 */
.block {}
.block__element {}
.block--modifier {}
/* 示例 */
.user-card {}
.user-card__avatar {}
.user-card--active {}二、代码风格
2.1 JavaScript / TypeScript
- 使用
const优先,需要重新赋值时使用let,禁止使用var - 使用箭头函数简化回调
- 使用模板字符串代替字符串拼接
- 使用解构赋值简化代码
- 使用
async/await处理异步操作
typescript
// ✅ 正确
const name = 'John'
const greeting = `Hello, ${name}!`
const numbers = [1, 2, 3]
const doubled = numbers.map(n => n * 2)
const { id, name: userName } = user
async function fetchData() {
try {
const res = await request.get('/api/data')
return res.data
} catch (error) {
console.error(error)
}
}2.2 Vue 组件
vue
<script setup lang="ts">
// ✅ 推荐使用 Composition API + setup 语法糖
import { ref, computed } from 'vue'
// Props 定义
const props = defineProps<{
title: string
count?: number
}>()
// Emits 定义
const emit = defineEmits<{
(e: 'update', value: string): void
(e: 'close'): void
}>()
// 响应式数据
const message = ref('Hello')
// 计算属性
const doubleCount = computed(() => (props.count ?? 0) * 2)
// 方法
const handleClick = () => {
emit('update', message.value)
}
</script>
<template>
<div class="my-component">
<h1>{{ title }}</h1>
<p>{{ doubleCount }}</p>
<button @click="handleClick">Update</button>
</div>
</template>
<style lang="scss" scoped>
.my-component {
padding: 16px;
}
</style>三、项目结构
src/
├── api/ # 接口请求
│ ├── modules/ # 按模块拆分
│ │ ├── user.ts
│ │ └── order.ts
│ └── index.ts
├── assets/ # 静态资源
│ ├── images/
│ └── styles/
├── components/ # 公共组件
│ ├── base/ # 基础组件
│ └── business/ # 业务组件
├── composables/ # 组合式函数
├── constants/ # 常量定义
├── directives/ # 自定义指令
├── layouts/ # 布局组件
├── pages/ # 页面组件
├── plugins/ # 插件
├── router/ # 路由配置
├── stores/ # 状态管理
├── types/ # TypeScript 类型
├── utils/ # 工具函数
└── App.vue四、Git 提交规范
4.1 Commit Message 格式
<type>(<scope>): <subject>
<body>
<footer>4.2 Type 类型
| 类型 | 说明 |
|---|---|
feat | 新功能 |
fix | 修复 Bug |
docs | 文档更新 |
style | 代码格式调整(不影响逻辑) |
refactor | 重构 |
perf | 性能优化 |
test | 测试相关 |
chore | 构建/工具链变动 |
ci | CI 配置变动 |
4.3 示例
bash
feat(user): 添加用户登录功能
- 实现用户名密码登录
- 添加登录表单验证
- 集成第三方登录接口
Closes #123五、接口请求规范
5.1 封装请求工具
typescript
// utils/request.ts
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 15000,
})
// 请求拦截器
service.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error)
)
// 响应拦截器
service.interceptors.response.use(
(response) => {
const { code, data, message } = response.data
if (code === 200) return data
return Promise.reject(new Error(message))
},
(error) => {
// 统一错误处理
return Promise.reject(error)
}
)
export default service5.2 API 模块化
typescript
// api/modules/user.ts
import request from '@/utils/request'
import type { UserInfo, LoginParams } from '@/types/user'
export function login(params: LoginParams) {
return request.post<UserInfo>('/auth/login', params)
}
export function getUserInfo() {
return request.get<UserInfo>('/user/info')
}六、样式规范
6.1 CSS 预处理器
- 推荐使用
SCSS作为 CSS 预处理器 - 全局变量统一在
variables.scss中定义
scss
// assets/styles/variables.scss
$primary-color: #1890ff;
$font-size-base: 14px;
$border-radius: 4px;
$spacing-unit: 8px;6.2 样式优先级
- 组件样式使用
scoped - 全局样式放在
assets/styles/下 - 尽量使用类选择器,避免标签选择器
- 避免使用
!important
vue
<style lang="scss" scoped>
// ✅ 推荐
.user-card {
padding: 16px;
&__title {
font-size: 16px;
font-weight: bold;
}
}
</style>七、性能优化
7.1 组件懒加载
typescript
// 路由懒加载
const routes = [
{
path: '/user',
component: () => import('@/pages/user/index.vue'),
},
]
// 组件懒加载
const HeavyComponent = defineAsyncComponent(() =>
import('@/components/HeavyComponent.vue')
)7.2 图片优化
- 使用 WebP 格式
- 图片懒加载
loading="lazy" - 小图标使用 SVG Sprite
- 大图使用 CDN
7.3 代码分割
typescript
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vue: ['vue', 'vue-router', 'pinia'],
vendor: ['axios', 'dayjs'],
},
},
},
},
})八、安全规范
8.1 XSS 防护
typescript
// ✅ 使用文本插值而非 v-html
<template>
<p>{{ userContent }}</p>
</template>
// ❌ 避免使用 v-html
<template>
<div v-html="userContent"></div>
</template>8.2 CSRF 防护
- 接口请求携带 CSRF Token
- 敏感操作使用 POST 请求
8.3 敏感信息
typescript
// ❌ 不要将敏感信息硬编码
const API_KEY = 'sk-xxxxxxxxxxxx'
// ✅ 使用环境变量
const API_KEY = import.meta.env.VITE_API_KEY九、代码提交检查
9.1 ESLint 配置
json
{
"extends": [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"@vue/eslint-config-typescript"
],
"rules": {
"no-console": "warn",
"no-unused-vars": "error",
"vue/multi-word-component-names": "off"
}
}9.2 Prettier 配置
json
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"vueIndentScriptAndStyle": true
}9.3 Git Hooks
json
{
"scripts": {
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx --fix",
"format": "prettier --write src/"
},
"lint-staged": {
"*.{vue,js,ts}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["prettier --write"]
}
}十、文档注释规范
10.1 函数注释
typescript
/**
* 格式化日期
* @param date - 日期对象或时间戳
* @param format - 格式化模板,默认 'YYYY-MM-DD'
* @returns 格式化后的日期字符串
* @example
* ```ts
* formatDate(new Date(), 'YYYY/MM/DD') // '2026/06/24'
* ```
*/
function formatDate(date: Date | number, format = 'YYYY-MM-DD'): string {
// ...
}10.2 组件注释
vue
<script setup lang="ts">
/**
* 用户卡片组件
* @description 用于展示用户基本信息的卡片组件
*
* @example
* ```vue
* <UserCard :user="userInfo" @click="handleClick" />
* ```
*/
defineProps<{
/** 用户信息对象 */
user: UserInfo
/** 是否显示关注按钮 */
showFollow?: boolean
}>()
</script>💡 以上规范建议根据团队实际情况进行调整,重要的是保持一致性。