当前位置: 首页 > news >正文

Vue3 项目的基本架构解读

目录

一. Vue项目构成及核心文件解读

1.1 assest 静态资源文件

1.2 utils 工具包

1.3 api,controller,http 包

1.4 view,page 包的页面组件

1.5 component 公共组件、UI组件

1.6 router/index.js——路由配置

1.7 store/index.js——状态管理

1.8 app.vue 

1.9 main.js 应用初始化脚本

1.10 HTML 应用入口容器文件

二. Vue 项目启动文件加载流程及依赖分析


在接手一个Vue项目时,合理的项目结构可能让我们非常迅速地对一个项目进行了解;此外,一个和良好的项目结构,对于项目后期的维护性和扩展性都是极有帮助的。下面我们就一起来看一个相对完整的Vue项目吧!       

一. Vue项目构成及核心文件解读

如上图所示,就是一个相对完整的Vue项目,大致可以分为10部分,我都一一对应做出了标注。

下面在介绍的时候,不会按照图片标注的顺序来进行说明,我们先从代码、图片文件介绍,再介绍项目结构、配置文件,方便同学们更好理解。

1.1 assest 静态资源文件

作用:存放静态资源文件 

这个应该是最好理解的了,里面通常会存放一些项目图片,网站图标,CSS样式文件,字体文件等。如果将文件夹展开,通常是下面这样,assest 大文件夹包含四个小文件夹,每个文件夹下存放对应的资源文件,这里就不展开说了,很好理解。

需要注意的一点是,在有一些中型以及大型项目中,由图片、图标、CSS、字体设置文件由于数量较多,会分为四个顶层文件夹来存储,就不再全部或部分存储到 assest 文件夹中啦,这一点小伙伴们可以注意一下,以后遇到了其他的Vue项目发现不一样也不用惊奇,这四类文件位置放哪都可以,但一般要么放一起,要么分四个放,要么部分放一起,都无所谓的。

1.2 utils 工具包

作用:存放工具类JS文件

这个基本上也不用怎么说,就是存放一些提前定义好的工具类JS文件,JS方法,类似于spring boot 项目的 utils 工具包,存放各种定义好的Java方法。

下面是我已经写好的一些JS文件,可以简单看下,从名字基本就能看出来是干什么用的,Date就是处理时间的,math是数学运算的......

1.3 api,controller,http 包

作用:存放与后端交互的请求函数接口规范JS文件

向后端发送请求时,通常需要设置请求参数、请求方式、请求地址,这些通常都会在JS文件中提前定义好。其实之所以叫 api,controller,http 是因为在不同的项目中,或因个人习惯的不同,这个 request 请求包通常会有不同的命名方式,但比较常见的是以上三种,

如下图所示,我简单展示该包下的文件。

然后我打开 baseCode.js 文件,小伙伴们可以简单看一下,不难发现,里面都是已经提前定义的接口规范,例如方法名称、参数值、参数处理、URL地址、HTTP请求类型等,然后使用 export 导出,这样就可以在其它Vue组件中导入使用,类似于Java后端的 import 导包,这种做法极大的提高了代码的可复用性,只定义一个HTTP函数,在项目多处都可以导入使用,极大程度上做到了我们开发中常说的低耦合!

import request from '@/utils/request'
import PromiseCache from '@/utils/PromiseCache'const queryLikeCache = new PromiseCache()
const queryInCache = new PromiseCache()export function queryLike(codeType, query, otherConditions) {const key = JSON.stringify({ codeType, query, otherConditions })return queryLikeCache.getCached(key, () => {return request({url: '/baseCode/queryLike',method: 'post',data: { codeType, query, otherConditions }})})
}export function queryIn(codeType, codes) {const key = JSON.stringify({ codeType, codes })return queryInCache.getCached(key, () => {return request({url: '/baseCode/queryIn',method: 'post',data: { codeType, codes }})})
}

