基于前后端分离项目(Vue3 + Vite + TypeScript + Pinia + Element Plus)全程类比 SpringBoot 思维,新手可直接上手
一、项目结构与核心文件作用
1. 整体结构
plaintext
项目根目录
├── .vscode/ VSCode 编辑器配置
├── node_modules/ 第三方依赖库(≈ Maven 本地仓库)
├── public/ 静态资源(≈ SpringBoot static)
├── src/ 业务源码(主要开发目录)
├── dist/ 打包后部署文件(≈ target/)
├── package.json 依赖 + 启动脚本(≈ pom.xml)
└── index.html 项目入口页面
2. 关键文件说明
- package.json:管理依赖、定义
dev/build/lint等命令 - node_modules/ :
npm install生成,不提交 Git - dist/ :
npm run build后生成,用于部署 - public/ :存放 favicon.ico 等不参与编译的静态资源
- src/ :页面、组件、接口、状态、路由均在此
二、项目运行与启动流程
1. 常用命令
bash
运行
npm run dev # 启动开发服务(≈ mvn spring-boot:run)
npm run build # 生产打包(≈ mvn clean package)
npm install # 安装依赖
2. 浏览器启动 Vue 流程
- 访问地址 → 加载
index.html - 解析并加载
main.ts(项目入口) - 创建 Vue 实例,挂载到
#app节点 - 加载路由 → 根据 URL 渲染对应页面
3. 入口文件 main.ts(≈ 启动类)
ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
三、Pinia 状态管理(核心重点)
1. 是什么?
Pinia = 前端的 @Service + 全局单例 Bean + 内存缓存用于:全局共享数据、业务逻辑封装、接口调用、权限状态。
2. 基本结构
ts
import { defineStore } from 'pinia'
export const useXxxStore = defineStore('唯一标识', {
state: () => ({
// 数据 ≈ 类成员变量
}),
actions: {
// 方法 ≈ 业务逻辑(支持 async/await)
},
getters: {
// 计算属性 ≈ getXxx()
}
})
3. async /await 说明
- async:标记为异步方法
- await:等待异步操作完成(如接口请求)
- 本质:异步执行,但写法像同步,避免回调嵌套
四、前后端分离接口封装
1. API 层(≈ Mapper / Dao)
ts
// src/api/student.ts
import request from './index'
export interface Student {
id: number
name: string
className: string
}
export function getStudentList(params: { page: number; pageSize: number }) {
return request<{ list: Student[]; total: number }>({
url: '/student/list',
method: 'get',
params
})
}
2. 请求工具统一携带 Token
ts
// src/api/index.ts
import axios from 'axios'
import { useAuthStore } from '@/stores/authStore'
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL
})
// 请求拦截器自动加 token
request.interceptors.request.use(config => {
const authStore = useAuthStore()
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`
}
return config
})
export default request
五、路由 Vue Router(≈ @RequestMapping)
配置示例
ts
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/student',
component: () => import('@/views/StudentList.vue'),
meta: { requiresAuth: true }
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
六、完整可运行示例:学生管理
1. 学生 Store(≈ Service)
ts
// src/stores/studentStore.ts
import { defineStore } from 'pinia'
import { getStudentList, Student } from '@/api/student'
export const useStudentStore = defineStore('student', {
state: () => ({
list: [] as Student[],
total: 0,
page: 1,
pageSize: 10,
loading: false
}),
actions: {
async fetchList() {
this.loading = true
try {
const res = await getStudentList({
page: this.page,
pageSize: this.pageSize
})
this.list = res.list
this.total = res.total
} finally {
this.loading = false
}
}
}
})
2. 学生列表页面(≈ Controller + View)
vue
// src/views/StudentList.vue
<template>
<el-card>
<el-table :data="studentStore.list" v-loading="studentStore.loading">
<el-table-column label="ID" prop="id" />
<el-table-column label="姓名" prop="name" />
<el-table-column label="班级" prop="className" />
</el-table>
<el-pagination
v-model:current-page="studentStore.page"
v-model:page-size="studentStore.pageSize"
:total="studentStore.total"
@current-change="studentStore.fetchList"
style="margin-top:16px; text-align:right"
/>
</el-card>
</template>
<script setup lang="ts">
import { useStudentStore } from '@/stores/studentStore'
const studentStore = useStudentStore()
studentStore.fetchList()
</script>
七、全局字典缓存(DictStore)
作用
统一管理性别、班级、状态等下拉数据,全局只请求一次。
ts
// src/stores/dictStore.ts
import { defineStore } from 'pinia'
import { getDictData } from '@/api/dict'
export const useDictStore = defineStore('dict', {
state: () => ({
gender: [],
classes: []
}),
actions: {
async loadDict() {
const res = await getDictData()
this.gender = res.gender
this.classes = res.classes
}
}
})
使用方式
ts
// App.vue 中全局加载一次
const dictStore = useDictStore()
dictStore.loadDict()
// 页面中直接使用缓存
dictStore.gender
dictStore.classes
八、前后端 MVC 对应关系
表格
| 前端技术 | Java 后端对应 |
|---|---|
| Vue 页面 | Controller + View |
| Pinia Store | Service 层 |
| API 接口 | Mapper / Dao |
| Pinia state | 成员变量 / 缓存 |
| axios | RestTemplate / WebClient |
| Vue Router | @RequestMapping |
| package.json | pom.xml |
| node_modules | Maven 依赖库 |
| dist 目录 | target 编译目录 |
九、核心知识点总结
- Vue 是前端框架,相当于浏览器里的 SpringBoot
- Pinia 是状态管理,相当于全局 Service + 缓存
- async/await 用于异步请求后端接口
- API 层统一封装接口,便于维护和加 Token
- 路由控制页面跳转,类似后端接口路由
- 项目结构、分层思想与后端高度一致
十、学习路线(后端工程师推荐)
- 项目结构与文件作用
- 启动流程与
main.ts - Pinia 基本使用
- 接口调用与 axios 封装
- 路由与登录权限
- 表格、表单、增删改查
- 全局字典、缓存、权限控制