简介:面向 Vue3 初学者与前端开发者的开箱即用工程,基于 Vue3 新语法 + Element-Plus 组件库搭建,同时集成了 Mockjs 假数据与 axios 请求工具。工程内已成功建立一个基于 Element-Plus 表格组件的示例页面,能直观看到组件引入、数据 mock 与页面搭建的完整写法,适合快速上手新工程或验证自己的页面思路。整个压缩包共 27 个文件,以 9 个 Vue 组件文件、3 个 JSON 配置文件、3 个 JS 脚本和 3 个 MD 说明文档为主,其中 JSON 负责依赖与项目配置、JS 承担 mock 与构建脚本、MD 记录使用要点,辅以 CSS、HTML、PNG 等资源文件,包体仅 130KB,轻量且目录清晰。源码注释与说明文档覆盖了 Vue3 语法、Element-Plus 引入方式、Mockjs 的拦截用法等关键点,拿到后可直接在已配置好的环境中运行并扩展新页面。工程预设了基础依赖与脚手架,省去手动配置环节,适合边看边练、快速构建 Vue3 demo 的读者;目前已有 2140 人学习下载。
1. 这套 Vue3 + Element-Plus + mockjs 的 demo,解决的是“接口还没好,前端先干活”
接到一个后台管理类的前端需求,原型要评审、交互要演示,可后端的接口连影子都没有。很多开发者的第一反应是干等,或者拿 JSON 文件硬塞,但页面一多、表格一复杂,假数据就散得到处都是。这套“Vue3 框架 + Element-Plus 库 + mockjs 假数据”的 vue3-demo,本质是一个已经配好依赖、配好路由、配好 mock 层的可运行工程,克隆下来装完依赖就能npm run dev。它适合三种人:刚接触 Vue3 组合式 API 的前端新手,需要在没有后端的情况下快速出页面原型的开发者,以及想用假数据先把接口字段和分页规则敲定、再交给后端的联调双方。核心价值不是“能跑”,而是 mock 层和 UI 层之间已经有一条清晰的替换路径——真实接口就绪后,改一行配置就能切换。
2. 把环境跑起来:依赖、启动命令与目录结构一次弄清
标题里“环境已经配好拿来就用”这句话,指的是一套工程已经把 Vue3、Element-Plus、mockjs、Vite、路由和 API 封装层全部组装好。你拿到手要做的第一件事,是把它跑起来,并且确认每个预配的部分真的在工作。
2.1 从零到跑起来的三条命令:依赖安装、启动与构建检查
不管这套 demo 是压缩包还是 Git 仓库形式,第一步永远是安装依赖。Vue3 + Element-Plus + mockjs 的组合在 npm 生态里非常成熟,依赖安装一般不会有大问题,但如果你本地的 Node 版本偏低,会直接卡在启动阶段——mockjs 本身是老牌库,兼容性没问题,Vite 和 Element-Plus 则对 Node 有硬性要求。我一般习惯先看 package.json 里的 engines 字段,再决定要不要升级本地 Node。
# 1. 安装依赖(首次执行,耐心等 1-3 分钟) npm install # 2. 启动开发服务器(默认端口 5173,启动成功会打印 Local 地址) npm run dev # 3. 构建产物检查(验证生产环境有没有隐性问题) npm run build第一条命令把项目里所有依赖装进 node_modules,包括 vue、element-plus、mockjs、vite、vue-router 和 axios。第二条命令里的dev脚本通常对应vite,它会在本地起一个开发服务器,支持热更新。第三条命令对应vite build,它会做完整的编译与打包,如果组件引入方式有错、资源路径有问题,build 阶段才会暴露出来。
启动成功后,浏览器打开http://localhost:5173,你能看到一个带侧边栏和顶部导航的后台管理框架页面,这就是 demo 的入口。如果页面白屏,优先看浏览器 Console 的红字报错;如果页面能打开但数据是空的,问题多半出在 mock 层,后面的排查章节会专门处理。
2.2 预配好的目录里藏着什么:mock、路由、组件三块各自负责什么
这套 demo 能“拿来就用”,是因为目录结构按职责拆好了。我拿到一套陌生工程,第一步永远是看目录,不看目录就改代码等于闭着眼开车。一个典型的预配目录长这样:
├── src │ ├── api # 接口请求封装层 │ │ └── user.js # 用户模块的请求函数 │ ├── mock # mockjs 假数据目录 │ │ ├── index.js # mock 入口,统一注册所有假接口 │ │ └── user.js # 用户列表、登录等假接口数据 │ ├── router # 路由配置 │ │ └── index.js # 侧边栏菜单与页面路由 │ ├── views # 页面组件 │ │ ├── dashboard # 首页仪表盘 │ │ └── system # 系统管理页面 │ │ └── user.vue # 用户列表页(最常改的页面) │ ├── App.vue │ └── main.js # 入口,挂载 Element-Plus 和 mock ├── vite.config.js # 开发服务器、代理、别名配置 ├── package.json └── index.htmlapi目录是把 axios 请求函数集中收编的地方,页面组件不直接写请求地址,而是调用api/user.js里导出的函数。这样做的直接好处是:mock 切真实后端时,只需要换baseURL或环境变量,页面代码一行不用动。
mock目录是本篇的重点。mock/index.js负责注册所有假接口,mock/user.js负责定义接口返回的数据模板。mockjs 的核心机制是拦截 XHR 请求,所以只要main.js引入了mock/index.js,前端发起的 axios 请求根本不会到网络层去,直接由 mockjs 在内存里模拟响应。
router目录里的路由配置决定了侧边栏有哪些菜单,菜单项与views下的页面一一对应。vite.config.js里通常预配了@别名指向src目录,这样代码里import xx from '@/api/user'就不会写错相对路径。
2.3 环境自检:怎么判断这套 demo“真的健康”
跑起来只是第一步,很多 demo 表面上能打开,但 mock 层是坏的,或者 Element-Plus 有一部分没挂上。我一般会用三步做快速自检:第一步,打开用户列表页,看表格里有没有随机生成的假数据——有,说明 mock 拦截成功;没有,说明 mock 层没启动或注册顺序不对。第二步,随便点一个编辑按钮,看能不能弹出 Element-Plus 的 Dialog 弹窗——弹得出来且带样式,说明 Element-Plus 的 JS 和 CSS 都正常工作。第三步,在手机模拟器或窄窗口下刷新页面,看表格会不会横向溢出、菜单会不会折叠异常——这一步用来验证响应式布局有没有被破坏。
如果这三步都过了,这套 demo 就是健康的,你可以放心在它上面加页面、改逻辑。如果哪一步不对,不要急着改代码,先把浏览器 Console 里的报错信息完整读一遍——百分之六十的问题,报错信息里已经写了答案。
3. Element-Plus 落进项目的三种挂法:全量、按需与主题调参
Element-Plus 是 Vue3 生态里最常用的组件库,但它不是装上就能用,挂载方式直接决定打包体积和维护体验。这套 demo 里预配的是全量引入,适合快速原型;但如果你打算在它之上继续做正式项目,大概率要切到按需引入。
3.1 全量与按需:两种挂载方式的取舍依据
全量引入是在main.js里把整个 Element-Plus 安装到 Vue 实例上,所有组件和样式一次性注册。这种方式的优点是省心,模板里随便写el-table、el-form不需要额外 import;缺点是打包产物大,一个空页面可能就多出几百 KB 的 JavaScript。
// src/main.js 全量引入方式的完整示例 import { createApp } from 'vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import App from './App.vue' import router from './router' import './mock' // 引入 mock 入口,注册所有假接口 const app = createApp(App) app.use(router) app.use(ElementPlus) // 全量注册 Element-Plus app.mount('#app')代码里app.use(ElementPlus)是核心,它把组件库整体注册成了全局组件;import './mock'这行决定了 mockjs 在应用启动时就被加载,mock 拦截必须在任何请求发出之前完成,所以它要放在createApp之前。参数层面需要注意,dist/index.css是完整样式文件,按需引入时不能这么写。
按需引入则借助 unplugin-vue-components 和 unplugin-auto-import 这两个构建期插件,打包时只把模板里用到的组件和对应的样式抽出来。体积能小很多,代价是配置多一层、第一次接触时容易漏配。
// vite.config.js 按需引入的核心配置片段 import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default defineConfig({ plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] }) ] })这段配置里的两个插件是有分工的:AutoImport负责自动引入 API 类的函数,比如ElMessage、ElMessageBox;Components负责自动引入模板里出现的组件,比如el-table。ElementPlusResolver是个解析器,它告诉插件“遇到 Element-Plus 组件时,样式文件去哪里找”。用好这套配置后,模板里写<el-button>,构建时会自动变成“组件代码 + 组件样式”的按需加载,不需要手动 import。
3.2 把表格和分页先搭出来:一段能直接跑的骨架代码
这套 demo 里最常被改的页面是用户列表,它由表格、分页、搜索表单三块组成。以下是一段可以直接粘贴进views/system/user.vue的骨架代码,它接上了 mockjs 假数据接口。
<template> <div class="user-page"> <!-- 搜索表单:名称关键字 + 状态筛选 --> <el-form :inline="true" :model="queryForm"> <el-form-item label="名称"> <el-input v-model="queryForm.name" placeholder="输入用户名称" clearable /> </el-form-item> <el-form-item label="状态"> <el-select v-model="queryForm.status" placeholder="全部" clearable> <el-option label="启用" :value="1" /> <el-option label="禁用" :value="0" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="handleSearch">查询</el-button> <el-button @click="handleReset">重置</el-button> </el-form-item> </el-form> <!-- 用户表格 --> <el-table :data="tableData" border stripe v-loading="loading"> <el-table-column prop="id" label="ID" width="80" /> <el-table-column prop="name" label="名称" min-width="120" /> <el-table-column prop="status" label="状态" width="100"> <template #default="{ row }"> <el-tag :type="row.status === 1 ? 'success' : 'danger'"> {{ row.status === 1 ? '启用' : '禁用' }} </el-tag> </template> </el-table-column> <el-table-column prop="createTime" label="创建时间" min-width="160" /> </el-table> <!-- 分页组件 --> <el-pagination v-model:current-page="queryForm.pageNum" v-model:page-size="queryForm.pageSize" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next" @change="fetchList" /> </div> </template> <script setup> import { ref, reactive, onMounted } from 'vue' import { getUserList } from '@/api/user' const loading = ref(false) const tableData = ref([]) const total = ref(0) const queryForm = reactive({ name: '', status: '', pageNum: 1, // 当前页,从 1 开始 pageSize: 10 // 每页条数 }) async function fetchList() { loading.value = true try { const res = await getUserList({ ...queryForm }) tableData.value = res.data.list total.value = res.data.total } finally { loading.value = false } } function handleSearch() { queryForm.pageNum = 1 // 重置到第一页,避免搜索结果停在旧页码 fetchList() } function handleReset() { queryForm.name = '' queryForm.status = '' queryForm.pageNum = 1 fetchList() } onMounted(fetchList) </script>这段代码的关键逻辑有三处:第一,getUserList({ ...queryForm })把展开后的查询参数传给 API 层,API 层再把它们原样交给 mock 接口;第二,queryForm.pageNum在搜索和重置时强制回到 1,这是分页查询最常见的细节,不重置的话,你在第 5 页搜索“张三”,接口返回空列表,页面看起来就像坏了;第三,el-pagination的v-model:current-page和v-model:page-size是双向绑定,页码变化后@change事件会自动触发fetchList,不需要手动监听页码。
3.3 Element-Plus 必调的三个参数:空数据文案、表格高度与表单校验时机
用过一段时间 Element-Plus 的人,基本都会固定在组件上做三处微调。第一处是表格的空数据状态,默认的英文 “No Data” 换成中文提示,否则演示时外行看着尴尬。使用el-table的empty-text属性,设置成暂无数据;如果希望空状态更友好,可以用#empty插槽替换成一张插画或一段引导文案。
第二处是表格高度,后台列表页数据一多,页面整体滚动体验很差。建议给el-table设置height属性,比如calc(100vh - 220px),让表格主体内部滚动,表头固定,分页始终贴着底部。这个值要配合搜索表单和分页的高度微调,不同页面的差值是 20 到 30 像素。
第三处是表单校验时机。el-form的rules默认在提交时统一校验,但更好的体验是“输入框失焦就校验当前字段”。通过el-form的validate-on-rule-change属性(默认 true)结合每个表单项的prop值,可以精确控制字段级别的校验时机。我一般会把status为空的提示语写成“请选择状态”,而不是默认的 “Please select”,对接中文团队时少一点翻译歧义。
4. mockjs 假数据挂上路由:让表格、表单和分页先跑起来
mockjs 的定位是“生成假数据 + 拦截请求”,它不是简单的静态 JSON,而是带随机规则的数据模板。这一章解决三个问题:mock 层怎么在 Vite 工程里正确注册、数据模板怎么写才能贴近真数据、列表页的搜索分页闭环怎么打通。
4.1 mockjs 在 Vite 工程里的正确接入方式
mockjs 本身不区分框架,它拦截的是浏览器里的 XHR 请求。在 Vite 工程里接入,最常见的方式是在main.js里import './mock',让 mock 入口在应用初始化之前完成注册。一个规范的 mock 入口文件长这样:
// src/mock/index.js import Mock from 'mockjs' // 先关闭 mockjs 的日志,避免控制台被刷屏 Mock.config({ timeout: 200 }) // 注册用户模块的假接口 import './user' // 在开发环境下打印一行提示,确认 mock 已生效 console.log('[mock] 假数据已启动,当前拦截所有 /api 请求')这里的Mock.config({ timeout: 200 })控制响应延迟时间,单位是毫秒。200 毫秒比较接近真实接口的体感,既能看到 loading 状态,又不至于等得着急;如果要做弱网模拟,可以调到 800 到 1500。import './user'会把用户模块的接口定义拉进来,每个模块负责各自领域的数据模板。
有一个重要的接入前提:mockjs 拦截的是 XHR,如果你的项目里用 fetch 发请求,mockjs 默认拦不到。这套 demo 预配的是 axios,所以没问题;你自己在正式项目里接 mock 时,要确认请求库是基于 XHR 的,否则 mock 不生效。
4.2 写一份带随机规则的假数据模板
mockjs 的核心语法是数据模板,它用'字段|规则': 值的形式描述生成规则。以下是一份用户列表接口的定义,覆盖了自增 id、随机名称、随机状态和日期格式:
// src/mock/user.js import Mock from 'mockjs' const { Random } = Mock // 生成 20 条用户假数据 const generateUserList = () => { return Mock.mock({ 'list|20': [ { 'id|+1': 1, // id 自增,从 1 开始 name: Random.cname(), // 随机中文名 'age|18-60': 1, // 18 到 60 之间的整数 'status|1': ['启用', '禁用'], // 从数组里随机取一个 'email': Random.email(), // 随机邮箱 'createTime': Random.datetime('yyyy-MM-dd HH:mm:ss') } ] }).list } // 拦截 GET 请求 /api/user/list Mock.mock('/api/user/list', 'get', (options) => { // options.url 是请求地址 // options.type 是请求方法 // options.body 是请求体(POST 时才有值) const params = new URLSearchParams(options.url.split('?')[1] || '') const pageNum = Number(params.get('pageNum')) || 1 const pageSize = Number(params.get('pageSize')) || 10 const allList = generateUserList() const start = (pageNum - 1) * pageSize const end = start + pageSize const pageList = allList.slice(start, end) return { code: 200, message: 'success', data: { total: allList.length, list: pageList } } })这段代码里的三个核心规则值得展开:'id|+1': 1表示每次生成 id 在上一次基础上加 1,适合表格主键展示;'status|1': ['启用', '禁用']表示每次从数组中随机取一个元素,适合做枚举字段的随机;Random.datetime('yyyy-MM-dd HH:mm:ss')是占位符方法,生成指定格式的随机时间。规则写在|前后,前面是字段名,后面是生成策略。
注意这个接口实现里没有做搜索字段的过滤,name和status的搜索需要自己按参数过滤。一个常见做法是先用Array.prototype.filter过滤name包含关键字、status相等的记录,再做分页切片。过滤逻辑放在 mock 层写一遍,真实接口的过滤规则由后端实现,前端拿到 mock 时的字段语义不变。
4.3 让列表页真正“活”起来:搜索、筛选与分页的完整闭环
假数据接口就绪后,API 层要做的是一层非常薄的封装,把页面传过来的查询参数原样拼到请求里。注意,axios 的 GET 请求参数会被转成 query string,mock 端收到后要用URLSearchParams解析,才能兼容搜索和分页。
// src/api/user.js import request from '@/utils/request' // 获取用户列表 export function getUserList(params) { return request({ url: '/api/user/list', method: 'get', params }) } // 删除用户(mock 端还没实现也可以先占位) export function deleteUser(id) { return request({ url: `/api/user/${id}`, method: 'delete' }) }页面上的handleSearch把queryForm里的关键字、状态、页码、条数一次传进去,mock 端解析pageNum、pageSize做分页,按name做模糊匹配,按status做精确匹配,最后返回当前页的list和总条数total。这样一个列表页的搜索、筛选、分页就全部跑通了:点查询时从第一页开始展示搜索结果,切页码时拿到对应页的数据,重置时回到全量列表的第一页。
这一整套链路里最不值得做的事,是让页面组件直接调用Mock.mock生成的静态数组——那等于把假数据写死在 vue 文件里,切真实接口时无从下手。保持“页面 → api 层 → mock 层”的三级结构,后续切换真实接口时,只需要在 api 层改baseURL,页面和 mock 层都不动。
5. 排查与避坑:mock 不生效、样式丢失、数据复位、分页错位
demo 环境本身是预配好的,但只要你动了它的代码,就会碰到一些“看着没改坏,突然就不对了”的场景。这些坑我用下来几乎全遇过,每条都是“现象 → 原因 → 解决”的固定套路。
5.1 mock 不生效:请求直接打到真实后端
现象是页面表格一直转圈,或者 Network 面板里能看到真实后端的 404 报错。原因通常是三选一:第一,main.js里压根没有import './mock'这行;第二,mock 的引入顺序晚于 axios 的请求发出时机;第三,项目里用了 fetch 而 mockjs 只拦截 XHR。
解决方法是按顺序排查:先看 Console 里有没有[mock] 假数据已启动的提示,没有就先加引入;再检查main.js顶部有没有这行代码,mock 一定要在createApp之前加载;最后确认项目里的请求库是 axios 而不是 fetch。还有一种隐蔽的情况:vite.config.js 里的 proxy 代理把/api前缀直接转发到了后端服务器,mock 拦截到的响应被代理覆盖了。解决办法是把 mock 的接口前缀改成/mock-api,与代理前缀错开,或者关掉 proxy 配置。
5.2 ElMessage 弹窗没有样式:按需引入的经典后遗症
现象是功能正常,但ElMessage、ElMessageBox弹出来是裸文本,没有边框背景。原因是在按需引入模式下,函数式调用的组件不会出现在模板里,unplugin-vue-components无法识别它们,对应的样式文件也不会被加载。
解决方法是手动补样式,常见做法是在main.js里显式引入这两个组件的样式文件,或者直接引入全量 Element-Plus 的 CSS 兜底。
// 按需引入模式下补全函数式组件样式 import 'element-plus/es/components/message/style/css' import 'element-plus/es/components/message-box/style/css'这套 demo 默认是全量引入,不会踩这个坑;但如果你为了减小体积改成按需引入,这两行别删。另外,项目里如果多个开发者协作,建议在代码注释里写清楚这一点,否则后来的人会在样式丢失的问题上反复折腾。
5.3 刷新页面数据“复原”了:mock 数据不是持久化存储
现象是你把一个用户的状态从“启用”改成“禁用”,切了个页面再回来,数据又变回原样。原因很简单:mockjs 的假数据是运行时生成的,每一轮页面刷新都会重新生成,不存在数据库持久化。
解决方式分两种情况。如果只是演示交互效果,接受这个设定就行,刷新复位是 mock 阶段可以容忍的。如果你需要模拟“编辑后留住数据”的效果,可以把变更结果写入 localStorage,刷新时优先读本地存储,读取不到再走 mock 接口生成。这个方案在后面的进阶章节里会展开写完整了。
原因落在哪:mock 层没有 memory 存储,Mock.set 只能改运行时数据,管不到下一次刷新。5.4 分页永远只出第一页数据:页码参数名不匹配
现象是表格能显示第一页数据,但点了第 2 页,数据没有变化;或者点第 2 页后表格直接空了。原因通常是 Element-Plus 的el-pagination默认把当前页绑定到current-page,而 mock 端解析的参数名是pageNum;页面里如果只绑定了v-model:current-page却没有在请求参数里带上pageNum,后端拿不到页码,自然一直返回第一页。
解决方法是统一参数名。最常见的做法是在queryForm里直接定义pageNum和pageSize,再通过el-pagination的v-model:current-page绑定到pageNum。这样 UI 层和请求参数层就保持了一致。
<el-pagination v-model:current-page="queryForm.pageNum" v-model:page-size="queryForm.pageSize" :total="total" layout="total, prev, pager, next" @change="fetchList" />注意@change事件只在页码或每页条数变化时触发,它同时覆盖了两种变化,不需要再分别监听current-change和size-change。如果你用的 Element-Plus 版本较旧,@change不可用,就退回去分开监听那两个事件。
5.5 代理和 mock 抢同一个请求前缀:404 来回跳
现象是本地 mock 明明注册了/api/user/list,但请求发出去后返回的是真实后端的 404,或者一会儿走 mock 一会儿走代理,表现不稳定。原因是在vite.config.js里配置了server.proxy,把/api前缀的请求全部转发到了测试环境地址,而 mockjs 也拦截/api前缀,两者产生竞争。
解决方式是让两者分工,不让它们抢路由。我习惯的做法是 mock 的接口前缀统一用/mock-api,代理转发保持/api;这样开发早期所有请求走 mock,联调时通过环境变量切换 baseURL,把/mock-api替换成/api,代理和 mock 互不干扰。
// vite.config.js 中代理与 mock 前缀错开,避免竞争 server: { proxy: { '/api': { target: 'http://localhost:8080', // 真实后端地址(示例占位) changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }这里的rewrite是把/api前缀剥掉再转发,常见后端接口路径不带/api。前端请求地址写成${import.meta.env.VITE_API_BASE_URL}/user/list,开发模式兜底为/mock-api,生产模式用.env文件里的变量指向/api。这样的配置逻辑,把“mock 阶段”和“联调阶段”的切换变成一次环境变量修改,而不是全局手改请求地址。
6. 更接近真实联调:延迟模拟、数据持久化与环境变量切换
mock 假数据做到能跑只是及格线,要让这套 demo 真正承担“原型演示给业务看、接口契约给后端看”的职责,需要再加三样东西:响应延迟、编辑持久化和接口开关。
第一样是全局响应延迟。Mock.config({ timeout: 200 })是统一延迟,只对 mock 层生效。如果你希望个别接口慢一点、观察 loading 效果,可以在某个接口的返回里包一层setTimeout——但这会让 mock 与真实接口的差异变大,我通常只用全局配置。演示给业务方看的时候,把 timeout 调到 500 毫秒左右,loading 动画出现得恰到好处,既不显得卡,也能证明 loading 状态存在。
第二样是编辑持久化。前面提到刷新数据复位的问题,如果你需要演示“修改后保存成功,刷新依然生效”,可以在 mock 层里加一层 localStorage 读写逻辑,把增删改的结果存下来,而不是每次刷新重新生成随机数据。
// src/mock/user.js 中做 localStorage 持久化的思路 const STORAGE_KEY = 'mock_user_list' function readDb() { const raw = localStorage.getItem(STORAGE_KEY) return raw ? JSON.parse(raw) : generateUserList() } function writeDb(list) { localStorage.setItem(STORAGE_KEY, JSON.stringify(list)) }思路核心是:首次访问用generateUserList()生成初始数据并写入 localStorage,之后的请求优先读本地存储,编辑、删除操作在内存里完成同步修改后再写回。注意,localStorage 有大小限制,数据量超过几千条时会报 QuotaExceededError,mock 数据别造太多,20 到 50 条足够演示。
第三样是环境变量切换接口。我一般会在项目根目录放两个文件:.env.development和.env.production,分别配置VITE_API_BASE_URL。开发环境默认/mock-api指向 mock 层,构建或联调时改成/api指向真实后端。切换只动环境变量文件,api 层的 request 封装读这一个变量,页面组件完全无感。如果后端接口路径里带版本号或模块前缀,只需要在变量值里补齐。
# .env.development VITE_API_BASE_URL=/mock-api# .env.production VITE_API_BASE_URL=/api这套组合用下来,真实验收时最省心。记得我还在模拟项目X里的时候,把 mock 和代理配在同一个前缀下面,演示到一半数据乱了,整场汇报尴尬收场。从那以后我养成了一个习惯:不管项目多小,mock 接口前缀永远独立,真实接口切换永远走环境变量,宁可多一步配置也不把两者揉在一起。这套 Vue3 + Element-Plus + mockjs 的 demo 环境,只要能稳定跑完这三步,你在它基础上做任何页面都心里有底,新手照着加页面不会改坏,熟手切真实接口也不会手忙脚乱。希望帮到你。
本文还有配套的精品资源,点击获取