在以往的 JavaScript 代码中,如下代码所示,通常都是直接在 JavaScript 代码中使用 Ajax、Axios 发送 HTTP 请求,这种做法就显得不够优雅,如下,envConfig.api.ip + config.backend.companyInfo 是已经提前封装在其他配置文件中了,所以显得简洁一些,如果没有封装,就会变得非常杂乱。

$http.post(envConfig.api.ip + config.backend.companyInfo, {"searchKey": $scope.clientData.insuredName
}).then(function(res){if(res.data.VerifyResult=='1'){$scope.clientData.smallMicroBusinesses='1';if($scope.companyData){$scope.companyData.smallMicroBusinesses = '1';}parentScope.proposal.prpTmainVo.smallMicroBusinesses='1';}else {$scope.clientData.smallMicroBusinesses='0';if($scope.companyData){$scope.companyData.smallMicroBusinesses = '0';}parentScope.proposal.prpTmainVo.smallMicroBusinesses='0';}
});

当我们使用了 export 导出方法和 import 导入之后,代码就可以变成下面这个样子。

首先第一步:导包,将提前定义好的 HTTP 规范函数导进来;

其次第二步:编写HTML这种页面元素,绑定 button1 单击函数,传递查询参数;

最后第三步:在 vue 的 method 列表中添加 button1 函数,在函数中注解调用已经导入进来的方法 queryLike,传递查询参数;

如此再来看,在整个文件中,几乎看不出来有调用 HTTP 的痕迹,全是纯代码逻辑编写,代码之间的耦合度也降低了,非常的优雅!

1. 导包部分
import { queryLike } from '@/api/common/baseCode'2. 页面部分
<el-button :disabled="editDisableds" @click="button12()">)</el-button>3. vue中的 method 方法
methods: {button1() {queryLike('feeMethod', this.intermediaryjg.feeMethod, {}).then((response) => {for (const item of response.data) {console.log(item.cname)this.intermediaryjg.formula = this.intermediaryjg.formula + '' + item.cname}})},
}

1.4 view,page 包的页面组件

作用:存放向用户实际展示的页面级别Vue组件(通常与路由对应)

简单来讲,就是之前的 .HTML 文件,有一点不同的是,在 vue 项目中,通常不会在使用 .html 文件,而是使用 .vue 文件,而且通常会搭配 elemenUI 组件一同使用,这里没什么好解释的。

此外,我这里将软件包定义为 view ,在一些其他项目中,因为项目开发习惯的不同,有些人会将软件包定义为 page,所以同学们下次见到不必大惊小怪,二者一般情况下都可以用来存放页面文件。

在这个软件包下,通常不同的模块还会定义子包,比如用户模块的页面文件都放在 user 包下;orders 订单模块的页面文件都放在 orders 包下;后台管理页面文件都放在 admin 包下;

1.5 component 公共组件、UI组件

作用:存放可复用的 Vue 组件

组件是 Vue 项目中一个非常重要的组成部分,广义上来说,任何一个定义的以 .vue 结尾的文件,都可以被看作是一个 Vue 组件,只需要在文件中使用如下语法,就可以把当前 .vue 文件作为一个组件使用导入到其他文件中或被其组件嵌套使用。

export default {// 1. 组件标识:当前要导出的组件名称,自定义名称,便于调试和递归name: 'UserCard',// 2. 数据管理:内部用来定义双向绑定的数据data() {return {isExpanded: false}},// 3. 方法:就是自定义的方法函数,都写在 methods 里面methods: {toggleExpand() {this.isExpanded = !this.isExpanded}},// 4. 组件注册:组件之间可以相互调用,import 导入后就在这里面声明components: {UserAvatar,UserInfo}// 5. 属性接收 (Props),可以用于验证、校验数据是否输入正确props: {user: {type: Object,required: true}},
}

在 Vue 项目中,组件也是有多种多样的,我就列举了两类比较常见的,一个是公共组件,一个是UI组件。

