《Vue3 项目结构详解:components、views、assets、router、stores 到底该怎么理解?》

一、写在前面

很多人学 Vue3,前期都是在一个很小的范围里练习:

  • 写一个 App.vue

  • 写几个小组件

  • 练练 ref

  • 练练 props

  • 做个 TodoList

这时候你对 Vue3 的理解,更多还是停留在:

一个组件怎么写。

但只要你开始接触稍微正式一点的项目,很快就会发现,真正的 Vue3 项目通常不是只有一两个文件,而是会出现一整套目录结构。

比如你会看到:

  • components

  • views

  • assets

  • router

  • stores

  • api

  • utils

  • composables

这时候很多新手会本能地发懵:

  • 为什么要分这么多目录?

  • 这些目录是不是都必须有?

  • 什么文件该放哪里?

  • 为什么我明明知道单个组件怎么写,一进项目还是看不懂?

其实这很正常。

因为从这里开始,你面对的问题已经不再只是"语法",而是:

一个 Vue 项目该怎么组织。

而项目结构组织能力,恰恰是从"会写练习"走向"会做项目"的关键一步。


二、为什么 Vue 项目需要目录结构?

先说一个根本问题:

项目目录不是为了显得专业,而是为了让代码在变多之后仍然可控。

你写一个很小的练习时,可能一个 App.vue 就够了。

因为功能少、文件少、逻辑简单,放一起也还能接受。

但如果项目开始变大,比如有:

  • 首页

  • 登录页

  • 详情页

  • 用户中心

  • 导航组件

  • 表单组件

  • 请求接口

  • 状态管理

  • 工具函数

这时候如果你还把所有内容都堆在一起,马上就会出问题:

  • 文件难找

  • 功能边界混乱

  • 修改容易误伤

  • 后期维护非常痛苦

所以项目结构存在的核心原因只有一个:

把不同职责的代码放到更合适的位置。

也就是说,项目结构本质上是在解决"代码分类"和"职责分层"的问题。


三、新手最容易误解的地方:目录不是越多越高级

这一点很重要。

很多新手第一次看到完整项目,会以为:

  • 目录越多越规范

  • 文件夹越细越专业

其实不是。

好的项目结构不是"复杂",而是"清楚"。

所以你一定要先建立这个认知:

项目结构的目标不是堆目录,而是让人容易找东西、容易理解、容易维护。

这意味着两件事:

1. 小项目不需要强行套大项目目录

2. 大项目也不能什么都乱堆在一个地方

也就是说,项目结构要和项目规模匹配。


四、先建立一个整体视角:一个 Vue3 项目通常由哪些层次组成?

你可以把一个比较常见的 Vue3 项目,粗略拆成下面几层:

1. 启动层

负责把项目跑起来

例如:

  • main.ts

  • App.vue

2. 页面层

负责完整页面视图

例如:

  • views

3. 组件层

负责可复用的局部模块

例如:

  • components

4. 路由层

负责页面跳转关系

例如:

  • router

5. 状态层

负责共享数据管理

例如:

  • stores

6. 资源层

负责图片、样式等静态资源

例如:

  • assets

  • public

7. 工具层

负责接口、工具函数、组合逻辑

例如:

  • api

  • utils

  • composables

这个分层一旦先有了整体感觉,后面你再看具体文件夹,就不会那么乱。


五、main.ts:项目启动入口

这个你前面其实已经接触过了。

最典型的写法通常是:

复制代码
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

它的核心职责就是:

启动整个 Vue 应用。

在真实项目里,main.ts 往往还会顺便做一些全局接入工作,比如:

  • 注册路由

  • 注册 Pinia

  • 引入全局样式

  • 挂载全局插件

例如:

复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'

const app = createApp(App)

app.use(router)
app.use(createPinia())

app.mount('#app')

所以你可以把 main.ts 理解成:

项目的总启动开关。


六、App.vue:最外层根组件

App.vue 通常是整个项目最外层的根组件。

你可以理解成:

  • main.ts 负责把应用启动起来

  • App.vue 负责决定应用最外层长什么样

在简单项目里,App.vue 可能直接写页面内容。

但在更正式的项目里,它往往会更像一个"外壳"。

例如:

复制代码
<template>
  <router-view />
</template>

也就是说:

  • 它不一定自己承担太多业务页面内容

  • 而是作为页面切换和整体承接入口

所以你可以记成:

App.vue 是项目最外层的组件容器。


