Skip to content

开发规范开发文档

1. 概述

本文档定义了梵医云前端项目的开发规范,旨在确保团队成员遵循统一的编码风格、项目结构和开发流程,提高代码质量和协作效率。

1.1 规范目标

  • 统一性:确保代码风格一致,降低维护成本
  • 可读性:提高代码可读性,便于团队协作
  • 可维护性:提高代码可维护性,便于后续扩展
  • 效率性:提高开发效率,减少重复工作

1.2 适用范围

本规范适用于梵医云前端项目的所有开发人员,包括但不限于:

  • 新功能开发
  • Bug修复
  • 代码重构
  • 文档编写

2. 开发环境规范

2.1 环境要求

工具版本要求说明
Node.js>= 16.18.0JavaScript运行环境
pnpm>= 8.6.0包管理器(强制使用)
VS Code最新版推荐的代码编辑器

2.2 必装VS Code插件

插件名功能用途
Vue - OfficialVue与TypeScript支持Vue3语法高亮和智能提示
unocssunocss for vscodeUnoCSS智能提示
Iconify IntelliSenseIconify预览和搜索图标预览和搜索
i18n Ally国际化智能提示国际化文本管理
StylelintCss格式化CSS代码检查和格式化
Prettier代码格式化代码格式化
ESLint脚本代码检查JavaScript/TypeScript代码检查
DotENVenv文件高亮环境变量文件高亮
Path Intellisense路径智能提示文件路径自动补全
GitLensGit增强Git历史和代码作者信息

2.3 VS Code配置

编辑器配置

在 [.vscode/settings.json](file:///e:/git.fanyicloud.com.cn/fanyi-cloud-ui/.vscode/settings.json) 中配置:

json
{
  "editor.tabSize": 2,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "files.eol": "\n",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  }
}

文件排除配置

json
{
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/.git": true
  },
  "files.exclude": {
    "**/.cache": true,
    "**/.eslintcache": true
  }
}

国际化配置

json
{
  "i18n-ally.localesPaths": ["src/locales"],
  "i18n-ally.keystyle": "nested",
  "i18n-ally.sortKeys": true,
  "i18n-ally.sourceLanguage": "en",
  "i18n-ally.displayLanguage": "zh-CN"
}

3. 代码风格规范

3.1 命名规范

文件命名

类型命名规则示例
Vue组件PascalCaseUserProfile.vue
TypeScript文件camelCaseuserService.ts
工具函数camelCaseformatDate.ts
常量文件camelCaseconstants.ts
类型定义camelCaseuserTypes.ts
样式文件camelCaseuserStyle.scss

变量命名

typescript
// 常量:UPPER_SNAKE_CASE
const MAX_COUNT = 100
const API_BASE_URL = 'https://api.example.com'

// 变量:camelCase
const userName = '张三'
const isLoggedIn = true

// 函数:camelCase
const getUserInfo = () => {}
const handleSubmit = () => {}

// 类:PascalCase
class UserService {}
class HttpClient {}

// 接口:PascalCase
interface UserInfo {}
interface ApiResponse {}

// 类型:PascalCase
type UserRole = 'admin' | 'user'
type UserStatus = 'active' | 'inactive'

// 枚举:PascalCase
enum UserRole {
  Admin = 'admin',
  User = 'user'
}

// 组件名:PascalCase
const UserProfile = defineComponent({
  name: 'UserProfile'
})

// 私有变量:下划线前缀
const _privateVar = 'private'
const _privateMethod = () => {}

组件命名

vue
<!-- 推荐:多词组件名 -->
<script setup lang="ts">
const UserProfile = defineComponent({
  name: 'UserProfile'
})
</script>

<!-- 不推荐:单词组件名 -->
<script setup lang="ts">
const Header = defineComponent({
  name: 'Header'
})
</script>

3.2 代码格式规范

缩进和空格

typescript
// 使用2个空格缩进
function example() {
  const obj = {
    name: '张三',
    age: 25
  }
  
  if (condition) {
    doSomething()
  }
}

// 对象属性冒号后加空格
const obj = { name: '张三', age: 25 }

// 运算符前后加空格
const sum = a + b
const result = a === b ? c : d

// 逗号后加空格
const arr = [1, 2, 3, 4, 5]

引号使用

typescript
// 优先使用单引号
const name = '张三'
const message = 'Hello, World!'

// JSON中使用双引号
const json = '{"name": "张三", "age": 25}'

