Vue 3项目架构设计:从2200行单文件到24个组件
作者:互联网
2026-04-19
️ Vue 3项目架构设计:从2200行单文件到24个组件
前言
在项目初期,为了快速实现功能,我把大部分代码都写在了App.vue中,导致单文件达到了2200多行。随着功能增多,代码越来越难以维护。于是我开始进行架构重构,将代码拆分成24个独立组件,最终实现了更好的代码组织和可维护性。
重构前后对比
代码结构对比
重构前:
App.vue (2200+ 行)
├── 布局代码
├── 业务逻辑
├── 组件代码
└── 工具函数
重构后:
src/
├── components/
│ ├── layout/ (5个组件)
│ ├── features/ (4个组件)
│ ├── gamification/ (4个组件)
│ └── article/ (6个组件)
├── composables/ (5个组合函数)
├── utils/ (3个工具模块)
└── views/ (5个页面组件)
数据对比
| 指标 | 重构前 | 重构后 | 改善 |
|---|---|---|---|
| 单文件最大行数 | 2200+ | 400 | ⬇️ 82% |
| 组件数量 | 1 | 24 | ⬆️ 24倍 |
| 代码复用率 | 0% | 40%+ | ⬆️ 40% |
| 可维护性 | 低 | 高 | ⬆⬆⬆ |
架构设计原则
1. 单一职责原则
每个组件只负责一个功能模块。
2. 开闭原则
通过props和emits扩展组件功能,不修改组件内部代码。
3. 依赖倒置原则
组件依赖于抽象的接口(props/emits),而非具体实现。
// composables/usePagination.ts
export function usePagination(options: PaginationOptions) {
const currentPage = ref(options.page || 1)
const pageSize = ref(options.pageSize || 10)
const nextPage = () => {
currentPage.value++
}
const prevPage = () => {
currentPage.value--
}
return {
currentPage,
pageSize,
nextPage,
prevPage
}
}
组件分类体系
1. 布局组件(5个)
AppBackground
TheHeader
TheFooter
BackToTop
ReadingProgressBar
2. 功能组件(4个)
Notification
{{ notif.message }}
SearchPanel
SettingsPanel
启用背景音乐
KeyboardHints
{{ hint.key }}
{{ hint.action }}
3. 游戏化组件(4个)
EnergyDisplay
{{ energy }}/100
SignDialog
{{ day }}
{{ signedToday ? '已签到' : '签到' }}
MusicPlayer
{{ currentTrack.name }}
{{ currentTrack.artist }}
4. 文章组件(6个)
ArticleCard
ArticleMeta
Composables设计
useArticle
// composables/useArticle.ts
export function useArticle() {
const articles = ref<Article[]>([])
const loading = ref(false)
const error = ref<Error | null>(null)
const fetchArticles = async () => {
loading.value = true
try {
articles.value = await getArticles()
} catch (e) {
error.value = e as Error
} finally {
loading.value = false
}
}
const getArticleById = (id: number) => {
return articles.value.find(a => a.id === id)
}
return {
articles,
loading,
error,
fetchArticles,
getArticleById
}
}
useTheme
// composables/useTheme.ts
export function useTheme() {
const isDark = ref(false)
const toggleTheme = () => {
isDark.value = !isDark.value
document.documentElement.classList.toggle('dark')
}
return {
isDark,
toggleTheme
}
}
useLocalStorage
// composables/useLocalStorage.ts
export function useLocalStorage(key: string, defaultValue: T) {
const stored = ref(defaultValue)
// 初始化时读取
const init = () => {
const item = localStorage.getItem(key)
if (item) {
try {
stored.value = JSON.parse(item)
} catch (e) {
console.error('Failed to parse localStorage', e)
}
}
}
// 变化并保存
watch(stored, (value) => {
localStorage.setItem(key, JSON.stringify(value))
}, { deep: true })
init()
return stored
}
组件通信方式
1. Props Down
2. Emits Up
3. Provide/Inject
// 祖先组件
provide('theme', isDark)
// 后代组件
const theme = inject('theme')
4. Event Bus
// utils/eventBus.ts
import mitt from 'mitt'
export const eventBus = mitt<{
notification: NotificationEvent
refresh: void
}>()
// 发送事件
eventBus.emit('notification', { type: 'success', message: '操作成功' })
// 事件
eventBus.on('notification', (event) => {
// 处理通知
})
性能优化
1. 组件懒加载
const HeavyComponent = defineAsyncComponent({
loader: () => import('./HeavyComponent.vue'),
loadingComponent: LoadingSpinner,
errorComponent: ErrorComponent,
delay: 200,
timeout: 3000
})
2. 虚拟滚动
3. 计算属性缓存
const hotArticles = computed(() => {
return articles.value
.filter(a => a.views > 1000)
.sort((a, b) => b.views - a.views)
})
最佳实践
1. 组件命名
- 使用PascalCase
- 组件名与文件名保持一致
- 使用语义化的名称
2. Props定义
- 明确定义类型
- 提供合理的默认值
- 使用TypeScript类型检查
3. 样式管理
- 使用scoped CSS
- 避免样式污染
- 使用CSS变量
总结
通过合理的架构设计和组件拆分,我们实现了:
- 更好的代码组织 - 职责清晰,易于理解
- 更高的可维护性 - 修改某个功能只需修改对应组件
- 更强的可复用性 - 组件可在多个页面中复用
- 更好的可测试性 - 独立组件更容易编写单元测试
- 更高的开发效率 - 团队成员可同时开发不同组件
标签:#Vue3 #组件化 #架构设计 #前端 #代码重构
点攒️ + 收藏⭐️ + 评论,你的支持是我创作的动力!
相关推荐
专题
+ 收藏
+ 收藏
+ 收藏
+ 收藏
+ 收藏
+ 收藏
最新数据
相关文章
Vue 3项目架构设计:从2200行单文件到24个组件
04/19
你的 Vue 3 defineAsyncComponent(),VuReact 会编译成什么样的 React?
04/19
Element Plus 组件库实战技巧与踩坑记录
04/19
你的 Vue 路由,VuReact 会编译成什么样的 React 路由?
04/19
Vue 项目高德地图性能优化实战:从卡死到丝滑的完整过程
04/19
Vue v-if 转 React:VuReact 怎么处理?
04/19
你的 Vue v-for,VuReact 会编译成什么样的 React 代码?
04/19
Vue v-html 与 v-text 转 React:VuReact 怎么处理?
04/19
Vue路由跳转全场景实战(Vue2+Vue3适配)| 新手必看
04/19
Vue 封装 Echarts 组件
04/19
AI精选