七、components:可复用组件目录

这是 Vue 项目里最核心、最常见的目录之一。

它通常用来放:

可以在多个地方复用的局部组件。

比如:

  • 按钮组件

  • 用户卡片组件

  • 搜索框组件

  • 表格组件

  • 弹窗组件

  • 分页组件

  • 侧边栏组件

  • 顶部导航组件

这些组件的共同特点是:

  • 它们不是一个完整页面

  • 而是页面中的局部模块

  • 通常具备复用价值


1. components 和前面讲的"组件化开发"是什么关系?

完全一致。

你前面学到:

  • 页面可以拆成很多局部模块

  • 这些模块可以封装成组件

那么这些组件文件,通常就放在 components 目录里。

例如:

复制代码
src/
  components/
    SearchBar.vue
    UserCard.vue
    BaseButton.vue

2. components 里适合放什么?

你可以用一个非常实用的判断法:

如果它更像"页面零件",而不是"完整页面",就优先考虑放在 components

例如:

  • 搜索栏

  • 用户资料卡片

  • 商品项

  • 评论列表项

  • 通用弹窗

  • 表格头

  • 表单输入组件

这些都很典型。


八、views:页面级组件目录

这也是很多新手最容易和 components 混淆的地方。

先直接给结论:

views 通常放"页面级组件",也就是和路由对应的页面。

例如:

  • 首页 HomeView.vue

  • 登录页 LoginView.vue

  • 详情页 DetailView.vue

  • 用户中心 ProfileView.vue

这些组件的特点是:

  • 它们通常对应一个完整页面

  • 会被路由切换加载

  • 内部可能还会再使用很多 components 里的小组件


1. viewscomponents 的最核心区别

这个一定要讲透。

views

更像"整页"

components

更像"页中的零件"

你可以把关系理解成:

一个 view 页面,通常会由多个 components 组件组成。

比如一个首页 HomeView.vue 里,可能会使用:

  • Banner.vue

  • SearchBar.vue

  • ProductCard.vue

  • FooterBar.vue

所以它们不是同一层的角色。


2. 一个很直观的类比

你可以把:

  • views 看成"整栋房间"

  • components 看成"房间里的家具和功能模块"

这样就很好理解。


九、为什么小案例里经常没有 views,但正式项目里很常见?

因为小案例通常没有真正的多页面概念。

比如你练一个计数器、待办列表、学生管理小页,

可能一个 App.vue 就够了,根本不需要路由切换。

但只要项目变成:

  • 首页

  • 登录页

  • 列表页

  • 详情页

这种多页面应用,就会很自然地需要一个 views 目录来集中放页面组件。

所以:

views 往往是随着"路由页面"一起出现的。


十、assets:项目内静态资源目录

assets 通常用来放:

  • 图片

  • 图标

  • 字体

  • 局部样式文件

  • 一些需要被构建工具处理的静态资源

比如:

复制代码
src/
  assets/
    logo.png
    banner.jpg
    main.css

你可以把它理解成:

和项目源码关系比较紧密、会参与打包处理的资源文件目录。


1. 常见会放哪些东西?

例如:

  • 页面中引用的图片

  • 组件内部用到的图标

  • 全局样式文件

  • CSS/SCSS 文件

  • 字体文件

这在 Vue 项目里非常常见。


十一、publicassets 有什么区别?

这是新手高频问题。

两者都能放静态资源,但它们的定位不完全一样。


assets

更偏向:

作为源码的一部分,被项目构建过程管理。

通常适合放:

  • 组件中引用的图片

  • 项目内部样式资源

  • 跟源码关系密切的静态文件


public

更偏向:

原样保留、不经过源码模块系统管理的公共资源。

通常适合放:

  • 网站 favicon

  • 不需要 import 的静态文件

  • 一些直接通过路径访问的公共资源


直观理解

你前期可以先简单记成:

  • 组件里常引用的资源 ,多半放 assets

  • 公共直接访问的资源 ,可以放 public

对新手来说,先建立这个层级感就够了。


十二、router:路由配置目录

只要你的项目涉及多页面切换,几乎就会出现 router

它的核心职责是:

定义页面和路径之间的对应关系。

比如:

  • / 对应首页

  • /login 对应登录页

  • /profile 对应个人中心页

典型写法会像这样:

复制代码
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LoginView from '../views/LoginView.vue'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: HomeView },
    { path: '/login', component: LoginView }
  ]
})

export default router

所以你可以把 router 目录理解成:

