前端开发规范梳理
前端开发规范梳理
前言
前端开发规范是确保团队协作、代码可维护性和项目一致性的重要文档。一个良好的开发规范应该:
- 提高代码可读性,使代码更加易于维护
- 提高团队协作效率,减少沟通成本
- 提高代码质量,减少 bug
- 统一团队技术栈和开发习惯
运行环境
Node.js 版本管理
Node.js 版本管理 使用工具管理不同项目的 Node.js 版本,确保每个项目运行在最佳版本的环境中。
推荐工具:
| 工具 | 特点 | 适用平台 |
|---|---|---|
| Volta | 自动切换,安装一次全局使用 | Mac、Linux、Windows |
| nvm | 功能强大,社区活跃 | Mac、Linux |
| n | 简单轻量 | Mac、Linux |
推荐使用 Volta(2026 年最佳实践):
# 安装 Volta
curl https://get.volta.sh | bash
# 安装特定 Node.js 版本
volta install node@18
# 锁定项目 Node.js 版本
volta pin node@18
包管理器
包管理器(Package Manager) 用于管理项目依赖的工具,不同包管理器有不同的性能和特点。
推荐使用 pnpm(2026 年最佳实践):
| 包管理器 | 特点 | 推荐指数 |
|---|---|---|
| pnpm | 节省磁盘空间、安装速度快 | ⭐⭐⭐⭐⭐ |
| yarn | 功能丰富、社区活跃 | ⭐⭐⭐⭐ |
| npm | 官方默认、兼容性好 | ⭐⭐⭐ |
pnpm 优势:
# 安装 pnpm
npm install -g pnpm
# 使用 pnpm 安装依赖
pnpm install
# 使用 pnpm 启动开发服务器
pnpm dev
# 使用 pnpm 构建
pnpm build
依赖版本管理
lockfile(锁文件) 锁定项目依赖包版本,确保所有开发者使用相同的依赖版本。
| 包管理器 | 锁文件 | 说明 |
|---|---|---|
| pnpm | pnpm-lock.yaml |
推荐使用 pnpm |
| npm | package-lock.json |
npm 默认 |
| yarn | yarn.lock |
yarn 默认 |
最佳实践:
# 将 lockfile 提交到版本控制
git add pnpm-lock.yaml
# 不要提交 node_modules
echo "node_modules/" >> .gitignore
Git 提交规范
Conventional Commits 规范
Conventional Commits(约定式提交) 一种用于提交信息的简单约定,使提交历史更加清晰和易于理解。
提交格式:
<type>(<scope>): <subject>
<body>
<footer>
提交类型(type):
| 类型 | 说明 | 示例 |
|---|---|---|
feat |
新功能 | feat: 添加用户登录功能 |
fix |
修复 bug | fix: 修复用户列表加载失败问题 |
docs |
文档更新 | docs: 更新 README.md |
style |
代码格式(不影响代码运行) | style: 修改代码缩进 |
refactor |
重构(既不是新增功能,也不是修复 bug) | refactor: 重构用户服务模块 |
perf |
性能优化 | perf: 优化列表渲染性能 |
test |
测试 | test: 添加用户服务单元测试 |
chore |
构建过程或辅助工具的变动 | chore: 更新依赖版本 |
ci |
CI 配置文件和脚本的变动 | ci: 添加 GitHub Actions 配置 |
revert |
回滚之前的提交 | revert: 回滚用户登录功能 |
提交示例:
# 新功能
git commit -m "feat(user): 添加用户登录功能"
# 修复 bug
git commit -m "fix(user-list): 修复用户列表加载失败问题"
# 文档更新
git commit -m "docs(readme): 更新 README 文档"
# 性能优化
git commit -m "perf(list): 优化列表渲染性能"
提交信息验证
Commitlint Git 提交信息检查工具,确保提交信息符合规范。
安装配置:
# 安装依赖
pnpm add -D @commitlint/cli @commitlint/config-conventional
# 创建配置文件
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js
Git 钩子
Husky Git 钩子管理工具,在 Git 操作(如提交、推送)前后自动执行脚本。
安装配置:
# 安装 Husky
pnpm add -D husky
# 初始化 Git 钩子
npx husky install
# 添加预提交钩子(运行 lint)
npx husky add .husky/pre-commit "pnpm lint"
# 添加提交信息钩子(运行 commitlint)
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
命名规范
基本原则
所有命名推荐使用语义化命名,命名要具有描述性。
- 禁止使用拼音或拼音缩写
- 禁止使用中文命名
- 可以使用规范缩写(如 API、URL、HTTP)
示例:
// 推荐
const userList = [];
const getUserData = () => {};
// 不推荐
const yhList = []; // 拼音
const 用户列表 = []; // 中文
项目命名
- 小写字母,多个单词用中划线连接
- 示例:
my-project、blog-website - 错误示范:
MyProject、my_project
文件命名
原则:小写字母,多个单词用中划线连接
Vue 组件文件:
- 推荐使用 PascalCase:
UserProfile.vue、HeaderNav.vue - 或使用 kebab-case:
user-profile.vue、header-nav.vue
JavaScript/TypeScript 文件:
- 使用 kebab-case:
user-service.ts、api-client.js
CSS/SCSS 文件:
- 使用 kebab-case:
main.css、user-profile.scss
错误示范:
userProfile.vue(kebab-case 风格项目)API_CLIENT.js(大写)
变量命名
原则:小写字母开头的驼峰命名法(camelCase)
// 推荐
const userName = 'John';
const isLoggedIn = true;
const getUserData = () => {};
// 常量:大写字母,下划线连接
const MAX_SIZE = 100;
const API_URL = 'https://api.example.com';
// 布尔值:is 开头
const isLogin = true;
const hasPermission = false;
函数命名
原则:动词开头,小写字母开头的驼峰命名法
常用动词:
| 功能 | 动词 | 示例 |
|---|---|---|
| 获取 | get |
getUser()、getData() |
| 设置 | set |
setUser()、setData() |
| 创建 | create |
createUser()、createData() |
| 更新 | update |
updateUser()、updateData() |
| 删除 | delete |
deleteUser()、deleteData() |
| 保存 | save |
saveUser()、saveData() |
| 提交 | submit |
submitForm()、submitData() |
| 取消 | cancel |
cancelOrder()、cancelRequest() |
| 关闭 | close |
closeModal()、closeDialog() |
| 打开 | open |
openModal()、openDialog() |
| 显示 | show |
showToast()、showModal() |
| 隐藏 | hide |
hideToast()、hideModal() |
| 加载 | load |
loadData()、loadImage() |
| 刷新 | refresh |
refreshData()、refreshToken() |
示例:
// 推荐
const getUserList = () => {};
const updateUserProfile = () => {};
const deleteUserAccount = () => {};
// 不推荐
const userList = () => {}; // 不是动词开头
const get_user_list = () => {}; // 不是驼峰命名
类命名
原则:大写字母开头的驼峰命名法(PascalCase)
// 推荐
class UserService {}
class UserProfile {}
class ApiClient {}
// 不推荐
class userService {} // 不是大写开头
class user_service {} // 不是驼峰命名
TypeScript 类型命名
原则:大写字母开头的驼峰命名法(PascalCase)
// 推荐接口命名:I 开头(可选)
interface IUser {
name: string;
}
// 推荐类型别名
type UserType = 'admin' | 'user';
// 推荐枚举
enum UserRole {
Admin = 'admin',
User = 'user',
}
// 推荐泛型:T 开头
interface ApiResponse<T> {
data: T;
}
HTML 规范
文档结构
推荐使用 HTML5 文档类型:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="页面描述">
<link rel="canonical" href="https://example.com">
<title>页面标题</title>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>
语义化标签
语义化 HTML(Semantic HTML) 使用具有语义含义的标签(如 header、nav、article、section)来构建页面结构,提高可访问性和 SEO。
常用语义化标签:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<!-- 头部 -->
<header>
<nav>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
<li><a href="/contact">联系</a></li>
</ul>
</nav>
</header>
<!-- 主体内容 -->
<main>
<article>
<h1>文章标题</h1>
<p>文章内容...</p>
</article>
<aside>
<h3>侧边栏</h3>
<ul>
<li><a href="/link1">链接1</a></li>
<li><a href="/link2">链接2</a></li>
</ul>
</aside>
</main>
<!-- 底部 -->
<footer>
<p>© 2026 My Website</p>
</footer>
</body>
</html>
元素属性
原则:
- 所有元素和属性必须使用小写字母
- 属性值必须用双引号括起来
- 自定义属性使用
data-*前缀
示例:
<!-- 推荐 -->
<img src="image.jpg" alt="图片描述" loading="lazy">
<a href="https://example.com" target="_blank" rel="noopener">链接</a>
<button type="button" data-action="submit">提交</button>
<!-- 不推荐 -->
<img src='image.jpg'> <!-- 单引号 -->
<a href="#" target="_blank">链接</a> <!-- 缺少 rel="noopener" -->
无障碍访问
无障碍访问(Accessibility,a11y) 确保网站对所有用户(包括残障用户)都可访问。
最佳实践:
<!-- 图片 alt 属性 -->
<img src="image.jpg" alt="图片描述">
<!-- 表单 label -->
<label for="username">用户名</label>
<input type="text" id="username" name="username">
<!-- 按钮文本 -->
<button type="button">提交</button>
<!-- ARIA 属性 -->
<button aria-label="关闭对话框" aria-pressed="false">关闭</button>
<div role="dialog" aria-modal="true">对话框内容</div>
性能优化
<!-- 预加载关键资源 -->
<link rel="preload" href="styles.css" as="style">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<!-- 预连接到重要域名 -->
<link rel="preconnect" href="https://api.example.com">
<!-- 懒加载图片 -->
<img src="image.jpg" loading="lazy" decoding="async">
<!-- 异步加载脚本 -->
<script src="script.js" async></script>
<script src="script.js" defer></script>
CSS 规范
文件组织
推荐使用 CSS Modules 或 CSS-in-JS:
// CSS Modules
import styles from './UserProfile.module.css';
function UserProfile() {
return <div className={styles.container}>用户资料</div>;
}
/* CSS Modules */
.container {
max-width: 1200px;
margin: 0 auto;
}
.title {
font-size: 24px;
font-weight: 600;
}
命名规范
原则:小写字母,多个单词用中划线连接(kebab-case)
/* 推荐 */
.user-profile {
/* 样式 */
}
.user-name {
/* 样式 */
}
/* 不推荐 */
.userProfile { /* 不是 kebab-case */
/* 样式 */
}
.user_name { /* 不是 kebab-case */
/* 样式 */
}
CSS 变量
CSS 变量(Custom Properties) CSS 自定义属性,用于定义可重用的值,便于主题切换和维护。
示例:
/* 定义 CSS 变量 */
:root {
--primary-color: #1890ff;
--secondary-color: #52c41a;
--text-color: #333333;
--background-color: #ffffff;
--border-color: #e8e8e8;
--border-radius: 4px;
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--font-size-base: 14px;
}
/* 使用 CSS 变量 */
.button {
background-color: var(--primary-color);
color: var(--text-color);
border-radius: var(--border-radius);
padding: var(--spacing-sm) var(--spacing-md);
}
代码格式
缩进:使用 2 个空格
属性顺序:按照功能分组
.box {
/* 定位属性 */
position: relative;
top: 0;
left: 0;
z-index: 1;
/* 盒子模型属性 */
display: flex;
width: 100%;
height: auto;
margin: 0 auto;
padding: 16px;
border: 1px solid #e8e8e8;
border-radius: 4px;
/* 文本属性 */
font-size: 14px;
font-weight: 400;
color: #333333;
text-align: center;
line-height: 1.5;
/* 背景属性 */
background-color: #ffffff;
background-image: none;
/* 其他属性 */
opacity: 1;
transition: all 0.3s ease;
}
选择器规范
避免使用:
- 通配符选择器
* - 标签选择器
- ID 选择器
- 嵌套过深(最多 3 层)
推荐使用:
- 类选择器
- 子选择器
> - 伪类选择器
/* 不推荐 */
* {
margin: 0;
padding: 0;
}
h1 {
color: red;
}
#container {
/* 样式 */
}
/* 推荐 */
.container {
margin: 0;
padding: 0;
}
.title {
color: red;
}
.container > .item {
/* 样式 */
}
响应式设计
使用媒体查询(Media Queries):
/* 移动优先设计 */
.container {
width: 100%;
padding: 16px;
}
/* 平板 */
@media (min-width: 768px) {
.container {
max-width: 768px;
padding: 24px;
}
}
/* 桌面 */
@media (min-width: 1024px) {
.container {
max-width: 1024px;
padding: 32px;
}
}
JavaScript 规范
TypeScript 优先
TypeScript JavaScript 的超集,添加了类型系统和其他特性,提高代码质量和开发效率。
推荐使用 TypeScript:
// 定义接口
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
// 定义类型
type UserRole = 'admin' | 'user' | 'guest';
// 定义函数
async function getUserById(id: string): Promise<User | null> {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
return data;
}
// 使用类型
const user: User = {
id: '1',
name: 'John',
email: 'john@example.com',
createdAt: new Date(),
};
变量声明
使用 let 和 const,避免使用 var:
// 推荐
const userName = 'John';
let isLoggedIn = true;
// 不推荐
var userName = 'John';
var isLoggedIn = true;
箭头函数
推荐使用箭头函数:
// 推荐
const getUserData = () => {};
const handleClick = (event) => {};
// 回调函数
users.map(user => user.name);
// 不推荐
function getUserData() {}
const handleClick = function(event) {};
模板字符串
推荐使用模板字符串:
// 推荐
const message = `Hello, ${userName}!`;
// 不推荐
const message = 'Hello, ' + userName + '!';
解构赋值
推荐使用解构赋值:
// 对象解构
const { name, email } = user;
// 数组解构
const [first, second] = list;
// 函数参数解构
function createUser({ name, email, age }) {
// ...
}
异步编程
推荐使用 async/await:
// 推荐
async function fetchUser() {
try {
const response = await fetch('/api/user');
const data = await response.json();
return data;
} catch (error) {
console.error('获取用户失败:', error);
throw error;
}
}
// 不推荐
function fetchUser() {
return fetch('/api/user')
.then(response => response.json())
.catch(error => {
console.error('获取用户失败:', error);
throw error;
});
}
错误处理
推荐使用 try-catch 处理错误:
async function getUserData(id: string) {
try {
const user = await getUserById(id);
return user;
} catch (error) {
console.error('获取用户失败:', error);
return null;
}
}
代码风格
使用 ESLint 和 Prettier:
// 安装依赖
pnpm add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin prettier eslint-config-prettier eslint-plugin-prettier
// ESLint 配置
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
plugins: ['@typescript-eslint', 'prettier'],
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'off',
},
};
// Prettier 配置
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 80,
tabWidth: 2,
useTabs: false,
};
Vue 3 规范
组件命名
原则:使用 PascalCase 或 kebab-case
<!-- 推荐:PascalCase -->
<template>
<UserProfile />
</template>
<!-- 推荐:kebab-case -->
<template>
<user-profile />
</template>
组件结构
推荐顺序:
<script setup lang="ts">
// 1. 导入
import { ref, computed, onMounted } from 'vue';
import type { User } from '@/types/user';
// 2. Props 和 Emits
interface Props {
userId: string;
}
interface Emits {
(e: 'update', value: string): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
// 3. 响应式状态
const loading = ref(false);
const user = ref<User | null>(null);
// 4. 计算属性
const userName = computed(() => user.value?.name ?? '');
// 5. 方法
const fetchUserData = async () => {
loading.value = true;
try {
const data = await getUserById(props.userId);
user.value = data;
} catch (error) {
console.error('获取用户失败:', error);
} finally {
loading.value = false;
}
};
// 6. 生命周期
onMounted(() => {
fetchUserData();
});
</script>
<template>
<div v-if="loading">加载中...</div>
<div v-else-if="user">
<h1>{{ userName }}</h1>
</div>
<div v-else>用户不存在</div>
</template>
<style scoped>
.container {
padding: 16px;
}
</style>
组合式函数
Composables(组合式函数) 使用 Vue Composition API 封装可复用的逻辑。
// composables/useUser.ts
import { ref } from 'vue';
import type { User } from '@/types/user';
export function useUser() {
const loading = ref(false);
const user = ref<User | null>(null);
const fetchUser = async (id: string) => {
loading.value = true;
try {
const data = await getUserById(id);
user.value = data;
} catch (error) {
console.error('获取用户失败:', error);
} finally {
loading.value = false;
}
};
return {
loading,
user,
fetchUser,
};
}
// 使用
<script setup lang="ts">
import { useUser } from '@/composables/useUser';
const { loading, user, fetchUser } = useUser();
onMounted(() => {
fetchUser('1');
});
</script>
前端工程化
目录结构
推荐目录结构:
src/
├── assets/ # 静态资源
│ ├── images/ # 图片
│ ├── fonts/ # 字体
│ └── styles/ # 全局样式
├── components/ # 公共组件
│ ├── common/ # 通用组件
│ └── business/ # 业务组件
├── composables/ # 组合式函数
├── layouts/ # 布局组件
├── pages/ # 页面组件
├── router/ # 路由配置
├── stores/ # 状态管理
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数
├── App.vue # 根组件
└── main.ts # 入口文件
环境变量
环境变量(Environment Variables)
- 用于存储不同环境的配置信息,如 API 地址、密钥等。
使用环境变量:
// .env.development
VITE_API_BASE_URL=http://localhost:3000
VITE_APP_TITLE=开发环境
// .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_APP_TITLE=生产环境
// 使用
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
构建优化
Vite 配置优化:
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
build: {
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'pinia'],
'ui-vendor': ['element-plus'],
},
},
},
chunkSizeWarningLimit: 1000,
},
server: {
port: 3000,
open: true,
},
});
代码审查
Pull Request 规范
PR 标题格式:<type>: <subject>
PR 描述模板:
## 📝 变更说明
- [ ] 新功能
- [ ] 修复 Bug
- [ ] 性能优化
- [ ] 重构
- [ ] 文档更新
- [ ] 其他
## 🎯 变更类型
- [ ] Major(不兼容的 API 变更)
- [ ] Minor(向后兼容的功能性新增)
- [ ] Patch(向后兼容的问题修正)
## ✅ 测试
- [ ] 单元测试
- [ ] 集成测试
- [ ] 端到端测试
## 📸 截图或录屏
(如果是 UI 变更,请添加截图或录屏)
## 🔗 关联 Issue
Closes #xxx
Code Review 检查清单
- [ ] 代码符合项目规范
- [ ] 添加了必要的注释
- [ ] 没有 console.log、debugger 等调试代码
- [ ] 没有注释的代码
- [ ] 代码结构清晰,易于理解
- [ ] 添加了必要的错误处理
- [ ] 添加了必要的类型定义
- [ ] 性能优化合理
- [ ] 无安全漏洞
结语
前端开发规范是团队协作的重要基础,遵循规范可以:
- 提高代码质量:统一规范减少代码错误
- 提高开发效率:减少沟通成本,快速上手
- 提高可维护性:代码结构清晰,易于维护
- 提高团队协作:统一规范,便于协作
记住:规范是为了更好地服务开发,而不是限制开发。在实际开发中,可以根据项目情况灵活调整。
参考资源: