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

Vue3+ElementPlus前后端分离项目实战

Hello,大家好,我是Yize,好久不见,最近一直在完成JavaWeb的学习,这两天在进行前端开发的时候发现了一个非常有意思的开发模式,下面就跟我一起来学习吧!!!


Vue3 + Element Plus 前后端分离项目:从页面到后端如何进行


一、前言

在前后端分离开发中,和我一样的很多初学者会遇到这样的困惑:

  • 我点了页面上的"新增"按钮,数据是怎么跑到数据库里的?

  • proxy配置到底是干嘛的?不配行不行?

  • 为什么我的请求 404 了?

下面将根据我最近在完成的Tlias智能学习辅助系统为例,把前端页面、API 请求层、Vite 代理配置三段代码串联起来,带领大家彻底搞懂前后端分离项目的运行全貌。


二、项目结构概览

我们的部门管理模块涉及三个关键文件:

project/ ├── vite.config.js # Vite 配置(含代理) ├── src/ │ ├── api/ │ │ └── depts.js # API 请求层 │ ├── views/ │ │ └── depts.vue # 部门管理页面组件 │ └── utils/ │ └── request.js # axios 封装(本文不展开)

三层架构关系:

┌────────────────────────────────────────────────────┐ │ Vue 组件 (depts.vue) │ │ ↑ 调用 ↓ 渲染 │ │ API 层 (depts.js) │ │ ↑ 发送请求 │ │ Vite Proxy │ │ ↓ 转发 │ │ 后端服务器 (localhost:8080) │ └────────────────────────────────────────────────────┘

三、第一层:Vite 代理配置

先看vite.config.js中的核心配置:

export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, server: { proxy: { '/api': { target: 'http://localhost:8080', secure: false, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), } } } })

这段配置做了什么?

配置项

作用

alias: { '@': ... }

@映射为src/目录,写导入路径时可以写@/api/depts而不用写相对路径

'/api'

拦截所有以/api开头的请求

target

转发到后端服务器地址

changeOrigin

修改请求头中的 Origin,避免后端跨域拦截

rewrite

去掉/api前缀后再转发

举个例子

假设request.js中配置了baseURL: '/api'

前端请求: /api/depts ↓ Vite 代理转发 实际到达: http://localhost:8080/depts

💡为什么要代理?​ 开发环境下前端跑在localhost:5173,后端跑在localhost:8080,不同端口会产生跨域问题。通过 Vite 代理,浏览器只和5173通信,由 Vite 服务端转发请求到8080,绕过了浏览器的同源策略。


四、第二层:API 请求层

src/api/depts.js负责把业务操作翻译成 HTTP 请求:

import request from '@/utils/request.js' // 查询全部部门 export const queryAllApi = () => request.get('/depts') // 添加部门 export const addDeptApi = (data) => request.post('/depts', data) // 根据ID查询 export const queryInfoApi = (id) => request.get(`/depts/${id}`) // 修改部门 export const updateDeptApi = (data) => request.put('/depts', data) // 删除部门 export const deleteDeptApi = (id) => request.delete(`/depts?id=${id}`)

RESTful 风格一览

业务操作

HTTP 方法

请求路径

说明

查询全部

GET

/depts

无请求体

查询单个

GET

/depts/{id}

路径参数

新增

POST

/depts

data 在请求体中

修改

PUT

/depts

data 在请求体中

删除

DELETE

/depts?id={id}

查询参数


五、第三层:Vue 组件(业务控制层)

depts.vue是整个页面的核心,我们用<script setup>语法编写:

5.1 数据定义与初始化

import { ref, onMounted } from 'vue' import { queryAllApi, addDeptApi, queryInfoApi, updateDeptApi, deleteDeptApi } from '@/api/depts' // 表格数据 let deptList = ref([]) // 页面挂载时加载数据 onMounted(() => { queryAll() }) const queryAll = async () => { const result = await queryAllApi() deptList.value = result.data }

运行流程:

组件挂载(onMounted) → 调用 queryAll() → await queryAllApi() // 发送 GET /depts → 后端返回 { code: 200, data: [...] } → deptList.value = result.data → 响应式更新,表格自动渲染

5.2 新增部门

const add = () => { formTitle.value = '新增部门' showDialog.value = true deptForm.value = { name: '' } }

用户点击"确定"后的提交流程:

