一点代码规范 自用

前端开发编码规范

目录

  • 项目结构规范
  • 命名规范
  • [Vue3 编码规范](#Vue3 编码规范 "#vue3-%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83")
  • [TypeScript 规范](#TypeScript 规范 "#typescript-%E8%A7%84%E8%8C%83")
  • [CSS/SCSS 规范](#CSS/SCSS 规范 "#cssscss-%E8%A7%84%E8%8C%83")
  • [Git 提交规范](#Git 提交规范 "#git-%E6%8F%90%E4%BA%A4%E8%A7%84%E8%8C%83")
  • 代码质量规范

项目结构规范

目录结构

csharp 复制代码
src/
├── api/                    # API 接口
│   ├── index.ts           # API 统一导出
│   ├── login.ts           # 登录相关接口
│   └── system.ts          # 系统相关接口
├── assets/                 # 静态资源
│   ├── images/            # 图片资源
│   ├── icons/             # 图标资源
│   └── styles/            # 样式资源
├── components/             # 公共组件
│   ├── index.ts           # 组件统一导出
│   └── common/            # 通用组件
├── hooks/                  # 组合式函数
│   └── index.ts           # hooks 统一导出
├── layout/                 # 布局组件
├── router/                 # 路由配置
│   ├── index.ts           # 路由主文件
│   └── routes.ts          # 路由配置
├── store/                  # 状态管理
│   ├── index.ts           # store 主文件
│   └── modules/           # store 模块
├── styles/                 # 全局样式
│   ├── index.scss         # 样式入口
│   ├── var.css            # CSS 变量
│   └── theme.scss         # 主题样式
├── types/                  # 类型定义
├── utils/                  # 工具函数
│   ├── index.ts           # 工具函数统一导出
│   ├── request.ts         # 请求封装
│   └── validator.ts       # 验证工具
└── views/                  # 页面组件
    ├── index/             # 首页
    ├── login/             # 登录页
    └── detail/            # 详情页

文件命名规范

  • 组件文件 : 使用 PascalCase,如 UserProfile.vue
  • 页面文件 : 使用 kebab-case,如 user-detail.vue
  • 工具文件 : 使用 camelCase,如 formatDate.ts
  • 样式文件 : 使用 kebab-case,如 user-profile.scss
  • 类型文件 : 使用 camelCase,如 userTypes.ts

命名规范

变量命名

typescript 复制代码
// ✅ 正确
const userName = 'John'
const userList = []
const isLoading = false
const API_BASE_URL = 'https://api.example.com'

// ❌ 错误
const user_name = 'John'
const userlist = []
const is_loading = false
const apiBaseUrl = 'https://api.example.com'

函数命名

typescript 复制代码
// ✅ 正确
const getUserInfo = () => {}
const handleClick = () => {}
const formatDate = (date: Date) => {}
const validateEmail = (email: string) => {}

// ❌ 错误
const get_user_info = () => {}
const click = () => {}
const date = (date: Date) => {}
const email = (email: string) => {}

组件命名

vue 复制代码
<!-- ✅ 正确 -->
<script setup lang="ts">
// 组件名使用 PascalCase
defineOptions({
  name: 'UserProfile'
})
</script>

<!-- ❌ 错误 -->
<script setup lang="ts">
defineOptions({
  name: 'user-profile'
})
</script>

Vue3 编码规范

组件结构

vue 复制代码
<template>
  <!-- 模板内容 -->
</template>

<script setup lang="ts">
// 1. 导入语句
import { ref, computed, onMounted } from 'vue'
import type { PropType } from 'vue'

// 2. 类型定义
interface User {
  id: number
  name: string
  email: string
}

// 3. Props 定义
interface Props {
  user: User
  loading?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  loading: false
})

// 4. Emits 定义
interface Emits {
  update: [user: User]
  delete: [id: number]
}

const emit = defineEmits<Emits>()

// 5. 响应式数据
const userName = ref('')
const userList = ref<User[]>([])

// 6. 计算属性
const filteredUsers = computed(() => {
  return userList.value.filter(user => 
    user.name.includes(userName.value)
  )
})

// 7. 方法定义
const handleUpdate = (user: User) => {
  emit('update', user)
}

const handleDelete = (id: number) => {
  emit('delete', id)
}

// 8. 生命周期
onMounted(() => {
  // 初始化逻辑
})

// 9. 暴露给父组件的方法
defineExpose({
  refresh: () => {
    // 刷新逻辑
  }
})
</script>

<style lang="scss" scoped>
/* 样式内容 */
</style>

Props 规范

vue 复制代码
<script setup lang="ts">
// ✅ 推荐:使用 TypeScript 接口定义
interface Props {
  title: string
  count?: number
  items: string[]
  user: {
    id: number
    name: string
  }
}

const props = withDefaults(defineProps<Props>(), {
  count: 0
})

// ❌ 不推荐:使用 PropType
const props = defineProps({
  title: String,
  count: {
    type: Number,
    default: 0
  }
})
</script>

事件处理

vue 复制代码
<template>
  <!-- ✅ 正确:使用 handle 前缀 -->
  <button @click="handleClick">点击</button>
  <input @input="handleInput" />
  <form @submit="handleSubmit">提交</form>
  
  <!-- ❌ 错误:直接使用动词 -->
  <button @click="click">点击</button>
  <input @input="input" />
</template>

<script setup lang="ts">
const handleClick = () => {
  // 处理点击事件
}

const handleInput = (event: Event) => {
  // 处理输入事件
}

const handleSubmit = (event: Event) => {
  // 处理提交事件
}
</script>

响应式数据

vue 复制代码
<script setup lang="ts">
// ✅ 正确:使用 ref 和 reactive
const count = ref(0)
const user = reactive({
  name: '',
  email: ''
})

// ✅ 正确:使用 computed
const doubleCount = computed(() => count.value * 2)

// ✅ 正确:使用 watch
watch(count, (newVal, oldVal) => {
  console.log(`count changed from ${oldVal} to ${newVal}`)
})

// ❌ 错误:直接修改 props
const updateProps = () => {
  props.title = 'new title' // 错误!
}
</script>

TypeScript 规范

类型定义

typescript 复制代码
// ✅ 正确:使用 interface 定义对象类型
interface User {
  id: number
  name: string
  email: string
  age?: number
}

// ✅ 正确:使用 type 定义联合类型
type Status = 'pending' | 'success' | 'error'
type UserRole = 'admin' | 'user' | 'guest'

// ✅ 正确:使用 enum 定义枚举
enum UserStatus {
  ACTIVE = 'active',
  INACTIVE = 'inactive',
  DELETED = 'deleted'
}

// ✅ 正确:使用泛型
interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

// ❌ 错误:使用 any
const user: any = { name: 'John' }

函数类型

typescript 复制代码
// ✅ 正确:函数类型定义
const getUserById = (id: number): Promise<User> => {
  return fetch(`/api/users/${id}`).then(res => res.json())
}

// ✅ 正确:回调函数类型
const handleUserUpdate = (callback: (user: User) => void) => {
  // 处理逻辑
}

// ✅ 正确:可选参数和默认值
const formatDate = (date: Date, format?: string): string => {
  // 格式化逻辑
  return date.toISOString()
}

// ❌ 错误:缺少类型注解
const getUser = (id) => {
  return fetch(`/api/users/${id}`)
}

类型断言

typescript 复制代码
// ✅ 正确:使用 as 进行类型断言
const element = document.getElementById('app') as HTMLElement

// ✅ 正确:使用尖括号语法(不推荐,与 JSX 冲突)
const element = <HTMLElement>document.getElementById('app')

// ✅ 正确:使用类型守卫
const isUser = (obj: any): obj is User => {
  return obj && typeof obj.id === 'number' && typeof obj.name === 'string'
}

// ❌ 错误:过度使用类型断言
const user = {} as User // 可能导致运行时错误

CSS/SCSS 规范

类名命名

scss 复制代码
// ✅ 正确:使用 BEM 命名规范
.user-profile {
  &__header {
    // 用户资料头部
  }
  
  &__content {
    // 用户资料内容
  }
  
  &__footer {
    // 用户资料底部
  }
  
  &--active {
    // 激活状态
  }
  
  &--disabled {
    // 禁用状态
  }
}

// ✅ 正确:使用 kebab-case
.user-list {
  .user-item {
    .user-name {
      // 用户名样式
    }
  }
}

// ❌ 错误:使用驼峰命名
.userProfile {
  .userName {
    // 不推荐
  }
}

样式组织

scss 复制代码
// ✅ 正确:按功能组织样式
.user-card {
  // 1. 布局属性
  display: flex;
  flex-direction: column;
  gap: 1rem;
  
  // 2. 尺寸属性
  width: 100%;
  max-width: 400px;
  height: auto;
  
  // 3. 间距属性
  padding: 1rem;
  margin: 0 auto;
  
  // 4. 背景属性
  background-color: #fff;
  border-radius: 8px;
  
  // 5. 边框属性
  border: 1px solid #e0e0e0;
  
  // 6. 字体属性
  font-size: 14px;
  line-height: 1.5;
  color: #333;
  
  // 7. 其他属性
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  
  // 8. 伪类
  &:hover {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  }
  
  // 9. 子元素
  &__title {
    font-weight: bold;
    margin-bottom: 0.5rem;
  }
  
  &__content {
    flex: 1;
  }
}

变量使用

scss 复制代码
// ✅ 正确:使用 CSS 变量
:root {
  --primary-color: #1890ff;
  --secondary-color: #52c41a;
  --text-color: #333;
  --border-color: #e0e0e0;
  --border-radius: 8px;
  --spacing-xs: 4px;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 24px;
  --spacing-xl: 32px;
}

.button {
  background-color: var(--primary-color);
  border-radius: var(--border-radius);
  padding: var(--spacing-sm) var(--spacing-md);
}

// ✅ 正确:使用 SCSS 变量
$primary-color: #1890ff;
$secondary-color: #52c41a;
$border-radius: 8px;

.button {
  background-color: $primary-color;
  border-radius: $border-radius;
}

Git 提交规范

提交信息格式

xml 复制代码
<type>(<scope>): <subject>

<body>

<footer>

类型说明

  • feat: 新功能
  • fix: 修复 bug
  • docs: 文档更新
  • style: 代码格式调整
  • refactor: 代码重构
  • perf: 性能优化
  • test: 测试相关
  • chore: 构建过程或辅助工具的变动

示例

bash 复制代码
# ✅ 正确
feat(user): 添加用户登录功能
fix(api): 修复用户列表接口错误
docs(readme): 更新项目说明文档
style(components): 调整按钮组件样式
refactor(utils): 重构日期格式化函数
perf(images): 优化图片加载性能
test(login): 添加登录组件单元测试
chore(deps): 更新依赖包版本

# ❌ 错误
update code
fix bug
add feature

代码质量规范

代码注释

typescript 复制代码
// ✅ 正确:函数注释
/**
 * 格式化日期为指定格式
 * @param date 日期对象
 * @param format 格式化字符串,默认为 'YYYY-MM-DD'
 * @returns 格式化后的日期字符串
 * @example
 * formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss')
 * // => '2024-01-01 12:00:00'
 */
const formatDate = (date: Date, format: string = 'YYYY-MM-DD'): string => {
  // 实现逻辑
}

// ✅ 正确:复杂逻辑注释
// 根据用户权限过滤菜单项
const filteredMenus = menus.filter(menu => {
  // 检查用户是否有访问权限
  if (!hasPermission(user.role, menu.permission)) {
    return false
  }
  
  // 检查菜单是否在用户可见范围内
  if (menu.hidden && !user.isAdmin) {
    return false
  }
  
  return true
})

// ❌ 错误:无意义的注释
// 这是一个变量
const name = 'John'

// 这是一个函数
const getName = () => {
  return name
}

错误处理

typescript 复制代码
// ✅ 正确:使用 try-catch 处理异步错误
const fetchUserData = async (userId: number): Promise<User> => {
  try {
    const response = await fetch(`/api/users/${userId}`)
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }
    
    const data = await response.json()
    return data
  } catch (error) {
    console.error('Failed to fetch user data:', error)
    throw new Error('获取用户数据失败')
  }
}

// ✅ 正确:使用 Result 模式
interface Result<T> {
  success: boolean
  data?: T
  error?: string
}

const getUserData = async (userId: number): Promise<Result<User>> => {
  try {
    const user = await fetchUserData(userId)
    return { success: true, data: user }
  } catch (error) {
    return { 
      success: false, 
      error: error instanceof Error ? error.message : '未知错误' 
    }
  }
}

性能优化

vue 复制代码
<script setup lang="ts">
// ✅ 正确:使用 v-memo 优化列表渲染
<template>
  <div v-for="item in list" :key="item.id" v-memo="[item.id, item.name]">
    {{ item.name }}
  </div>
</template>

// ✅ 正确:使用 computed 缓存计算结果
const expensiveValue = computed(() => {
  return heavyCalculation(props.data)
})

// ✅ 正确:使用 watchEffect 自动清理副作用
watchEffect((onCleanup) => {
  const timer = setInterval(() => {
    // 定时器逻辑
  }, 1000)
  
  onCleanup(() => {
    clearInterval(timer)
  })
})

// ✅ 正确:使用 defineAsyncComponent 懒加载组件
const AsyncComponent = defineAsyncComponent(() => import('./HeavyComponent.vue'))
</script>

工具配置

ESLint 配置

json 复制代码
{
  "extends": [
    "@vue/eslint-config-typescript",
    "@vue/eslint-config-prettier"
  ],
  "rules": {
    "vue/multi-word-component-names": "off",
    "vue/no-unused-vars": "error",
    "@typescript-eslint/no-unused-vars": "error",
    "@typescript-eslint/explicit-function-return-type": "warn"
  }
}

Prettier 配置

json 复制代码
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80,
  "bracketSpacing": true,
  "arrowParens": "avoid"
}

TypeScript 配置

json 复制代码
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}

总结

遵循以上编码规范可以:

  1. 提高代码可读性和可维护性
  2. 减少团队协作中的沟通成本
  3. 降低代码出错概率
  4. 提升开发效率
相关推荐
盏茶作酒29几秒前
自己实现Promise.all
前端
極光未晚16 分钟前
从卡顿到丝滑:我给 React 项目「踩油门」的那些事
前端·react.js·性能优化
Hilaku22 分钟前
这几个CSS和JS新特性,将在2026年变流行
前端·javascript·css
拾光拾趣录23 分钟前
如何高效判断DOM元素是否进入可视区域
前端·性能优化·dom
阿白的白日梦25 分钟前
为 Vue3 + TypeScript + Vite 项目配置 Prettier代码格式化
前端
外啫啫25 分钟前
基于n-scrollbar,滚动到列表指定位置
前端
好奇de悟空27 分钟前
复合二进制文档 - 文档结构提取(中篇)
前端·javascript
好奇de悟空28 分钟前
复合二进制文档 - msi文件信息提取(下篇)
前端·javascript
Running_C30 分钟前
深入理解 HTTP 缓存:从原理到实践
前端·面试
布兰妮甜31 分钟前
Vite:下一代前端构建工具的革命
前端·javascript·vite·构建工具