前端开发规范梳理

前言

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

  • 提高代码可读性,使代码更加易于维护
  • 提高团队协作效率,减少沟通成本
  • 提高代码质量,减少 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(锁文件) 锁定项目依赖包版本,确保所有开发者使用相同的依赖版本。

包管理器锁文件说明
pnpmpnpm-lock.yaml推荐使用 pnpm
npmpackage-lock.jsonnpm 默认
yarnyarn.lockyarn 默认

最佳实践

# 将 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修复 bugfix: 修复用户列表加载失败问题
docs文档更新docs: 更新 README.md
style代码格式(不影响代码运行)style: 修改代码缩进
refactor重构(既不是新增功能,也不是修复 bug)refactor: 重构用户服务模块
perf性能优化perf: 优化列表渲染性能
test测试test: 添加用户服务单元测试
chore构建过程或辅助工具的变动chore: 更新依赖版本
ciCI 配置文件和脚本的变动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

函数命名

原则:动词开头,小写字母开头的驼峰命名法

常用动词

功能动词示例
获取getgetUser()getData()
设置setsetUser()setData()
创建createcreateUser()createData()
更新updateupdateUser()updateData()
删除deletedeleteUser()deleteData()
保存savesaveUser()saveData()
提交submitsubmitForm()submitData()
取消cancelcancelOrder()cancelRequest()
关闭closecloseModal()closeDialog()
打开openopenModal()openDialog()
显示showshowToast()showModal()
隐藏hidehideToast()hideModal()
加载loadloadData()loadImage()
刷新refreshrefreshData()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. 提高团队协作:统一规范,便于协作

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


参考资源