前端开发规范梳理

前言

前端开发规范是确保团队协作、代码可维护性和项目一致性的重要文档。一个良好的开发规范应该:

  • 提高代码可读性,使代码更加易于维护
  • 提高团队协作效率,减少沟通成本
  • 提高代码质量,减少 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-projectblog-website
  • 错误示范MyProjectmy_project

文件命名

原则:小写字母,多个单词用中划线连接

Vue 组件文件

  • 推荐使用 PascalCase:UserProfile.vueHeaderNav.vue
  • 或使用 kebab-case:user-profile.vueheader-nav.vue

JavaScript/TypeScript 文件

  • 使用 kebab-case:user-service.tsapi-client.js

CSS/SCSS 文件

  • 使用 kebab-case:main.cssuser-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>&copy; 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 等调试代码
  • [ ] 没有注释的代码
  • [ ] 代码结构清晰,易于理解
  • [ ] 添加了必要的错误处理
  • [ ] 添加了必要的类型定义
  • [ ] 性能优化合理
  • [ ] 无安全漏洞

结语

前端开发规范是团队协作的重要基础,遵循规范可以:

  1. 提高代码质量:统一规范减少代码错误
  2. 提高开发效率:减少沟通成本,快速上手
  3. 提高可维护性:代码结构清晰,易于维护
  4. 提高团队协作:统一规范,便于协作

记住:规范是为了更好地服务开发,而不是限制开发。在实际开发中,可以根据项目情况灵活调整。


参考资源