// 模板字符串中使用反引号
const message = `你好,${name}`

分号使用

typescript
// 不使用分号(根据Prettier配置)
const name = '张三'
const age = 25

function greet() {
  console.log('Hello')
}

行长度

typescript
// 每行最大100个字符
const longString = '这是一段很长的字符串,需要换行显示以保持代码的可读性'

// 超过100字符时换行
const result = someFunction(
  arg1,
  arg2,
  arg3
)

3.3 注释规范

单行注释

typescript
// 简短说明
const MAX_COUNT = 100 // 最大数量限制

// 解释代码意图
const userAge = calculateAge(birthDate) // 计算用户年龄

多行注释

typescript
/**
 * 计算用户年龄
 * @param birthDate 出生日期
 * @returns 年龄
 */
const calculateAge = (birthDate: Date): number => {
  const today = new Date()
  const birth = new Date(birthDate)
  let age = today.getFullYear() - birth.getFullYear()
  const monthDiff = today.getMonth() - birth.getMonth()
  
  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
    age--
  }
  
  return age
}

JSDoc注释

typescript
/**
 * 用户服务类
 * @description 提供用户相关的业务逻辑
 * @author 张三
 * @date 2024-01-01
 */
class UserService {
  /**
   * 获取用户信息
   * @param userId 用户ID
   * @returns 用户信息
   * @throws {Error} 当用户不存在时抛出错误
   */
  async getUserInfo(userId: number): Promise<UserInfo> {
    // ...
  }
}

TODO和FIXME

typescript
// TODO: 待办事项,需要完成的功能
// TODO: 添加用户验证逻辑

// FIXME: 需要修复的问题
// FIXME: 这个方法有性能问题,需要优化

// HACK: 临时解决方案
// HACK: 临时绕过验证,后续需要修复

// XXX: 警告或需要注意的地方
// XXX: 这个方法有副作用,使用时要注意

4. Vue组件规范

4.1 组件结构

vue
<template>
  <!-- 模板内容 -->
</template>

<script setup lang="ts">
// 1. 导入
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'

// 2. Props定义
interface Props {
  userId: number
  userName?: string
}
const props = withDefaults(defineProps<Props>(), {
  userName: ''
})

// 3. Emits定义
interface Emits {
  (e: 'update:modelValue', value: string): void
  (e: 'submit', data: FormData): void
}
const emit = defineEmits<Emits>()

// 4. 响应式数据
const userInfo = ref<UserInfo | null>(null)
const loading = ref(false)

// 5. 计算属性
const displayName = computed(() => {
  return props.userName || userInfo.value?.name || '未知用户'
})

// 6. 方法
const fetchUserInfo = async () => {
  loading.value = true
  try {
    userInfo.value = await getUserInfo(props.userId)
  } finally {
    loading.value = false
  }
}

const handleSubmit = (data: FormData) => {
  emit('submit', data)
}

// 7. 生命周期
onMounted(() => {
  fetchUserInfo()
})
</script>

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

4.2 Props规范

typescript
// 使用TypeScript定义Props
interface Props {
  userId: number
  userName?: string
  userStatus: 'active' | 'inactive'
  userRoles: string[]
}

// 设置默认值
const props = withDefaults(defineProps<Props>(), {
  userName: '',
  userStatus: 'active',
  userRoles: () => []
})

// Props验证(可选)
const props = defineProps({
  userId: {
    type: Number,
    required: true,
    validator: (value: number) => value > 0
  },
  userName: {
    type: String,
    default: ''
  }
})

4.3 Emits规范

typescript
// 使用TypeScript定义Emits
interface Emits {
  (e: 'update:modelValue', value: string): void
  (e: 'submit', data: FormData): void
  (e: 'cancel'): void
}
const emit = defineEmits<Emits>()

// 触发事件
const handleUpdate = (value: string) => {
  emit('update:modelValue', value)
}

const handleSubmit = (data: FormData) => {
  emit('submit', data)
}

const handleCancel = () => {
  emit('cancel')
}

4.4 模板规范