整个项目的页面导航地图。


1. 为什么它很重要?

因为只要项目不是单页面小练习,而是真正的"多个页面切换",

就一定需要一个集中管理路由关系的地方。

router 的出现,会让你开始真正进入"应用级项目"的感觉。


十三、stores:全局状态管理目录

这个目录通常和 Pinia 配合出现。

它的核心职责是:

存放多个页面或多个组件之间需要共享的状态。

例如:

  • 当前登录用户信息

  • 购物车数据

  • 主题状态

  • 权限信息

  • 全局计数或缓存数据

如果这些数据只是某个组件自己用,那放组件内部就行。

但如果很多地方都要用,就适合放到 stores 里统一管理。


1. 为什么不直接组件里各写各的?

因为一旦数据需要跨组件、跨页面共享,

如果你还靠层层传 props,或者每个组件自己维护一份,就会非常混乱。

所以状态管理目录的本质意义在于:

集中管理"大家都要用"的共享状态。


2. stores 通常长什么样?

例如:

复制代码
src/
  stores/
    user.ts
    counter.ts

每个文件通常负责一类共享状态。

比如:

  • user.ts 管用户登录信息

  • cart.ts 管购物车

  • theme.ts 管主题模式

这会让全局状态职责清晰很多。


十四、api:接口请求目录

不是所有教程都一定会先建这个目录,

但在稍微正式一点的项目里,它非常常见。

它通常用来放:

和后端接口交互相关的请求函数。

例如:

  • 登录接口

  • 获取用户信息接口

  • 获取商品列表接口

  • 删除学生接口

你可以把它理解成:

把所有"请求后端"的代码集中放在一起。

这样做的好处是:

  • 页面组件更干净

  • 接口逻辑统一管理

  • 后期维护和修改更方便


一个简单例子

复制代码
import request from './request'

export const getUserInfo = () => {
  return request.get('/user/info')
}

然后页面中再去调用它。

这比直接在页面里到处写请求代码要清晰很多。


十五、utils:工具函数目录

这个目录通常放:

和业务页面无强绑定、可复用的通用工具函数。

比如:

  • 日期格式化

  • 金额格式化

  • 防抖节流

  • 字符串处理

  • 数组去重

  • 本地存储封装

例如:

复制代码
export const formatDate = (date) => {
  // 日期格式化逻辑
}

它的核心特征是:

  • 不是页面本身

  • 不是组件本身

  • 不是状态本身

  • 而是很多地方都可能会用到的小工具

所以把它们集中放在 utils 会很自然。


十六、composables:组合式逻辑复用目录

这个目录是 Vue3 组合式 API 时代很常见的一个目录。

它通常用来放:

可复用的组合逻辑函数。

比如你把一组逻辑封装成:

  • 获取鼠标位置

  • 处理分页逻辑

  • 表单校验逻辑

  • 搜索逻辑

  • 倒计时逻辑

这些逻辑本质上不是完整组件,

但它们又是可以被多个组件共用的。

这时候就很适合放在 composables 里。

例如:

复制代码
export function useCounter() {
  const count = ref(0)

  const add = () => count.value++

  return { count, add }
}

这就是典型的组合式逻辑封装。

你前期不一定马上大量使用它,

但知道这个目录的存在非常有帮助。


十七、一个比较常见的 Vue3 项目目录长什么样?

你可以先参考这种理解结构:

复制代码
src/
  assets/
  components/
  views/
  router/
  stores/
  api/
  utils/
  composables/
  App.vue
  main.ts

这里每个目录的角色大致就是:

  • assets:资源

  • components:局部可复用组件

  • views:页面

  • router:路由

  • stores:全局状态

  • api:接口

  • utils:工具函数

  • composables:组合式逻辑复用

  • App.vue:根组件

  • main.ts:启动入口

你只要先把这个"角色地图"记住,很多项目就能看懂个大概。


十八、小项目和正式项目目录为什么差别这么大?

这是新手特别容易困惑的一点。

原因其实很简单:

项目规模不同,结构需求就不同。

小项目可能只有:

复制代码
src/
  App.vue
  main.ts
  components/

因为功能简单,不需要更多分层。

而正式项目可能需要:

  • 多页面

  • 路由

  • 状态共享

  • 请求接口

  • 工具封装

  • 资源分类

那目录自然就会丰富起来。

所以不要误以为:

  • 小项目目录少就是不规范

  • 大项目目录多就是高级

