外观
目录分层约定
是什么
「目录分层」回答的是:新文件放进 src 下的哪一格。放错格子的代价不是难看,是依赖方向会乱——今天 components 里偷偷调了个接口,明天所有组件都这么干,想换请求库就要翻遍全项目。
只需要记住一条核心纪律,其余都是它的推论:
核心纪律
依赖只能向下,UI 组件禁止直接调接口。
五个格子,各收什么
| 目录 | 收什么 | 不收什么 |
|---|---|---|
views/(或 pages/) | 路由对应的一整个页面 | 可复用的小组件(会被两个页面用的) |
components/ | 可复用的 UI 组件 | 业务请求、全局状态的定义 |
composables/ | 可复用的状态逻辑(useXxx) | 模板和样式 |
stores/ | 全局状态(Pinia store) | 只在一个组件里用的状态 |
api/ | 接口封装:一个端点一个函数 | 组件名、样式类、任何和 UI 有关的东西 |
依赖方向
views → components → composables → stores → api
\ ↑
└────────────── 任何上层都可以用 api ──────────────────┘- 箭头右边永远不知道左边存在:
api/user.ts里 import 一个.vue文件,是分层已崩的明确信号 - 「UI 组件禁止直接调接口」的推论:组件要数据,就让父层(view)或 composable 取好了传进去。这样接口一换,只有
api/和views/要动,组件一个不用改
最小落地结构
text
src/
├── api/ # user.ts → getUser(), login()……只有 fetch,没有状态
├── composables/ # useAuth.ts → 组合 api + 状态,暴露给组件
├── stores/ # auth.ts → 跨页面共享的登录态
├── components/ # UserCard.vue → 只吃 props,吐 emit
└── views/ # UserList.vue → 组装以上一切,路由直达一个请求的正规路径:api/user.ts 定义函数 → composables/useUsers.ts 管加载态和缓存 → views/UserList.vue 调 composable → components/UserCard.vue 只收 props。每一层只认识下一层。
怎么选放哪
新文件犹豫时问一句:「它认识谁?」只认识数据 → api;管状态 → stores/composables;只管长相 → components;都认识 → views。
参考链接
- Vue 官方 · 组合式函数
- patterns.dev——「逻辑与 UI 分离」的模式来源