vue
<template>
  <!-- 使用语义化标签 -->
  <div class="user-profile">
    <!-- 使用v-if和v-else -->
    <div v-if="loading" class="loading">
      加载中...
    </div>
    <div v-else-if="userInfo" class="user-info">
      <h1 class="user-info__name">{{ userInfo.name }}</h1>
      <p class="user-info__email">{{ userInfo.email }}</p>
    </div>
    <div v-else class="empty">
      暂无数据
    </div>

    <!-- 使用v-for -->
    <ul class="user-list">
      <li
        v-for="user in userList"
        :key="user.id"
        class="user-list__item"
        @click="handleUserClick(user)"
      >
        {{ user.name }}
      </li>
    </ul>

    <!-- 使用v-model -->
    <el-input
      v-model="searchKeyword"
      placeholder="请输入搜索关键词"
      @input="handleSearch"
    />

    <!-- 使用v-show -->
    <div v-show="isShow" class="modal">
      模态框内容
    </div>
  </div>
</template>

4.5 样式规范

vue
<style lang="scss" scoped>
// 使用BEM命名规范
.user-profile {
  padding: 20px;
  
  &__name {
    font-size: 24px;
    color: #333;
  }
  
  &__email {
    font-size: 14px;
    color: #666;
    margin-top: 10px;
  }
  
  &--active {
    background-color: #f0f0f0;
  }
}

// 使用嵌套
.user-list {
  list-style: none;
  padding: 0;
  
  &__item {
    padding: 10px;
    border-bottom: 1px solid #eee;
    
    &:hover {
      background-color: #f5f5f5;
    }
  }
}

// 使用变量
$primary-color: #409eff;
$font-size-base: 14px;

.button {
  background-color: $primary-color;
  font-size: $font-size-base;
}
</style>

5. TypeScript规范

5.1 类型定义

typescript
// 基本类型
const name: string = '张三'
const age: number = 25
const isActive: boolean = true
const data: null = null
const value: undefined = undefined

// 数组类型
const numbers: number[] = [1, 2, 3]
const strings: Array<string> = ['a', 'b', 'c']

// 对象类型
interface UserInfo {
  id: number
  name: string
  email?: string
  roles: string[]
}

const user: UserInfo = {
  id: 1,
  name: '张三',
  roles: ['admin']
}

// 函数类型
type FunctionType = (a: number, b: number) => number

const add: FunctionType = (a, b) => {
  return a + b
}

// 联合类型
type Status = 'active' | 'inactive' | 'pending'

const status: Status = 'active'

// 交叉类型
type UserWithTimestamp = UserInfo & {
  createdAt: Date
  updatedAt: Date
}

// 泛型
interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

const response: ApiResponse<UserInfo> = {
  code: 200,
  message: 'success',
  data: {
    id: 1,
    name: '张三',
    roles: ['admin']
  }
}

5.2 函数规范

typescript
// 函数参数和返回值类型
function calculateAge(birthDate: Date): number {
  const today = new Date()
  const birth = new Date(birthDate)
  let age = today.getFullYear() - birth.getFullYear()
  const monthDiff = today.getMonth() - birth.getMonth()
  
  if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
    age--
  }
  
  return age
}

// 可选参数
function greet(name: string, greeting?: string): string {
  return `${greeting || 'Hello'}, ${name}`
}

// 默认参数
function createUser(name: string, age: number = 18): UserInfo {
  return { id: 0, name, roles: [] }
}

// 剩余参数
function sum(...numbers: number[]): number {
  return numbers.reduce((acc, num) => acc + num, 0)
}

// 箭头函数
const multiply = (a: number, b: number): number => {
  return a * b
}

// 异步函数
async function fetchUserInfo(userId: number): Promise<UserInfo> {
  const response = await fetch(`/api/users/${userId}`)
  return response.json()
}

5.3 类规范

typescript
class UserService {
  private static instance: UserService
  private apiUrl: string

  private constructor() {
    this.apiUrl = import.meta.env.VITE_API_URL
  }

  static getInstance(): UserService {
    if (!UserService.instance) {
      UserService.instance = new UserService()
    }
    return UserService.instance
  }

  async getUserInfo(userId: number): Promise<UserInfo> {
    const response = await fetch(`${this.apiUrl}/users/${userId}`)
    return response.json()
  }

  async createUser(userData: Partial<UserInfo>): Promise<UserInfo> {
    const response = await fetch(`${this.apiUrl}/users`, {
      method: 'POST',
      body: JSON.stringify(userData)
    })
    return response.json()
  }
}

// 使用
const userService = UserService.getInstance()

5.4 接口规范

typescript
// 用户信息接口
interface UserInfo {
  id: number
  name: string
  email?: string
  phone?: string
  avatar?: string
  status: UserStatus
  roles: UserRole[]
  createdAt: Date
  updatedAt: Date
}