真正合理的标准是:

目录结构是否和项目复杂度匹配。


十九、新手最常见的项目结构误区

这一部分很重要。


1. 什么都往 components 里塞

这是最高频问题之一。

很多新手一开始学组件化后,会把:

  • 页面

  • 弹窗

  • 表格

  • 路由页面

  • 大块布局

全都塞进 components

结果后面越来越难区分:

  • 哪个是局部模块

  • 哪个是整页

  • 哪个才是路由页面

所以一定要逐渐学会区分:

  • components 更偏零件

  • views 更偏整页


2. 什么都放在 App.vue

这在初学阶段非常常见,但不能长期这样。

一旦你发现 App.vue 里开始同时承担:

  • 页面内容

  • 列表逻辑

  • 路由逻辑

  • 组件组合

  • 表单逻辑

那就说明应该考虑拆分和分层了。


3. 盲目照搬大项目目录

有些人做一个很小的练习,也硬建:

  • api

  • stores

  • utils

  • composables

  • hooks

  • layouts

结果项目本身没多大,目录却特别复杂。

这不是规范,而是过度工程化。


4. 文件命名和目录职责混乱

比如:

  • 页面组件叫得像通用组件

  • 通用组件又放到页面目录

  • 工具函数随手放某个组件里

这样会让项目边界越来越糊。

所以从一开始就要有意识地让:

  • 目录职责清楚

  • 文件命名有语义


二十、你现在最需要建立的项目结构思维是什么?

我建议你先建立下面这几个意识。

1. 项目结构本质上是代码分类

不是形式主义。

2. 页面和组件不是一回事

viewscomponents 要逐渐分开理解。

3. 路由、状态、接口、工具,最好各有位置

这样项目长大后不会乱。

4. 目录不是越多越好,而是越清楚越好

始终围绕"方便维护"去设计。

只要这几个意识起来了,你后面看任何 Vue3 项目都会更顺。


二十一、这一篇学完后,你应该达到什么程度?

如果你把这篇真正理解了,至少应该做到:

  • 知道 main.ts 是项目启动入口

  • 知道 App.vue 是最外层根组件

  • 知道 components 放局部复用组件

  • 知道 views 放页面级组件

  • 知道 assetspublic 的基本区别

  • 知道 router 负责页面路径关系

  • 知道 stores 负责共享状态

  • 知道 apiutilscomposables 分别大致做什么

  • 知道项目目录不是越复杂越好,而要和项目规模匹配

只要这些点清楚了,你对 Vue3 的理解就会从"单个组件怎么写",进一步升级到:

一个完整项目大概是怎么组织起来的。


二十二、总结

这一篇文章,我们把 Vue3 项目结构中最核心的一批目录系统梳理了一遍。

最重要的主线可以浓缩成下面几句话:

  • main.ts:启动项目

  • App.vue:最外层根组件

  • components:局部可复用组件

  • views:页面级组件

  • assets / public:静态资源

  • router:页面路径管理

  • stores:共享状态管理

  • api:接口请求封装

  • utils:工具函数

  • composables:组合式逻辑复用

如果说前面的文章让你逐渐学会了:

  • 写页面

  • 写组件

  • 做组件通信

  • 会基础调试

那么这一篇的作用,就是让你开始真正具备:

看懂一个 Vue3 项目骨架的能力。

这一步很关键,因为接下来我们就要正式进入"应用级开发"里非常核心的一层了:路由与全局状态管理

相关推荐
雨雨雨雨雨别下啦2 小时前
Vue——小白也能学!Day6
前端·javascript·vue.js
XPoet2 小时前
AI 编程工程化:Hook——AI 每次操作前后的自动检查站
前端·后端·ai编程
難釋懷3 小时前
RedisTemplate配置读写分离
前端·bootstrap·html
冰暮流星3 小时前
javascript如何实现删除数组里面的重复元素
开发语言·前端·javascript
网络点点滴4 小时前
透传属性$attrs
前端·javascript·vue.js
90后的晨仔5 小时前
OpenClaw macOS 完整安装指南
前端
Moment5 小时前
尤雨溪宣布 Vite+ 正式开源,前端工具链要大一统了
前端·javascript·面试
喵叔哟5 小时前
5. 【Blazor全栈开发实战指南】--Blazor组件基础
开发语言·javascript·ecmascript
sunny_5 小时前
📖 2026年 大厂前端面试手写题库已开源(2.3k star)
前端·面试·github