开发规范开发文档
1. 概述
本文档定义了梵医云前端项目的开发规范,旨在确保团队成员遵循统一的编码风格、项目结构和开发流程,提高代码质量和协作效率。
1.1 规范目标
- 统一性:确保代码风格一致,降低维护成本
- 可读性:提高代码可读性,便于团队协作
- 可维护性:提高代码可维护性,便于后续扩展
- 效率性:提高开发效率,减少重复工作
1.2 适用范围
本规范适用于梵医云前端项目的所有开发人员,包括但不限于:
- 新功能开发
- Bug修复
- 代码重构
- 文档编写
2. 开发环境规范
2.1 环境要求
| 工具 | 版本要求 | 说明 |
|---|---|---|
| Node.js | >= 16.18.0 | JavaScript运行环境 |
| pnpm | >= 8.6.0 | 包管理器(强制使用) |
| VS Code | 最新版 | 推荐的代码编辑器 |
2.2 必装VS Code插件
| 插件名 | 功能 | 用途 |
|---|---|---|
| Vue - Official | Vue与TypeScript支持 | Vue3语法高亮和智能提示 |
| unocss | unocss for vscode | UnoCSS智能提示 |
| Iconify IntelliSense | Iconify预览和搜索 | 图标预览和搜索 |
| i18n Ally | 国际化智能提示 | 国际化文本管理 |
| Stylelint | Css格式化 | CSS代码检查和格式化 |
| Prettier | 代码格式化 | 代码格式化 |
| ESLint | 脚本代码检查 | JavaScript/TypeScript代码检查 |
| DotENV | env文件高亮 | 环境变量文件高亮 |
| Path Intellisense | 路径智能提示 | 文件路径自动补全 |
| GitLens | Git增强 | 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组件 | PascalCase | UserProfile.vue |
| TypeScript文件 | camelCase | userService.ts |
| 工具函数 | camelCase | formatDate.ts |
| 常量文件 | camelCase | constants.ts |
| 类型定义 | camelCase | userTypes.ts |
| 样式文件 | camelCase | userStyle.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/xxx | Bug修复 |
| 热修复分支 | 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 main7.2 提交信息规范
提交信息格式
<type>(<scope>): <subject>
<body>
<footer>提交类型
| 类型 | 说明 | 示例 |
|---|---|---|
| feat | 新功能 | feat(user): 添加用户头像上传功能 |
| fix | 修复bug | fix(login): 修复登录页面样式问题 |
| docs | 文档更新 | docs(readme): 更新项目说明文档 |
| style | 代码格式修改 | style(component): 统一组件代码格式 |
| refactor | 重构代码 | refactor(api): 重构用户API接口 |
| test | 测试用例修改 | test(user): 添加用户单元测试 |
| build | 构建系统或包依赖修改 | build(deps): 升级依赖包版本 |
| ci | CI/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规范
- 标题:清晰描述PR的目的
- 描述:详细说明PR的内容和变更
- 关联Issue:关联相关的Issue
- 截图:如有UI变更,提供截图
- 测试:说明测试情况
代码审查要点
- 代码风格是否符合规范
- 是否有潜在的安全问题
- 是否有性能问题
- 是否有逻辑错误
- 是否有重复代码
- 是否有足够的注释
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.vue9. 性能优化规范
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_URL11. 测试规范
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)
}
}注意:本文档持续更新中,如有问题请及时反馈。