// 用户状态枚举
enum UserStatus {
  Active = 'active',
  Inactive = 'inactive',
  Pending = 'pending'
}

// 用户角色枚举
enum UserRole {
  Admin = 'admin',
  User = 'user',
  Guest = 'guest'
}

// API响应接口
interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

// 分页参数接口
interface PageParams {
  pageNo: number
  pageSize: number
}

// 分页响应接口
interface PageResponse<T> {
  list: T[]
  total: number
}

6. API调用规范

6.1 API文件组织

src/api/
├── user.ts          # 用户相关API
├── auth.ts          # 认证相关API
├── product.ts       # 产品相关API
└── index.ts         # API统一导出

6.2 API定义规范

typescript
// src/api/user.ts
import request from '@/utils/request'
import type { UserInfo, PageParams, PageResponse } from '@/types/user'

/**
 * 获取用户信息
 * @param userId 用户ID
 * @returns 用户信息
 */
export const getUserInfo = (userId: number) => {
  return request.get<UserInfo>({
    url: `/user/${userId}`
  })
}

/**
 * 获取用户列表
 * @param params 分页参数
 * @returns 用户列表
 */
export const getUserList = (params: PageParams) => {
  return request.get<PageResponse<UserInfo>>({
    url: '/user/list',
    params
  })
}

/**
 * 创建用户
 * @param data 用户数据
 * @returns 用户信息
 */
export const createUser = (data: Partial<UserInfo>) => {
  return request.post<UserInfo>({
    url: '/user/create',
    data
  })
}

/**
 * 更新用户
 * @param userId 用户ID
 * @param data 用户数据
 * @returns 用户信息
 */
export const updateUser = (userId: number, data: Partial<UserInfo>) => {
  return request.put<UserInfo>({
    url: `/user/${userId}`,
    data
  })
}

/**
 * 删除用户
 * @param userId 用户ID
 * @returns 操作结果
 */
export const deleteUser = (userId: number) => {
  return request.delete({
    url: `/user/${userId}`
  })
}

6.3 错误处理

typescript
// 使用try-catch处理错误
const fetchUserInfo = async (userId: number) => {
  try {
    const userInfo = await getUserInfo(userId)
    return userInfo
  } catch (error) {
    console.error('获取用户信息失败:', error)
    throw error
  }
}

// 使用async/await处理错误
const handleUserSubmit = async () => {
  try {
    loading.value = true
    const result = await createUser(formData.value)
    ElMessage.success('创建用户成功')
    return result
  } catch (error) {
    ElMessage.error('创建用户失败')
    throw error
  } finally {
    loading.value = false
  }
}

7. Git工作流规范

7.1 分支管理

分支类型

分支类型命名规范说明
主分支main/master生产环境分支
开发分支develop开发环境分支
功能分支feature/xxx新功能开发
修复分支fix/xxxBug修复
热修复分支hotfix/xxx紧急修复
发布分支release/xxx版本发布

分支操作

bash
# 创建功能分支
git checkout -b feature/user-profile

# 创建修复分支
git checkout -b fix/login-error

# 创建热修复分支
git checkout -b hotfix/security-patch

# 合并功能分支到主分支
git checkout main
git pull origin main
git merge feature/user-profile
git push origin main

7.2 提交信息规范

提交信息格式

<type>(<scope>): <subject>

<body>

<footer>

提交类型

类型说明示例
feat新功能feat(user): 添加用户头像上传功能
fix修复bugfix(login): 修复登录页面样式问题
docs文档更新docs(readme): 更新项目说明文档
style代码格式修改style(component): 统一组件代码格式
refactor重构代码refactor(api): 重构用户API接口
test测试用例修改test(user): 添加用户单元测试
build构建系统或包依赖修改build(deps): 升级依赖包版本
ciCI/CD配置修改ci(github): 添加GitHub Actions配置
chore其他杂项修改chore(config): 更新配置文件
revert回滚到上一版本revert: 回滚用户功能
perf性能优化perf(list): 优化列表渲染性能

提交示例

bash
# 简单提交
git commit -m "feat(user): 添加用户头像上传功能"

# 详细提交
git commit -m "fix(login): 修复登录页面样式问题

- 修复登录按钮样式错位问题
- 优化输入框焦点样式
- 添加加载状态提示

Closes #123"

7.3 代码审查