其实二者区别不大,指示作用不太相同,公共组件类似于Java后端代码的 common 公共包,里面定义一些比较通用的组件;UI组件也是一样,就是提前定义好的一些界面样式,有时候很多网页结构都是非常相似的,这个时候我们就可以将网页结构整体提出来,然后在每一个 .vue 文件中进行导入直接复用,提高了代码的质量,降低了冗余度。

如下图,就是组件包展开的样子,一般可以定义两个子包,layout 通常存放公共组件;ui 就用来存放UI组件。

1.6 router/index.js——路由配置

作用:存放路由配置(路径与组件的映射),管理页面跳转和路由守卫。

该文件夹下通常只含有一个核心文件 index.js ,index.js 文件中会定义所有的页面组件和路径的映射关系

注意!!!这里所指的页面组件就是直接展示给用户浏览的页面,基本上就是 view、page包下的页面组件,而公共组件包是不映射的,具体是否映射见下表格。

需要路由定义的组件不需要路由定义的组件

(1) 通过URL直接访问的页面;

(2) 需要深度链接的页面;

(3) 需要浏览器导航功能的页面;

(1)纯UI组件:按钮/卡片;
(2)业务子组件:表单/列表;
(3)弹窗/抽屉等临时组建

举个栗子更好理解:如下图所示,我的 view 页面定义了几个页面组件,admin 管理员界面、OrderCenter 订单中心页面、Login 登陆页面等都是需要在浏览器直接展示的;

如果映射关系对应的 index.js 文件中,代码如下:path 就是浏览器要展示URL路径地址,然后对应 component 中所写的页面组件,这样一来就可以通过此路由文件来控制展示给用户的界面了。此外,404Not Found 页面通常要写在末尾,否则会报错,这一点要注意!

// 1. 导入需要用的组件
import VueRouter from 'vue-router';// 2. 定义路由映射关系
// path:自定义的,就是浏览器上显示的URL路径;
// name:自定义名称,通常可以命名为文件名称;
// component: 编写组件所在的文件路径
const routes = [{path:'/admin/admin1',name:'admin1',component:()=>import('../view/admin/admin1.vue')},{path:'/orders/OrderCenter',name:'OrderCenter',component:()=>import('../view/orders/OrderCenter.vue')},{path:'/user/Login',name:'Login',component:()=>import('../view/user/Login.vue')},{path:'/user/UserCenter',name:'UserCenter',component:()=>import('../view/user/UserCenter.vue')},{path:'/Home',name:'Home',component:()=>import('../view/Home.vue')},{path:'/404',name:'404',component:()=>import('../view/404.vue')},
]// 3. 创建路由实例
const router = new VueRouter({mode:'history',routes
})// 4. 导出当前路由组件,供其它组件使用
export default router;

另外一个小芝士,component 组建的路径定义中,我使用了 ".." ,表示当前文件夹的上一层,就拿 admin.vue 路由举例,有些小伙伴可能见过下面这种写法。

    {path:'/admin/admin1',name:'admin1',component:()=>import('@/view/admin/admin1.vue')},

其实在这里 "@" 和 ".." 表述的意思相近,".." 表示当前文件夹的上一层,就是 view 文件的上一层 src,是相对路径。

而"@"是 webpack/Vite 的路径别名,默认指向项目根目录下的 src 目录,与文件位置无关,是绝对路径。

二者的区别如下表格

特性.. (相对路径)@ (绝对路径)
解析基础基于当前文件位置基于工程根目录
是否受文件位置影响是 (文件移动会导致路径失效)否 (全局有效)
推荐度★★☆☆☆★★★★★
配置位置无需配置需在 webpack/vite 中配置别名
典型路径../view/admin/admin1.vue@/view/admin/admin1.vue

小编这里图省事,使用了 ".." ,但小编个人更推荐 "@",只是使用"@"需要注意一点,要提前在

如果使用 Vue2 ,要提前在 vue.config.js 中配置@别名,如下所示

const path = require('path')module.exports = {configureWebpack: {name: name,resolve: {alias: {'@': path.resolve( 'src'),}},}
}

如果使用 Vue3 ,要提前在 vite.config.js 中配置@别名,如下所示

