人人都会AI编程

业务域拆分、模块分层

更新时间:2026-07-10

当 Vue 项目从一个“个人练手”或“小型活动页”逐渐发展成 几十个页面、多个业务团队协作、功能持续迭代 的大型应用时,单纯靠“按功能划分目录”已经不够了。这时候需要引入业务域拆分模块分层的架构思想,目的是让代码组织方式匹配业务复杂度,降低耦合,提升可维护性。


业务域拆分:按“业务领域”划地盘

传统的目录结构通常是“按技术角色”分层:

src/
├── components/    # 所有组件混在一起
├── views/         # 所有页面
├── store/         # 所有状态
├── api/           # 所有接口
└── utils/         # 所有工具函数

当业务模块超过 5 个时,一个修改就可能散落在 views/Order.vuestore/order.jsapi/order.jscomponents/OrderDetail.vue 等四五个目录中,跳转查找低效,且多人同时修改时极易产生冲突。

业务域拆分的思路是:按业务领域(如用户、订单、商品)将相关代码聚合在一起,每个域内自行管理它的组件、状态、接口、工具等。

src/
├── domains/
│   ├── user/          # 用户域
│   │   ├── components/
│   │   │   └── UserProfile.vue
│   │   ├── store/
│   │   │   └── userStore.ts
│   │   ├── api/
│   │   │   └── userApi.ts
│   │   └── utils/
│   │       └── formatUser.ts
│   ├── order/         # 订单域
│   │   ├── components/
│   │   │   ├── OrderList.vue
│   │   │   └── OrderDetail.vue
│   │   ├── store/
│   │   │   └── orderStore.ts
│   │   ├── api/
│   │   │   └── orderApi.ts
│   │   └── views/
│   │       └── OrderPage.vue
│   └── product/       # 商品域
│       └── ...
├── shared/            # 跨域共享的通用模块
│   ├── components/    # 全局通用组件(按钮、弹窗等)
│   ├── utils/         # 通用工具函数(日期格式化、防抖等)
│   └── api/           # 基础请求封装
└── app/               # 应用级配置(路由、全局样式、入口)
    ├── router/
    └── App.vue

拆分原则

  • 高内聚:一个业务域内的代码尽量自给自足,域内修改不影响其他域。
  • 低耦合:域与域之间通过明确的接口(如 Pinia Store 的 public getters/actions、共享组件 Props)通信,避免直接引用域内部实现细节。
  • 按团队边界拆分:如果多个业务由不同团队负责,业务域可以进一步拆成独立的 Git 子仓库或 Monorepo 包,实现物理隔离。

实际收益

  • 新成员接手“订单模块”时,只需要关注 domains/order/ 下的代码,不会被其他几十个文件干扰。
  • 订单功能的迭代、重构甚至下线,影响范围被严格限定在域内,降低“牵一发而动全身”的风险。
  • 如果项目足够大,甚至可以单独为某个域做性能分析、测试覆盖,管理颗粒度更细。

模块分层:在业务域内部分层

即使做了业务域拆分,某个域内部的一坨代码仍然可能难以维护。比如 OrderDetail.vue 里同时塞了 API 请求、数据转换、业务判断、DOM 事件处理……这种“面条代码”需要进一步按职责分层

在 Vue 项目中,一个比较实用的分层模型是 视图层 → 逻辑层 → 数据层

1. 视图层(View/Component)
负责渲染 UI 和接收用户交互,保持“纯净”:

  • 只关心 DOM 结构、样式、事件绑定。
  • 不直接写业务判断(如 if(user.role === 'admin') ),而是通过逻辑层暴露的状态和事件。
  • 从逻辑层获取数据,把用户操作传递给逻辑层。
<!-- views/OrderPage.vue - 视图层 -->
<template>
  <div>
    <OrderList 
      :orders="orderList" 
      @select="handleSelect" 
    />
    <OrderDetail 
      v-if="selectedOrder" 
      :order="selectedOrder" 
      @cancel="cancelOrder"
    />
  </div>
</template>

<script setup lang="ts">
import { useOrderList } from '../composables/useOrderList'
import { useOrderAction } from '../composables/useOrderAction'

const { orderList, selectedOrder, loadOrders } = useOrderList()
const { cancelOrder } = useOrderAction()

const handleSelect = (order: Order) => {
  selectedOrder.value = order
}

onMounted(() => loadOrders())
</script>

2. 逻辑层(Composable / Hooks)
这一层是 Vue 应用的核心,负责全部业务逻辑。全部用组合式 API 的自定义 hooks 实现:

  • 数据获取、状态管理。
  • 表单校验规则、状态机流转。
  • 与 Pinia Store 或 API 层交互。
  • 对外暴露响应式状态和方法,供视图层消费。
// composables/useOrderList.ts
import { ref } from 'vue'
import { orderApi } from '../api/orderApi'

export function useOrderList() {
  const orderList = ref<Order[]>([])
  const selectedOrder = ref<Order | null>(null)

  async function loadOrders(params?: any) {
    orderList.value = await orderApi.fetchList(params)
  }

  // 可暴露更多计算属性、watch 等
  return { orderList, selectedOrder, loadOrders }
}

3. 数据层(API + Store)
负责与外部数据源(后端接口、localStorage、WebSocket)打交道:

  • 纯数据访问函数,不包含任何视图相关逻辑。
  • Pinia Store 可以看作数据层的“缓存 + 共享状态”层,它本身也可以被逻辑层调用。
// api/orderApi.ts
import request from '@/shared/api/request'

export const orderApi = {
  fetchList: (params: any) => request.get('/api/orders', { params }),
  cancel: (id: string) => request.post(`/api/orders/${id}/cancel`)
}

这样分层后,一个典型的数据流是:

视图触发事件 → 逻辑层方法执行 → 调用数据层接口 → 
逻辑层更新响应式状态 → 视图自动更新

分层的实际好处

  • 可测试性强:逻辑层不依赖 DOM,可以用 Vitest 独立测试组合式函数。
  • 可复用:同一个 useOrderList 可能在订单列表页、首页订单卡片、后台管理页同时复用。
  • 可维护:需要换接口时只改数据层,需要换 UI 框架时只改视图层,核心业务逻辑不动。
  • 新人友好:逻辑清晰,看一层关注一层,不用在 800 行的组件文件中反复横跳。

总结:一张图看清架构

┌─────────────────────────────────────────┐
│              业务域 A / B / C            │
│                                         │
│  视图层 (Vue 组件)                       │
│    ↓↑ 事件/状态                          │
│  逻辑层 (Composables / Hooks)            │
│    ↓↑ 数据/动作                          │
│  数据层 (Pinia Store / API / 工具)       │
│                                         │
├─────────────────────────────────────────┤
│          共享模块 (shared)               │
│      通用组件 / 工具 / 基础请求          │
└─────────────────────────────────────────┘

对于大多数中型项目(10-50 个页面),可以先按业务域划分目录,每个域内部再简单分层。对于超过 100 个页面、多团队并行的大项目,引入业务域拆分 + 模块分层能显著降低维护成本,让前端架构像后端微服务一样,做到“高内聚、低耦合、职责清晰”。