Pull Request规范

  1. 标题:清晰描述PR的目的
  2. 描述:详细说明PR的内容和变更
  3. 关联Issue:关联相关的Issue
  4. 截图:如有UI变更,提供截图
  5. 测试:说明测试情况

代码审查要点

  • 代码风格是否符合规范
  • 是否有潜在的安全问题
  • 是否有性能问题
  • 是否有逻辑错误
  • 是否有重复代码
  • 是否有足够的注释

8. 项目结构规范

8.1 目录结构

src/
├── api/              # API接口
├── assets/           # 静态资源
├── components/       # 公共组件
├── composables/      # 组合式函数
├── config/           # 配置文件
├── directives/       # 自定义指令
├── hooks/            # 自定义钩子
├── layout/           # 布局组件
├── locales/          # 国际化文件
├── router/           # 路由配置
├── store/            # 状态管理
├── styles/           # 全局样式
├── types/            # 类型定义
├── utils/            # 工具函数
├── views/            # 页面组件
├── App.vue           # 根组件
└── main.ts           # 入口文件

8.2 组件组织

components/
├── XButton/          # 按钮组件
│   ├── src/
│   │   ├── XButton.vue
│   │   └── types.ts
│   └── index.ts
├── XTable/           # 表格组件
│   ├── src/
│   │   ├── XTable.vue
│   │   └── types.ts
│   └── index.ts
└── index.ts          # 组件统一导出

8.3 页面组织

views/
├── user/             # 用户模块
│   ├── index.vue     # 用户列表
│   ├── detail.vue   # 用户详情
│   └── components/  # 用户模块组件
│       ├── UserForm.vue
│       └── UserTable.vue
└── product/          # 产品模块
    ├── index.vue
    ├── detail.vue
    └── components/
        ├── ProductForm.vue
        └── ProductTable.vue

9. 性能优化规范

9.1 组件优化

vue
<script setup lang="ts">
// 使用computed缓存计算结果
const filteredList = computed(() => {
  return list.value.filter(item => item.status === 'active')
})

// 使用watchEffect自动追踪依赖
watchEffect(() => {
  console.log('count changed:', count.value)
})

// 使用v-once只渲染一次
<div v-once>{{ staticContent }}</div>

// 使用v-memo缓存DOM
<div v-memo="[count.value]">{{ count.value }}</div>
</script>

9.2 列表优化

vue
<template>
  <!-- 使用key提高列表渲染性能 -->
  <ul>
    <li v-for="item in list" :key="item.id">
      {{ item.name }}
    </li>
  </ul>

  <!-- 使用虚拟滚动处理长列表 -->
  <VirtualList :items="longList" :item-height="50" />
</template>

9.3 图片优化

vue
<template>
  <!-- 使用懒加载 -->
  <img v-lazy="imageUrl" alt="description" />

  <!-- 使用响应式图片 -->
  <picture>
    <source media="(max-width: 768px)" :srcset="imageUrlSmall" />
    <source media="(max-width: 1024px)" :srcset="imageUrlMedium" />
    <img :src="imageUrlLarge" alt="description" />
  </picture>
</template>

9.4 代码分割

typescript
// 路由懒加载
const routes = [
  {
    path: '/user',
    component: () => import('@/views/user/index.vue')
  }
]

// 组件懒加载
const HeavyComponent = defineAsyncComponent(() =>
  import('@/components/HeavyComponent.vue')
)

10. 安全规范

10.1 XSS防护

typescript
// 避免使用v-html
<div v-html="userContent"></div> // 不推荐

// 使用文本插值
<div>{{ userContent }}</div> // 推荐

// 使用DOMPurify清理HTML
import DOMPurify from 'dompurify'
const cleanHtml = DOMPurify.sanitize(userContent)

10.2 CSRF防护

typescript
// 在请求头中添加CSRF令牌
axios.interceptors.request.use(config => {
  const csrfToken = getCsrfToken()
  if (csrfToken) {
    config.headers['X-CSRF-TOKEN'] = csrfToken
  }
  return config
})

10.3 敏感信息处理

typescript
// 不要在前端存储敏感信息
// 不推荐
localStorage.setItem('password', password)

// 推荐
// 使用短期令牌
const token = await getAuthToken()
sessionStorage.setItem('token', token)

// 使用环境变量
const apiUrl = import.meta.env.VITE_API_URL

11. 测试规范

11.1 单元测试

typescript
// 使用Vitest进行单元测试
import { describe, it, expect } from 'vitest'
import { calculateAge } from '@/utils/date'

