一、为什么需要好的目录结构

刚开始做Vue项目时,很多人会把所有文件都堆在src目录下。随着项目越来越大,你会发现找文件就像大海捞针,改一个功能要翻遍整个项目。好的目录结构就像整理房间,东西放对位置,找起来就方便多了。

想象一下,你接手一个别人开发的项目:

  • 组件散落在各处
  • API调用分散在多个文件
  • 工具函数重复定义
  • 样式互相覆盖

这种情况我们叫"面条式代码",维护起来特别痛苦。好的目录结构能帮我们避免这些问题。

二、基础目录结构设计

我们先来看一个基础但实用的目录结构(技术栈:Vue 3 + TypeScript):

src/
├── assets/          # 静态资源
│   ├── images/      # 图片
│   └── styles/      # 全局样式
├── components/      # 公共组件
│   ├── common/      # 全平台通用组件
│   └── business/    # 业务相关组件
├── composables/     # 组合式函数
├── router/          # 路由配置
├── stores/          # 状态管理
├── utils/           # 工具函数
│   ├── http/        # 网络请求相关
│   └── helpers/     # 辅助函数
├── views/           # 页面组件
├── App.vue          # 根组件
└── main.ts          # 入口文件

这个结构适合中小型项目。每个目录都有明确职责:

  • assets放不会变的东西
  • components放可复用的UI部件
  • views是路由对应的页面
  • stores集中管理状态

三、进阶目录设计方案

当项目变得复杂时,我们需要更细致的划分。这里介绍两种常见方案:

方案一:按功能模块划分

src/
├── modules/
│   ├── user/        # 用户模块
│   │   ├── components/ # 模块专用组件
│   │   ├── stores/   # 模块状态
│   │   └── utils/    # 模块工具
│   └── product/     # 商品模块
├── core/            # 核心基础设施
│   ├── http/        # 网络请求
│   └── constants/   # 常量定义
└── shared/          # 共享资源

这种结构特别适合多人协作的大型项目,每个团队负责自己的模块,不会互相干扰。

方案二:按技术职责划分

src/
├── presentation/    # 展示层
│   ├── components/
│   └── pages/
├── application/     # 应用层
│   ├── services/    # 业务服务
│   └── stores/
├── domain/          # 领域层
│   ├── entities/    # 业务实体
│   └── repositories # 数据访问
└── infrastructure/  # 基础设施
    ├── http/
    └── config/

这种结构借鉴了DDD(领域驱动设计)思想,适合业务逻辑复杂的系统。

四、关键目录详解

让我们深入看看几个重要目录的最佳实践:

1. components目录设计

好的组件分类能大幅提高开发效率。建议这样划分:

components/
├── ui/              # 基础UI组件
│   ├── buttons/
│   ├── inputs/
│   └── dialogs/
├── layout/          # 布局组件
│   ├── Header.vue
│   └── Sidebar.vue
└── business/        # 业务组件
    ├── ProductCard.vue
    └── UserAvatar.vue

每个组件应该自包含:

<!-- components/ui/buttons/PrimaryButton.vue -->
<template>
  <button 
    class="primary-btn"
    :disabled="disabled"
    @click="$emit('click')"
  >
    <slot></slot>
  </button>
</template>

<script setup lang="ts">
defineProps({
  disabled: {
    type: Boolean,
    default: false
  }
})

defineEmits(['click'])
</script>

<style scoped>
.primary-btn {
  /* 基础样式 */
}
</style>

2. API请求管理

推荐集中管理API请求:

src/
└── api/
    ├── modules/     # 按模块划分API
    │   ├── user.ts
    │   └── product.ts
    ├── http.ts      # 请求实例配置
    └── types.ts     # 公共类型定义

示例API模块:

// api/modules/user.ts
import http from '../http'
import type { UserProfile, LoginParams } from '../types'

export const userApi = {
  // 获取用户资料
  getProfile: (userId: string) => {
    return http.get<UserProfile>(`/users/${userId}`)
  },
  
  // 用户登录
  login: (params: LoginParams) => {
    return http.post('/auth/login', params)
  }
}

五、实际场景分析

场景一:电商后台系统

对于电商系统,我们可能需要:

src/
├── modules/
│   ├── product/     # 商品管理
│   ├── order/       # 订单管理
│   ├── member/       # 会员管理
│   └── marketing/    # 营销活动
├── shared/
│   ├── components/  # 通用业务组件
│   │   ├── DataTable.vue  # 数据表格
│   │   └── SearchBar.vue  # 搜索栏
│   └── hooks/       # 通用逻辑
└── core/
    ├── permission.ts # 权限控制
    └── router.ts    # 路由守卫

场景二:SaaS平台

SaaS平台通常需要:

src/
├── apps/            # 子应用
│   ├── crm/         # CRM应用
│   └── erp/         # ERP应用
├── framework/       # 平台框架
│   ├── layout/      # 布局系统
│   └── plugin/      # 插件系统
└── services/        # 微服务
    ├── auth/        # 认证服务
    └── notification # 通知服务

六、注意事项

  1. 命名一致性:整个项目保持相同的命名风格,比如全部用短横线命名法(kebab-case)

  2. 避免过度设计:小型项目不需要复杂的分层,简单直接更好

  3. 静态资源管理

    • 小图标建议用雪碧图或iconfont
    • 大图片考虑CDN托管
  4. 环境变量处理

    # .env.development
    VITE_API_BASE=/api
    VITE_DEBUG=true
    
  5. 类型安全:TypeScript类型定义要集中管理:

    // types/user.d.ts
    interface UserProfile {
      id: string
      name: string
      avatar?: string
    }
    

七、技术选型考量

Vuex vs Pinia

对于新项目,建议使用Pinia:

// stores/user.ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    token: '',
    profile: null as UserProfile | null
  }),
  actions: {
    async login(credentials: LoginParams) {
      const res = await userApi.login(credentials)
      this.token = res.token
    }
  }
})

样式方案选择

  • 简单项目:Scoped CSS
  • 复杂项目:CSS Modules或TailwindCSS

八、项目演进策略

随着项目增长,目录结构也需要调整:

  1. 第一阶段(0-10个页面):基础结构
  2. 第二阶段(10-50个页面):按模块划分
  3. 第三阶段(50+页面):微前端或monorepo

九、总结建议

好的目录结构应该:

  1. 让新人能快速找到代码
  2. 避免重复代码
  3. 方便功能扩展
  4. 支持团队协作

记住:没有完美的方案,只有适合的方案。根据团队习惯和项目特点选择最合适的结构,并在开发过程中不断优化。