const save = async () => { await deptFormRef.value.validate(async valid => { if (!valid) return let result = null if (deptForm.value.id) { result = await updateDeptApi(deptForm.value) // 修改 } else { result = await addDeptApi(deptForm.value) // 新增 } if (result.code) { ElMessage.success('操作成功') showDialog.value = false resetForm() queryAll() // 刷新列表 } else { ElMessage.error(result.msg) } }) }

关键点:通过判断deptForm.value.id是否存在来区分"新增"和"修改",复用同一个对话框和提交方法。


5.3 修改部门

const handleEdit = async (id) => { formTitle.value = '修改部门' showDialog.value = true deptForm.value = { name: '' } const result = await queryInfoApi(id) if (result.code) { deptForm.value = result.data // 回显数据 } }

回显逻辑:先打开弹窗,再根据 ID 查询完整数据填充表单,用户修改后点确定走save()方法。


5.4 删除部门

const handleDelete = (id) => { ElMessageBox.confirm('此操作将永久删除该部门, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { const result = await deleteDeptApi(id) if (result.code) { ElMessage.success('删除成功') queryAll() // 刷新列表 } }) }

先用ElMessageBox弹确认框,用户确认后才真正发删除请求。


六、完整调用链路图

以"修改部门"为例,完整的数据流转如下:

┌─────────────────────────────────────────────────────────────┐ │ ① 用户点击"修改"按钮 │ │ → handleEdit(id) │ ├─────────────────────────────────────────────────────────────┤ │ ② 调用 API 层 │ │ → queryInfoApi(id) │ │ → GET /depts/1 │ ├─────────────────────────────────────────────────────────────┤ │ ③ Vite 代理转发 │ │ → /api/depts/1 → http://localhost:8080/depts/1 │ ├─────────────────────────────────────────────────────────────┤ │ ④ 后端处理 │ │ → Controller 接收请求 │ │ → Service 调用业务逻辑 │ │ → Mapper 查询数据库 │ │ → 返回 { code: 200, data: { id: 1, name: "研发部" } } │ ├─────────────────────────────────────────────────────────────┤ │ ⑤ 前端接收响应 │ │ → deptForm.value = result.data │ │ → 表单回显"研发部" │ ├─────────────────────────────────────────────────────────────┤ │ ⑥ 用户修改名称,点击"确定" │ │ → save() → updateDeptApi(data) │ │ → PUT /depts → 后端更新数据库 │ │ → queryAll() → 表格刷新 │ └─────────────────────────────────────────────────────────────┘

七、常见坑点与最佳实践

7.1 代理不生效

现象:请求直接打到前端端口,报 404。

排查

  • 检查request.js中是否配置了baseURL: '/api'

  • 检查 API 层路径是否以/depts开头(不带/api

  • 两者必须配套,否则代理匹配不到/api规则

7.2 跨域问题

现象:浏览器控制台报 CORS 错误。

解决

  • 开发环境:确保 Vite 代理配置正确

  • 生产环境:让后端配置 CORS 或通过 Nginx 反向代理

7.3 代码风格统一建议

// ❌ 不一致的风格 GET /depts/{id} // 路径参数 DELETE /depts?id={id} // 查询参数 // ✅ 统一 RESTful 风格 GET /depts/{id} PUT /depts/{id} DELETE /depts/{id}

八、总结

通过这一个部门管理模块,我们看到了前后端分离项目的典型分层:

层级

文件

职责

视图层

depts.vue

页面渲染、用户交互、状态管理

请求层

depts.js

封装 API、翻译业务操作为 HTTP 请求

配置层

vite.config.js

开发代理、路径别名

后端

Spring Boot(未展开)

处理业务、操作数据库

核心思想:每一层只关心自己的事。组件不关心请求怎么发出去,API 层不关心数据怎么展示,代理不关心业务逻辑。各司其职,维护起来就清晰多了。(这就非常像我们后端的三层架构设计)

好啦,这次的分享到此结束,后面遇到好玩的东西我会继续分享,我们下期再见!!

http://www.jsqmd.com/news/1311727/

相关文章:

  • 2026抖店无货源合规运营全攻略:避开90%商家踩中的风控红线,一套工具搞定铺货+自动履约 - 电商分享
  • 基于CH348L的8路USB转TTL串口扩展器设计全解析
  • vn.py 量化交易框架实践指南:从安装配置到 CTA 策略回测
  • mncli配ip踩坑日记
  • 从零理解数据维度:高维灾难、降维实战与业务应用全解析
  • 从高压放电原理看美容电弧笔的技术缺陷:为什么家用款必然不安全
  • AutoCAD .NET插件自动化加载:LSP脚本驱动NETLOAD的工程实践
  • reBotArm B601 DM / ROS 2 工程文件架构
  • OpenRouter下调GPT-5.6价格:大模型API成本优化与实战集成指南
  • GEOSLAM移动激光测绘实战:从原理到应用的全流程解析
  • 2026年程序员必备:大模型技术体系与实战指南
  • Android开发入门指南:从环境搭建到第一个应用实战
  • Burp Suite宏实战:自动化破解动态Token登录防护
  • 3个月备考信息系统管理工程师——第一天——信息与信息化现代化基础设施
  • 海山数据库(HaishanDB)面向能源行业全场景技术方案
  • 2026年灭火器充装厂家怎么选?成都地区正规消防器材服务商甄选参考 - 优质品牌商家
  • 2026 年 7 月新发布:合川靠谱的201 不锈钢水箱生产厂家联系方式,别再乱买水箱了,用它存水竟会埋下健康隐患!-潇湘凌云供水设备 - 企业推荐官【认证】
  • 用QEMU搭建ARM Linux驱动开发环境:从虚拟到真实的嵌入式学习路径
  • 圆偏振光显示技术发展史:从 LCD 偏光片到 OLED 护眼膜的技术演进
  • 树莓派变身家庭媒体中心:OSMC+Kodi打造全能电视盒子
  • 树莓派驱动7.8英寸电子墨水屏:从SPI通信到低功耗信息显示实战
  • 智能社交架构解析:从AI Agent到AIGC的社交产品重构
  • 2026 年至今,南沙知名的回收旧电缆电线企业哪家靠谱,收废品的靠它月入过万?很多人还当废铁卖亏大了-成信废旧物资回收 - 行业严选官
  • 领普C6无刷窗帘电机深度评测:Matter协议与静音动力如何重塑智能家居体验
  • 2026年国内气压弹簧怎么选?从行业数据看采购关键点与厂商参考 - 优质品牌商家
  • Ubuntu下SD卡分区格式化全攻略:从fdisk到parted实战指南
  • 3分钟快速上手Balena Etcher:跨平台镜像烧录终极指南
  • 谷歌开源Groundsource:用Gemini大模型从新闻中构建全球洪水数据集
  • 2.42英寸OLED模块驱动指南:从硬件连接到网络时钟实战
  • SAP ABAP ALV报表状态指示灯实现:红绿黄灯图标显示与实战指南