describe('calculateAge', () => {
  it('should calculate age correctly', () => {
    const birthDate = new Date('1990-01-01')
    const age = calculateAge(birthDate)
    expect(age).toBeGreaterThan(30)
  })

  it('should handle edge cases', () => {
    const today = new Date()
    const age = calculateAge(today)
    expect(age).toBe(0)
  })
})

11.2 组件测试

typescript
// 使用Vue Test Utils进行组件测试
import { mount } from '@vue/test-utils'
import UserProfile from '@/components/UserProfile.vue'

describe('UserProfile', () => {
  it('renders user name', () => {
    const wrapper = mount(UserProfile, {
      props: {
        userName: '张三'
      }
    })
    expect(wrapper.text()).toContain('张三')
  })

  it('emits submit event', async () => {
    const wrapper = mount(UserProfile)
    await wrapper.find('button').trigger('click')
    expect(wrapper.emitted('submit')).toBeTruthy()
  })
})

12. 文档规范

12.1 代码文档

typescript
/**
 * 用户服务类
 * 
 * @description 提供用户相关的业务逻辑
 * @author 张三
 * @date 2024-01-01
 * @version 1.0.0
 * 
 * @example
 * ```typescript
 * const userService = UserService.getInstance()
 * const userInfo = await userService.getUserInfo(1)
 * ```
 */
class UserService {
  // ...
}

12.2 README文档

markdown
# 项目名称

## 简介
简要描述项目的功能和用途

## 技术栈
列出项目使用的主要技术

## 安装
```bash
pnpm install

开发

bash
pnpm dev

构建

bash
pnpm build

部署

说明部署流程


## 13. 最佳实践

### 13.1 代码复用

```typescript
// 提取公共逻辑为组合式函数
// composables/useUser.ts
export function useUser() {
  const userInfo = ref<UserInfo | null>(null)
  const loading = ref(false)

  const fetchUserInfo = async (userId: number) => {
    loading.value = true
    try {
      userInfo.value = await getUserInfo(userId)
    } finally {
      loading.value = false
    }
  }

  return {
    userInfo,
    loading,
    fetchUserInfo
  }
}

// 在组件中使用
<script setup lang="ts">
import { useUser } from '@/composables/useUser'

const { userInfo, loading, fetchUserInfo } = useUser()
</script>

13.2 错误处理

typescript
// 统一错误处理
class ApiError extends Error {
  constructor(
    public code: number,
    message: string,
    public data?: any
  ) {
    super(message)
  }
}

// 错误拦截器
axios.interceptors.response.use(
  response => response,
  error => {
    if (error.response) {
      throw new ApiError(
        error.response.status,
        error.response.data.message,
        error.response.data
      )
    }
    throw error
  }
)

13.3 日志记录

typescript
// 统一日志记录
const logger = {
  info: (message: string, data?: any) => {
    console.log(`[INFO] ${message}`, data)
  },
  warn: (message: string, data?: any) => {
    console.warn(`[WARN] ${message}`, data)
  },
  error: (message: string, error?: any) => {
    console.error(`[ERROR] ${message}`, error)
  }
}

// 使用
logger.info('用户登录成功', { userId: 123 })
logger.error('用户登录失败', error)

14. 常见问题

14.1 如何处理循环依赖?

typescript
// 使用依赖注入或事件总线解决循环依赖
// 方案1:使用Pinia store
// 方案2:使用事件总线
// 方案3:重构代码结构

14.2 如何优化首屏加载?

typescript
// 1. 路由懒加载
const routes = [
  {
    path: '/user',
    component: () => import('@/views/user/index.vue')
  }
]

// 2. 组件懒加载
const HeavyComponent = defineAsyncComponent(() =>
  import('@/components/HeavyComponent.vue')
)

// 3. 图片懒加载
<img v-lazy="imageUrl" />

14.3 如何处理大文件上传?

typescript
// 使用分片上传
const uploadFile = async (file: File) => {
  const chunkSize = 1024 * 1024 * 2 // 2MB
  const chunks = Math.ceil(file.size / chunkSize)
  
  for (let i = 0; i < chunks; i++) {
    const start = i * chunkSize
    const end = Math.min(start + chunkSize, file.size)
    const chunk = file.slice(start, end)
    
    await uploadChunk(chunk, i, chunks)
  }
}

注意:本文档持续更新中,如有问题请及时反馈。