项目结构与最佳实践 #
一、项目目录结构 #
1.1 推荐目录结构 #
text
src/
├── assets/ # 静态资源
│ ├── images/ # 图片
│ ├── styles/ # 全局样式
│ └── fonts/ # 字体
├── components/ # 公共组件
│ ├── common/ # 通用组件
│ ├── layout/ # 布局组件
│ └── ui/ # UI组件
├── composables/ # 组合式函数
├── directives/ # 自定义指令
├── layouts/ # 布局模板
├── router/ # 路由配置
│ ├── index.js
│ └── routes.js
├── stores/ # 状态管理
│ ├── index.js
│ ├── user.js
│ └── product.js
├── utils/ # 工具函数
│ ├── request.js # 请求封装
│ ├── storage.js # 存储封装
│ └── helpers.js # 辅助函数
├── views/ # 页面组件
│ ├── home/
│ ├── user/
│ └── product/
├── App.vue
└── main.js
1.2 按功能模块组织 #
text
src/
├── modules/ # 功能模块
│ ├── user/
│ │ ├── components/
│ │ ├── composables/
│ │ ├── stores/
│ │ ├── views/
│ │ └── router.js
│ ├── product/
│ │ ├── components/
│ │ ├── composables/
│ │ ├── stores/
│ │ ├── views/
│ │ └── router.js
│ └── order/
├── shared/ # 共享资源
│ ├── components/
│ ├── composables/
│ ├── directives/
│ └── utils/
└── App.vue
二、组件设计原则 #
2.1 单一职责 #
vue
<!-- ❌ 不推荐:组件职责过多 -->
<template>
<div>
<header>...</header>
<nav>...</nav>
<main>...</main>
<footer>...</footer>
</div>
</template>
<!-- ✅ 推荐:职责单一 -->
<template>
<div>
<AppHeader />
<AppNav />
<AppMain />
<AppFooter />
</div>
</template>
2.2 组件分类 #
text
components/
├── common/ # 通用组件
│ ├── Button.vue
│ ├── Input.vue
│ └── Modal.vue
├── layout/ # 布局组件
│ ├── Header.vue
│ ├── Sidebar.vue
│ └── Footer.vue
├── business/ # 业务组件
│ ├── UserCard.vue
│ └── ProductList.vue
└── form/ # 表单组件
├── FormInput.vue
└── FormSelect.vue
2.3 组件命名 #
vue
<!-- 组件名使用PascalCase -->
<UserCard />
<ProductList />
<!-- 多词命名避免冲突 -->
<BaseButton />
<AppHeader />
<!-- 组件文件命名 -->
components/
├── BaseButton.vue
├── UserCard.vue
└── ProductList.vue
三、组合式函数设计 #
3.1 目录结构 #
text
composables/
├── useAuth.js # 认证相关
├── useFetch.js # 数据请求
├── useStorage.js # 本地存储
├── useDebounce.js # 防抖
└── useThrottle.js # 节流
3.2 组合式函数模板 #
javascript
// composables/useFeature.js
import { ref, onMounted, onUnmounted } from 'vue'
export function useFeature(options = {}) {
// 响应式状态
const state = ref(null)
const loading = ref(false)
const error = ref(null)
// 方法
function doSomething() {
// ...
}
// 生命周期
onMounted(() => {
// 初始化
})
onUnmounted(() => {
// 清理
})
// 返回
return {
state,
loading,
error,
doSomething
}
}
3.3 常用组合式函数 #
javascript
// composables/useFetch.js
import { ref, toValue, watchEffect } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(false)
async function fetchData() {
loading.value = true
error.value = null
try {
const response = await fetch(toValue(url))
data.value = await response.json()
} catch (e) {
error.value = e
} finally {
loading.value = false
}
}
watchEffect(() => {
fetchData()
})
return { data, error, loading, refetch: fetchData }
}
// composables/useLocalStorage.js
import { ref, watch } from 'vue'
export function useLocalStorage(key, defaultValue) {
const stored = localStorage.getItem(key)
const data = ref(stored ? JSON.parse(stored) : defaultValue)
watch(data, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue))
}, { deep: true })
return data
}
四、代码规范 #
4.1 组件结构 #
vue
<template>
<!-- 模板内容 -->
</template>
<script setup>
// 1. 导入
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import MyComponent from './MyComponent.vue'
// 2. Props和Emits
const props = defineProps({
title: String
})
const emit = defineEmits(['update', 'delete'])
// 3. 响应式状态
const count = ref(0)
const loading = ref(false)
// 4. 计算属性
const doubled = computed(() => count.value * 2)
// 5. 方法
function increment() {
count.value++
}
// 6. 生命周期
onMounted(() => {
fetchData()
})
// 7. 暴露给模板引用
defineExpose({
count,
increment
})
</script>
<style scoped>
/* 样式 */
</style>
4.2 命名规范 #
javascript
// 组件名:PascalCase
MyComponent.vue
UserCard.vue
// 组合式函数:use前缀
useAuth.js
useFetch.js
// 事件名:kebab-case
emit('update-user')
emit('delete-item')
// Props:kebab-case在模板中
<UserCard user-name="张三" />
// 变量名:camelCase
const userName = ref('')
const isLoading = ref(false)
// 常量:UPPER_SNAKE_CASE
const API_BASE_URL = '/api'
const MAX_RETRY_COUNT = 3
4.3 注释规范 #
vue
<script setup>
/**
* 用户卡片组件
* @description 显示用户信息卡片
* @author Your Name
*/
import { ref } from 'vue'
// 用户数据
const user = ref({
name: '',
email: ''
})
/**
* 获取用户数据
* @param {number} id - 用户ID
* @returns {Promise<void>}
*/
async function fetchUser(id) {
// 实现逻辑
}
</script>
五、性能优化 #
5.1 懒加载组件 #
javascript
// 路由懒加载
const routes = [
{
path: '/about',
component: () => import('./views/About.vue')
}
]
// 组件懒加载
const AsyncComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
)
5.2 使用v-memo #
vue
<template>
<!-- 跳过不必要的更新 -->
<div v-memo="[selected]">
<p>{{ item.name }}</p>
<p>{{ selected ? '已选中' : '未选中' }}</p>
</div>
</template>
5.3 虚拟列表 #
vue
<template>
<VirtualList
:items="largeList"
:item-height="50"
>
<template #default="{ item }">
<div class="item">{{ item.name }}</div>
</template>
</VirtualList>
</template>
5.4 避免不必要的响应式 #
vue
<script setup>
import { ref, shallowRef, markRaw } from 'vue'
// 大型不可变数据使用shallowRef
const largeData = shallowRef({ /* ... */ })
// 不需要响应式的对象使用markRaw
const staticConfig = markRaw({
apiUrl: '/api',
timeout: 5000
})
</script>
六、错误处理 #
6.1 全局错误处理 #
javascript
// main.js
const app = createApp(App)
app.config.errorHandler = (err, instance, info) => {
console.error('全局错误:', err)
// 上报错误
reportError(err)
}
app.config.warnHandler = (msg, instance, trace) => {
console.warn('警告:', msg)
}
6.2 组件错误边界 #
vue
<template>
<slot v-if="!error" />
<div v-else class="error">
{{ error.message }}
<button @click="resetError">重试</button>
</div>
</template>
<script setup>
import { ref, onErrorCaptured } from 'vue'
const error = ref(null)
onErrorCaptured((err) => {
error.value = err
return false // 阻止错误传播
})
function resetError() {
error.value = null
}
</script>
七、总结 #
项目结构要点 #
- 按功能模块组织代码
- 组件分类存放
- 组合式函数独立目录
- 工具函数统一管理
最佳实践 #
- 组件单一职责
- 命名规范统一
- 合理使用懒加载
- 做好错误处理
- 注释清晰完整
最后更新:2026-03-26