
简介这是基于 Vue3 框架与 Element-Plus 组件库构建的前端示例工程同时集成 Mockjs 与 axios 工具适合想掌握 Vue3 新语法、了解 Element-Plus 引入方式和 Mock 数据模拟思路的开发者快速上手与二次开发。工程已成功创建出基于 Element-Plus table 组件的功能页面Vue3 组合式 API 与依赖配置均已就绪目录结构条理清晰能够在此基础上继续搭建新页面显著降低环境配置成本。资源包共 27 个文件核心包括 9 个 Vue 页面与组件、3 个 JavaScript 脚本、3 个 JSON 配置、3 个 Markdown 说明文档并辅以 CSS、图片、图标、SVG、HTML 入口等静态资源压缩后整体仅 130KB体积轻量、便于下载与迁移。Mockjs 的假数据请求流程和 axios 的接入封装都已包含其中可快速验证表格数据交互与接口返回逻辑。目前已有 2140 人学习或下载适合需要快速上手 Vue3 工程搭建、Element-Plus 组件使用及 Mock 数据联调的开发者参考。1. vue3-demo 是给谁的环境配好了缺的只是业务做后台管理系统时最烦的不是写页面而是搭环境。装 Node 依赖、引入 UI 库、配置路由、再为接口造假数据……一套流程下来小半天就没了新同事进组光是让项目跑起来就得折腾一晚上。vue3-demo 这个东西说白了就是把 Vue3 框架、Element-Plus 库和 mockjs 假数据提前集成好环境已经配好了拉下来就能在浏览器里看到能点、能查、能翻页的页面。它不是教学玩具而是给马上要写业务的人用的起跑线想验证表格交互、想和后端并行开发、想学这三个东西怎么配合都能直接上手。我拆过几个类似的 demo真正值钱的不是组件多炫而是 mock 层和 UI 层已经打通你能把精力全放在自己的需求上。2. 把环境跑起来命令、目录结构与三分钟验证“环境已经配好”这句话最容易让人误读。它不是说后端接口都准备好了而是说前端这一侧的运行环境、依赖声明、样式入口、mock 拦截器都已经摆好你只需要启动。拿到 vue3-demo 之后第一件事不是看代码而是确认它能不能在你机器上跑起来。2.1 启动前要确认的三个条件一个完整的 Vite Vue3 工程对运行环境有三个隐藏要求Node 版本不能太老、包管理器要统一、依赖装得干净。在终端里先看一眼版本能避免后面一堆莫名其妙的问题。node -v npm -v # 如果项目用了 pnpm就单独确认 pnpm -vNode 版本决定 Vite 能不能正常启动一般建议使用长期支持版本。vue3-demo 这类项目通常不要求你手动装全局东西依赖全部写在一个 package.json 里npm install 一步到位。常见做法是仓库里不包含 node_modules所以拿到手先安装依赖再启动开发服务器。cd vue3-demo npm install npm run dev第一次安装依赖时如果网络很慢或者卡在某个包上常见做法是先把镜像源切换成国内镜像再删掉 node_modules 和 package-lock.json 重装。npm install 之后的等待时间不是 bug很多包要从远端拉取耐心等。启动成功后终端会输出本地地址一般是 localhost:3000 或 localhost:5173取决于 Vite 配置。2.2 源码目录每一层都在干什么跑通环境后我建议先把目录结构过一遍。vue3-demo 的目录结构通常长这样vue3-demo ├── index.html ├── package.json ├── vite.config.js ├── src │ ├── main.js │ ├── App.vue │ ├── api │ │ └── user.js │ ├── mock │ │ ├── index.js │ │ └── modules │ │ └── user.js │ ├── router │ │ └── index.js │ ├── store │ │ └── index.js │ ├── views │ │ ├── Login.vue │ │ └── Dashboard.vue │ └── styles │ └── index.scssmock 目录是 vue3-demo 的核心价值点。main.js 里一旦 import 了 mock/index.jsmockjs 就会在运行时替换浏览器原生的 XHR 对象之后所有匹配规则的请求都会被它接管压根碰不到真实后端。api 和 mock 是两套独立的东西api 是前端调用接口的入口mock 是接口的替身。换到真实接口时你只需要改 api 层或者环境变量页面代码几乎不用变。2.3 三分钟验证环境是否真的通了我不建议一上来就改代码先用默认页面验证一条完整链路启动项目、打开页面、调用一个 mock 接口、看到返回数据。这个过程能暴露大多数环境问题比如端口冲突、依赖缺失、mock 注册失败。npm run dev打开浏览器进入登录页随便输入一个账号密码能进到列表页说明路由和 Element-Plus 组件渲染正常。然后打开开发者工具的 Network 面板刷新列表页找到以 /api/user/list 开头的请求。如果 Response 里返回了 code 为 200 的 JSON 数据说明 mock 拦截也正常。这一步不要跳过很多人等到写业务时才发现 mock 根本没生效到时候已经改了一堆代码成本高得多。目录里如果有多份环境变量文件比如 .env.development 和 .env.production留意一下里面的 VITE_USE_MOCK 之类的字段它决定要不要注册 mock。这个开关是环境配置里最容易忽略但最有用的参数后文会单独说。3. 用 Element-Plus 搭页面从按钮到表格的常见姿势vue3-demo 把 Element-Plus 集成好了但“能跑”和“会用”是两码事。很多初学者直接复制官网示例结果发现数组改了表格不刷新、表单校验不生效。这里先把集成方式和页面写法理清楚。3.1 在 main.js 里把 Element-Plus 挂上Element-Plus 是 Vue3 的组件库最基础的接入方式是全量引入。main.js 里通常是三段式创建应用、注册插件、挂载节点。import { createApp } from vue import ElementPlus from element-plus import element-plus/dist/index.css import zhCn from element-plus/es/locale/lang/zh-cn import App from ./App.vue import router from ./router const app createApp(App) app.use(router) app.use(ElementPlus, { locale: zhCn, size: default }) app.mount(#app)这段代码里有两处值得说。第一个是 locale: zhCnElement-Plus 默认文案是英文像分页器的“Total”和日期选择器的月份不配中文的话会很别扭。第二个是 size: default它统一控制组件尺寸后续想全局改成小尺寸只改这一处就行。如果项目已经配置了按需引入这段代码会不一样但 vue3-demo 一般会选择全量引入因为省心demo 阶段不需要考虑打包体积。3.2 用组合式 API 写一个列表页Vue3 里现在主流写法是 script setup 配合 ref 和 reactive。列表页是后台系统最常见的页面我习惯把它拆成四块搜索区、表格区、分页区、数据加载函数。下面这段代码可以直接替换掉 vue3-demo 里的空白页面跑起来。template el-card el-form inline el-form-item label关键字 el-input v-modelquery.keyword placeholder输入姓名 clearable / /el-form-item el-button typeprimary clickhandleSearch查询/el-button /el-form el-table :datalist v-loadingloading border el-table-column propid labelID width80 / el-table-column propname label姓名 / el-table-column propemail label邮箱 / el-table-column propcreateTime label创建时间 / /el-table el-pagination v-model:current-pagequery.page v-model:page-sizequery.pageSize :totaltotal :page-sizes[10, 20, 50] layouttotal, sizes, prev, pager, next current-changeloadData size-changehandleSizeChange / /el-card /template script setup import { ref, reactive, onMounted } from vue import { getUserList } from /api/user const loading ref(false) const list ref([]) const total ref(0) const query reactive({ keyword: , page: 1, pageSize: 10 }) async function loadData() { loading.value true try { const res await getUserList(query) list.value res.data.rows total.value res.data.total } finally { loading.value false } } function handleSearch() { query.page 1 loadData() } function handleSizeChange() { query.page 1 loadData() } onMounted(loadData) /script这里 ref 和 reactive 是有明确分工的列表和 loading 属于“单个值或需要整体替换”的数据用 ref查询条件属于同一个对象里的多个字段用 reactive 更顺手。el-pagination 的 v-model:current-page 和 v-model:page-size 是 Element-Plus 比较新的写法比手动监听事件再改值要少一步。注意切页时 page 会变成 2 或 3但切 pageSize 时应该把 page 重置回 1否则容易出现“第 5 页但每页 20 条”这种越界空数据。3.3 表单校验rules 和自定义校验的边界后台系统表单场景逃不掉Element-Plus 的 el-form 自带校验逻辑配合 rules 使用。vue3-demo 里登录页一般就是这种结构。一个典型的用户表单校验长这样template el-form refformRef :modelform :rulesrules label-width80px el-form-item label姓名 propname el-input v-modelform.name / /el-form-item el-form-item label年龄 propage el-input v-model.numberform.age / /el-form-item el-button typeprimary clicksubmitForm提交/el-button /el-form /template script setup import { ref, reactive } from vue import { ElMessage } from element-plus const formRef ref() const form reactive({ name: , age: 0 }) const validateAge (rule, value, callback) { if (value 18 || value 60) { callback(new Error(年龄需要在 18 到 60 之间)) } else { callback() } } const rules { name: [{ required: true, message: 请输入姓名, trigger: blur }], age: [{ validator: validateAge, trigger: blur }] } async function submitForm() { await formRef.value.validate() ElMessage.success(校验通过) } /script这里最重要的一点是 el-form-item 上的 prop 必须和 rules 里的 key 对应否则校验不触发。自定义校验函数接收三个参数rule、value、callback。校验失败调用 callback 时传入 Error 对象失败原因会显示在表单项下面。还有一个小坑年龄输入框如果用 v-model 而不是 v-model.number拿到的是字符串比较时会得到“18” 18 的结果所以数值场景要记得加 .number 修饰符。Element-Plus 的组件原子化做得不错但它的坑往往藏在这些交互细节里。用法熟悉了以后你会发现把 search、table、pagination 三件套拼成一个通用列表组件后续每个页面都能省一半时间。4. mockjs 让后端“提前下班”接口与假数据设计vue3-demo 和其他后台模板最大的区别就是集成了 mockjs。没有后端前端也能联调页面这是 mockjs 存在的意义。理解它的拦截原理后你就能自己设计假数据而不是停留在“照着项目里已有的抄”的水平。4.1 mockjs 的拦截原理与数据模板语法mockjs 不是一个 HTTP 服务器它做的是在浏览器里替换 XMLHttpRequest 对象。当浏览器发起的请求路径匹配到 Mock.mock 注册的规则时请求不会真正离开浏览器而是直接由 mockjs 生成数据并回调。所以在 Network 面板里你能看到这个请求但它的发起端和返回端都在前端。mockjs 的数据模板语法是它的灵魂。常见的写法是名字|规则Mock.mock({ list|5-10: [{ name: cname, age|18-60: 1, email: EMAIL }] })list|5-10表示数组长度随机在 5 到 10 之间age|18-60: 1表示生成 18 到 60 之间的整数cname是内置的随机中文姓名EMAIL是随机邮箱。这些占位符是 mockjs 官方定义的随机函数比自己去拼造数据靠谱得多。写模板时注意力要集中在数据结构和字段类型上mock 数据的取值范围反而不重要。4.2 设计一个支持分页和关键词过滤的列表接口vue3-demo 里的 mock 模块我一般拆成一个入口和 n 个业务模块每个接口一个函数互不干扰。用户列表接口是后台系统的标配下面这段代码可以直接放在 mock/modules/user.js 里。import Mock from mockjs const Random Mock.Random export default function (Mock) { Mock.mock(/\/api\/user\/list/, get, (options) { const params new URLSearchParams(options.url.split(?)[1]) const page Number(params.get(page) || 1) const pageSize Number(params.get(pageSize) || 10) const keyword params.get(keyword) || const allRows Array.from({ length: 67 }, (_, i) { return { id: i 1, name: Random.cname(), email: Random.email(), createTime: Random.datetime(yyyy-MM-dd HH:mm:ss) } }) const filtered keyword ? allRows.filter(item item.name.includes(keyword)) : allRows const start (page - 1) * pageSize const rows filtered.slice(start, start pageSize) return { code: 200, message: success, data: { rows, total: filtered.length } } }) }这段代码有三个设计点值得说明。第一个是 Mock.mock 的第一个参数用了正则而不是字符串。如果请求路径里带了 ?page1pageSize10字符串 /api/user/list 匹配不上而正则 //api/user/list/ 可以忽略 query 部分这是接入 axios 后最常见的 mock 失效原因。第二个是拦截回调里手动解析 URL 参数因为 mock 的模板语法本身不好处理动态参数。第三个是返回结构固定成 { code, message, data }这相当于一份前后端契约后面换真实接口时页面上不用改任何东西。4.3 从 mock 接口到页面调用的完整链路mock 模块注册完之后页面不能直接依赖 Mock 对象而是通过 api 层的 axios 封装去请求。vue3-demo 里通常有一个 request 工具我把最小可行的版本写出来import axios from axios const request axios.create({ baseURL: , timeout: 5000 }) request.interceptors.response.use( (response) { const res response.data if (res.code ! 200) { return Promise.reject(new Error(res.message || 请求失败)) } return res }, (error) Promise.reject(error) ) export default request在 api/user.js 里暴露业务方法import request from /utils/request export function getUserList(params) { return request.get(/api/user/list, { params }) }这里的 baseURL 留空是因为 mockjs 拦截的是页面最终请求的完整地址如果 baseURL 写成 /api那 request.get(/user/list) 也会拼成 /api/user/list。两种写法都能通但 demo 里统一用空 baseURL 加全路径逻辑更清楚。把 axios 拦截器里的 res.code 判断留着等后面接真实接口时只要后端 Code 定义不同你只需要改这一处判断。axios 请求发出时mockjs 的拦截回调会接管并返回数据这个流程对页面来说是透明的。你可以把 mock 模块当成一个内存里的后端数据都是临时生成的每次刷新页面都会变化。如果想要固定一批数据方便反复调试可以去掉 Random 函数直接在 allRows 里写死几行真实值。5. 避坑清单mock 失效、样式丢失与生产残留vue3-demo 把路铺好了但路边的坑也不少。我在几个模拟项目里都踩过同样的雷这里挑四个最常见的按照“现象、原因、解决”的方式梳理一遍能帮你少走很多弯路。5.1 mock 接口一直 pending最后超时现象页面表格一直转圈Network 面板里 /api/user/list 请求状态是 pending过一会儿提示超时。原因通常是两个情况叠加。一是 Mock.mock 注册时用了字符串路径比如 /api/user/list但 axios 请求带了 query变成了 /api/user/list?page1pageSize10字符串匹配不上二是 Mock.setup 的 timeout 配得太大看起来就像卡死了一样。解决把注册路径改成正则表达式像上一章那样写成/\/api\/user\/list/。Mock.setup 的 timeout 控制在 200 到 600 毫秒之间太短没真实感太长会让人误以为接口挂了。另外vue3-demo 的 main.js 里注册 mock 的时机要在所有业务代码执行之前如果写在异步回调里页面首屏请求可能已经发出去了自然拦截不到。5.2 Element-Plus 按需引入后样式丢了一半现象按钮和输入框有样式但表格没有边框、下拉框弹层位置错乱甚至图标加载不出来。原因按需引入组件是通过 unplugin-vue-components 在编译时自动导入的它默认只处理组件 JS不处理样式。如果你只配了 Components 插件没配 ElementPlusResolver那组件的样式就不会跟着进来或者你手动引了部分样式但漏了表这类弹层组件的样式。解决最快的方式是先退回全量引入把样式问题排除掉。如果执意要按需引入vite.config.js 里要这样配import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers export default defineConfig({ plugins: [ Components({ resolvers: [ElementPlusResolver()] }) ] })ElementPlusResolver 会自动帮你加载每个组件对应的样式。注意跑完配置后必须重启 dev server这类编译插件不会热更新配置项。vue3-demo 一般默认全量引入体检会稍大但胜在稳定新手先别折腾按需引入的事。5.3 生产构建把 mock 数据打进去了现象前端打包上线后接口请求全部返回假数据页面拿不到真实后端数据而且 Network 面板里看不到请求发出到真实服务器。原因main.js 里无条件执行了import ./mockVite 在 build 时不会根据环境自动剔除这段代码mock 模块里的拦截逻辑就跟着进了生产包。这是最危险的一类错误因为它不会崩溃只会让整个线上页面变成空壳。解决用环境变量或者 import.meta.env.DEV 做条件判断把 mock 注册限制在开发环境。推荐在 main.js 里写成if (import.meta.env.DEV import.meta.env.VITE_USE_MOCK ! false) { import(./mock) }同时检查 .env.production 里不要设置 VITE_USE_MOCKtrue。我一般还会在 mock/index.js 顶部加一行console.log([mock] enabled)打包后搜一下终端日志有没有这个输出一眼就能确认 mock 是否残留。5.4 改了 mock 数据页面上却还是旧数据现象改完 mock/modules/user.js 里的字段刷新页面后表格还是老结构必须重启 npm run dev 才生效。原因Vite 对部分依赖有缓存机制mockjs 被预构建后存在 node_modules/.vite 目录下改动源码文件时缓存没有及时失效。浏览器层面也可能直接缓存了 GET 请求的响应。解决第一选择是重启 dev server这一步能解决八成问题。第二选择是在 vite.config.js 里把 mockjs 加到 optimizeDeps.exclude让它不参与预构建这样每次改动都会被当作源码处理。如果改的是返回数据而不是模板结构还可以在浏览器开发者工具的 Network 面板里勾选 Disable cache再硬刷新页面。避坑的核心思路其实就一句话mock 是开发辅助工具不是业务逻辑的一部分它必须被隔离在开发环境里。凡是涉及“为什么生产环境也出现了假数据”的诡异问题大半都是 mocking 开关没控制好。6. 从 demo 到工程把假数据换成真接口的改造链vue3-demo 帮我们把坑填平了但 demo 的价值在于被拆掉。我自己拿到这类项目后会先做三件事把 mock 做成可开关的独立模块把 axios 的基础路径抽到环境变量里最后让页面只面向一份数据结构。这三件事做完从 demo 到工程就只差会议室里对接口了。第一件是把 mock 开关交给环境变量。在项目根目录建两个文件.env.development 里写VITE_USE_MOCKtrue.env.production 里写VITE_USE_MOCKfalse。然后在 main.js 里用import.meta.env.VITE_USE_MOCK条件注册 mock。这样开发时假数据照常跑打包时 mock 自然消失不用靠人肉记着删代码。第二件是统一定义接口返回结构。mock 接口返回的每一层字段都有意义真实后端对接时如果返回结构不一致页面就得改很多处。常见做法是统一成 code、message、data 三层data 里放业务数据。收到真实接口文档后先比较它和 mock 的结构差异差异大就让后端调整差异小就改 axios 拦截器把后端的返回包成同一层结构。这样页面代码一行都不用动。第三件是我一直保留的习惯demo 到手先不写业务花十分钟跑一遍环境看 mock 请求有没有被正确拦截Element-Plus 的表格能不能正常渲染然后把这些操作写进团队的新人上手文档。因为大部分问题都出在环境认知不一致上比如有人直接跳过了 mock 验证最后把时间全浪费在排查一个根本不存在的后端问题上。vue3-demo 给了你一个不用从零开始的机会但它不会替你决定接口数据长什么样、表格列怎么设计。真正让环境变成生产力的是你对 mock、UI 库和页面三者边界的理解。每次要接新页面时我都习惯先问一句这个请求现在应该走 mock 还是真实接口如果答案是 mock那就让页面数据保持干净别让假数据逻辑混进业务代码里。这个习惯帮我避免过很多次上线前的临时救火希望帮到你。本文还有配套的精品资源点击获取