import { defineConfig } from 'vite'
import path from 'path'export default defineConfig({resolve: {alias: {'@': path.resolve(__dirname, './src'),}}
})

1.7 store/index.js——状态管理

作用:集中管理应用状态(如用户信息、全局配置),提供响应式数据和状态变更方法

使用 Pinia(Vue 3 推荐)或 Vuex。

示例代码如下:

// store/index.js (Pinia 示例)
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => ({ count: 0 }),actions: {increment() {this.count++}}
})

在经过 export 导出之后, 当前组件会被 main.js 文件注册并导入到 Vue 应用中。

其他组件通过 useStore()(Pinia)或 this.$store(Vuex)访问状态。

1.8 app.vue 

作用:应用顶级组件,所有页面的容器;

app.vue 内部通常定义全局布局(如导航栏/页脚),全局样式等,包含路由视图容器 <router-view>

<template><div id="app"><!-- 全局导航栏 --><nav><router-link to="/">Home</router-link> |<router-link to="/about">About</router-link></nav><!-- 路由页面渲染区 --><router-view/><!-- 全局页脚 --><footer>© 2025 ZhangSir</footer></div>
</template><script>
// 导出当前 app 根容器,然后在 main.js 文件中导入使用
export default {name: 'App',// 可在此添加全局逻辑(如用户登录状态检查)
}
</script><style scoped>
/* 全局样式 */
nav { padding: 20px; }
footer { margin-top: 50px; }
</style>

1.9 main.js 应用初始化脚本

作用:创建Vue应用实例、集成全局插件(路由Router、状态管理Store等)、挂载应用到DOM

如下实例代码,

第一步:导包。将我们上面定义的路由router、状态管理store、Vue根容器以及一些其他第三方组件如ElementUI等全部导入;

第二步:注入。创建一个 Vue 实例,并将导入的包全部注入到 Vue 实例中;

第三步:挂载。将 Vue 实例挂载到 id = "app" DOM节点上(此处的DOM节点通常就是指我们下面 index.html 文件中 id = "app" 的 div 元素块)。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'   // 导入路由配置
import store from './store'     // 导入状态仓库const app = createApp(App)
// 注入路由系统
app.use(router)
// 注入状态管理
app.use(store)
// 挂载到id="app"的DOM节点
app.mount('#app')
// 可选:全局错误处理
app.config.errorHandler = (err) => {console.error('全局错误:', err)
}

1.10 HTML 应用入口容器文件

作用:整个单页面应用(SPA)的HTML基础模板、提供Vue应用挂载的根节点(<div id="app">)、引入全局CSS/JS资源(如字体、SDK等)。

是整个Vue文件的基础模板,通常含有一个根元素,提供上方创建的 vue 应用挂载的根节点(<div id = "app">),Vue 应用会挂在到这个元素上。此外,还可以引入打包后的JavaScript、CSS文件作为全局的CSS、JS资源(如字体、SDK等)。

示例代码如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>My Vue App</title><!-- 引入全局样式 --><link rel="stylesheet" href="https://cdn.example.com/font.css"><!-- 引入打包后的JS文件 --><script src="./dist/main.js"></script>
</head>
<body><!-- Vue应用挂载点 --><div id="app"></div><!-- 构建工具会自动注入打包后的JS文件 --><script type="module" src="/src/main.js"></script>
</body>
</html>

二. Vue 项目启动文件加载流程及依赖分析

1. index.html 文件被浏览器加载,其中包含一个挂载点,通常为<div id = “app”>和引入 main.js 的脚本文件;

2. main.js 文件执行:

   导入 Vue 库、导入 App.vue 作为根组件、导入 router 和 store、创建 Vue 实例并将 router 和 store 注入到 Vue 中,再渲染 app.vue。

3. app.vue 被渲染

   在模板中可能含有全局组件(如<NavBar> 和 <router-view>);此时,router开始根据文件内的URL地址匹配路由;

4. router 根据路由配置,加在对应的 view 页面组件,如 Home.vue;

5. view 组件被渲染

   在 view 页面组件中,极大概率会引用 component 中的子组件;

   在`created`或`mounted`钩子中,可能通过`api`调用接口,或通过`store`访问/修改全局状态;

6. **store** 中的actions可能调用`api`模块,`api`模块使用`utils`中的请求工具发送请求;

7. **components** 组件在`views`中被使用,它们可能使用`assets`中的资源(如图片)或`utils`中的工具函数;

综合上面的话,大致可以总结为下面这张图

各个模块可能出现的依赖关系如下表格

模块/组件/文件名称依赖模块被依赖模块
index.htmlmain.js (作为入口文件被加载)
main.js

app.vue (根组件)

router (路由系统)

store (状态管理系统)

assest (静态资源文件)

utils (工具包)

无 (是项目入口,不被其他文件依赖)
App.vue

router (使用<router-view>)

conponent (全局布局组件)

assest (应用级样式)

main.js (作为根组件被加载)
router(router/index.js)

view/*.vue (路由组成)

store (路由守卫使用 Vuex)

main.js (初始化)

app.vue (提供路由视图容器)

store(store/index.js)

api (调用网络请求)

utils (数据处理工具,各种工具类方法)

main.js (初始化)

view/*.vue (使用状态)

component (使用状态)

view(页面组件)

conponent (使用子组件)

api (请求调用)

store (使用 Vuex)

utils (页面工具,各种方法)

assest (静态资源,多为图片图标等)

router (被路由引用)
component(可复用组件)

assest (组件资源)

utils (组件工具)

其它 component (组件之间可以互相嵌套)

view (被页面引用)

App.vue (全局组件)

api(请求函数模块)utils工具模块(如请求拦截器、数据处理等)

store (Vuex action调用)

view (页面组件调用)

assest(静态资源模块)

App.vue、view 、component 

utils(工具包)

api、store、view、component

依赖循环处理,在有些项目中,会出现 store 依赖 utils,同时 utils 也依赖 store 的情况,

解决方案:

1:依赖注入,在 main.js 文件中初始化工具

// main.js
import utils from '@/utils'
import store from './store'utils.setStore(store) // 注入store依赖

2:延迟加载,在函数内部 require

// utils/auth.js
export const getToken = () => {const store = require('@/store') // 动态引入return store.state.token
}

3:架构重组,将共享功能提取到独立模块

相关文章:

  • 2012-2023年 上市公司-知识重组创造、知识重组再利用数据-社科经管实证数据
  • 《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析LLP (二)
  • 备份还原打印机驱动
  • 数据库管理与高可用-MySQL高可用
  • Java基于SpringBoot的校园闲置物品交易系统,附源码+文档说明
  • 以智能管理为基础,楼宇自控打造建筑碳中和新路径
  • WebFuture 系统升级提示外键约束的问题处理
  • WebWorker-----高频面试题(浏览器篇)
  • 30、memory-order-relaxed
  • 从零开始开发纯血鸿蒙应用之网络检测
  • A Execllent Software Project Review and Solutions
  • 【物联网-ModBus-RTU
  • 【Go语言基础【14】】defer与异常处理(panic、recover)
  • 【HarmonyOS 5】拍摄美化开发实践介绍以及详细案例
  • 关于datetime获取时间的问题
  • n8n + AI Agent:AI 自动化生成测试用例并支持导出 Excel
  • 洛谷P12170 [蓝桥杯 2025 省 Python B] 攻击次数
  • PLC有脉冲输出,但伺服电机无法旋转
  • 数组名作为函数参数详解 —— 指针退化及遍历应用示例
  • 一款“短小精悍的”手机录屏软件
  • 优秀的定制网站建设制作商/sem竞价是什么
  • 电影网站建设教学视频/西安seo排名扣费
  • 福建建设执业资格网站报名系统/seo建站是什么意思
  • wordpress多主题/长沙优化科技
  • 电商网站业务流程/百度图片搜索图片识别
  • wordpress论坛系统/微信搜索seo优化