Vue + ElementUI后台管理系统源码设计:从权限到二次开发的完整实践

Vue + ElementUI后台管理系统源码设计:从权限到二次开发的完整实践 简介这套基于Vue和ElementUI的后台管理系统源码适合前端学习者、初中级Vue工程师以及需要快速搭建管理后台的开发者参考重点展示了中后台常见业务模块的工程化实现方式。压缩包共92个文件涵盖23个JavaScript脚本、22个Vue组件、20张PNG图片以及CSS样式、HTML页面、字体文件和源码映射等辅助内容整体约10.27MB目录按工程化惯例拆分为api、utils、store、router、views、components等层次便于对照学习环境配置、构建脚本与开发变量文件也一并提供适合从零还原工程。项目已经完成用户管理、菜单管理、角色管理、公司管理、权限管理和支付配置等核心功能并包含登录、商品管理、交易订单、图表页面等界面素材涉及axios请求封装、Vuex状态管理、路由配置、组件复用等常见实践。目前已有1280人学习下载既可作为课程设计或毕业设计的参考源码也能在此基础上进行二次开发与功能扩展。 后台管理系统大概是前端领域里最不缺需求、也最不缺模板的一类项目。前阵子我整理了一套基于Vue和ElementUI的后台管理系统设计源码有个朋友问了我一句市面上现成模板那么多直接改一改就能用为什么还要自己从头设计一套我当时给他说了一句话——你不是在写一个后台你是在给后面半年的自己减少加班。如果这套源码的目录结构、权限设计、路由管理、组件封装是乱的那每接一个需求就多踩一次坑。这篇博客我不聊大而全的框架理论就说说我实际设计这套Vue ElementUI后台管理系统源码时的思路、落地的核心功能以及那些不跑一遍源码根本发现不了的问题。适合正在做后台管理项目、打算自己搭一套可复用模板的开发者参考。1. 为什么后台管理系统选 Vue ElementUI 而不是其他组合1.1 这个组合解决的真正问题很多人选技术栈的时候习惯性先看热度。Vue在国内开发者里的普及程度确实高ElementUI又几乎是后台管理系统的“标配”但这套组合真正解决的问题不是“流行”而是开发效率与可维护性的平衡。后台管理系统和C端产品是两种完全不同的东西。C端产品要追求极致的首屏性能、交互创新和动效体验而后台管理系统90%的页面就是表格、表单、弹窗、树形结构、数据统计卡片。这类页面的特点是重复度高、业务逻辑重、对美观要求不是第一位但对开发速度要求极高。一个需求下来界面长得和上个模块差不多逻辑却完全不一样这时候组件库的丰富程度直接决定你加班到几点。ElementUI以及它在Vue3里的继任者Element Plus把后台最常用的控件都做好了表格的排序、筛选、分页表单的校验、级联、日期选择布局的栅格系统反馈的弹窗和消息提示。你不需要从零写样式和交互只需要把精力花在业务逻辑上。配合Vue的响应式数据绑定和组件化能力一份源码拆成几十个组件每个组件管一块业务维护起来非常清晰。1.2 Vue2 配 ElementUI 还是 Vue3 配 Element Plus这是我在设计源码时第一个要做的决定。网上搜“后台管理系统模板”的时候Vue2历史的存量项目非常多很多人还在看老项目而新项目已经全面转向Vue3了。我的选择建议这样考虑如果你的需求是维护老系统、公司存量代码全是Vue2那就老老实实用Vue2 ElementUI不要强行升级稳定压倒一切。如果你是从零开始设计一套自己的源码模板或者公司新项目启动直接上Vue3 Element Plus Vite这是目前最顺手的组合。具体到源码设计里Vue3和Vue2的差距不仅仅是语法层面。组合式APIComposition API让同一块业务逻辑可以聚在一起写不用像选项式API那样散落在data、methods、computed、watch里。路由方面Vue Router 4的createRouter、createWebHistory写起来更现代状态管理用Pinia比Vuex省掉了一大笔样板代码。Element Plus在组件API上也做了改良比如el-dialog的v-model就比Vue2时代的visible更符合直觉。1.3 它的边界在哪里任何技术选型都有边界这套组合也不例外。后台管理系统如果遇到特别复杂的自定义可视化大屏、大量拖拽编排的图形化配置页面纯靠ElementUI是撑不起来的得配合ECharts、AntV这类可视化和拖拽库。另外如果你的项目对首屏加载、打包体积极度敏感后台管理系统这种一个页面塞几十个组件的场景必须配合路由懒加载、按需引入组件库来优化。我在源码里默认就开了路由懒加载和ElementUI组件的按需导入因为后台管理系统随着业务扩展页面数量增长非常快。你不做懒加载的话首屏白屏时间会越来越严重——最开始的几百毫秒用户还能忍到后面页面多了白屏爬到三秒以上那就不是一个“能用”的系统了。所以这套组合的适用边界是常规业务后台、中后台管理系统、企业内部工具平台。超出这个范围你就得往工程化、微前端、可视化方向扩展那已经是另一套体系了。2. 一套可维护的后台管理系统源码骨架是怎么搭出来的2.1 目录结构要按“业务”分不按“文件类型”分很多新手写源码喜欢这样组织目录components目录放所有组件views目录放所有页面utils目录放所有工具函数。简洁是简洁但业务一多找一个按钮的代码可能要翻五个文件夹。我在设计这套源码时采用的是按业务模块聚类的结构。核心是这个思路src/ api/ # 接口请求按业务模块拆分文件 assets/ # 静态资源 components/ # 公共组件只放被多个模块复用的 composables/ # 组合式函数拆业务逻辑用 layout/ # 后台整体布局侧边栏、顶栏、标签栏 router/ # 路由配置 store/ # 状态管理 styles/ # 全局样式 utils/ # 工具函数请求封装、鉴权工具等 views/ # 页面按业务模块建子目录views目录下不是直接堆页面文件而是按业务模块分文件夹。比如用户管理模块是一个文件夹里面的列表页、新增编辑页、角色配置页都在这个文件夹下。api目录也按同样风格拆用户管理相关的接口请求就放api/user.js里。这样当你维护用户模块时页面、接口、逻辑都聚集在相邻的目录里找代码的时间能省一半。2.2 路由拆分静态路由和动态路由分开写后台管理系统的路由是整个源码的骨架路由写乱了权限控制、菜单渲染、页面跳转全都会出问题。我在这套源码里把路由分成两部分。第一部分是静态路由也就是不需要权限就能访问的东西比如登录页、404页、无权限提示页。第二部分是动态路由那些需要登录后并且有对应权限才能访问的页面比如用户管理、订单管理、报表统计这类。静态路由和动态路由分开写核心是一个动态添加路由的机制。前端在用户登录后拿到后端返回的权限码和用户角色根据权限码过滤出他能访问的路由表再把这些路由动态注册进去。Vue Router 3用的是addRoutesVue Router 4改成了addRoute一次性传路由数组的方式变成了逐个添加。我写源码的时候封装了一个动态注册路由的工具函数循环调用addRoute把过滤后的路由加进去。还有一个容易忽略的点动态路由注册以后如果用户退出登录路由不会自动销毁。我在源码里会记录原本的静态路由表退出登录时重置路由到初始状态避免下次登录一个低权限用户钻进别人的菜单里。2.3 状态管理不是非用 Vuex 不可后台管理系统的全局状态老实说没有C端项目那么多。常见的全局状态无非是用户信息、token、权限码、侧边栏折叠状态、标签页缓存。如果你用Vue3我强烈建议直接用Pinia理由非常现实Pinia的API更简单没有mutations的概念修改状态直接调用action还天然支持模块化每个store就是一个独立的文件。Vuex那一套commit、dispatch的逻辑写起来太啰嗦在我维护过的项目里大部分状态其实根本不需要时间旅行调试这种高级特性Pinia足够用。我在这套源码的store设计里至少会拆成user用户信息与鉴权、permission权限码与动态路由、app侧边栏、标签页这些界面状态三个独立store。这样模块之间不会互相污染维护起来也直观。设计原则是能放在组件内部用ref管理的状态绝不放全局store。全局状态越少排查问题越容易。3. 登录、权限、表格联动与Excel预览源码里这些硬骨头怎么啃3.1 登录鉴权与token管理登录功能是后台管理系统第一个必须面对的硬骨头。很多初始模板只是简单地把token存到localStorage里登录后跳转首页看起来一切正常但项目一旦上线问题就来了token过期了该怎么处理用户刷新页面后用户信息丢了怎么办接口返回401时要不要主动跳登录页我在这套源码里做了一个完整的鉴权闭环。登录请求成功后把token保存起来的同时调用一次获取当前用户信息的接口把用户昵称、头像、权限码一次性拿回来存到Pinia里。路由守卫beforeEach里做三重判断有没有token没有就跳登录页有token但没有用户信息就先去拉用户信息用户信息拉完后再判断当前路由是否在权限列表里不在就跳无权限页。token的存储位置我选择了localStorage。sessionStorage在关闭浏览器后token就没了实际上很多后台用户刷新页面都不希望被强制重新登录cookie更适合服务端渲染场景纯前端spa项目用localStorage最直接。注意别把所有用户信息都塞到localStorage里占空间倒是其次主要是任何脚本通过XSS拿到localStorage的内容等于把用户画像全泄露了所以localStorage里只放token用户信息放内存。3.2 动态权限按钮级和路由级分开控制权限设计是后台管理系统源码里最容易写乱的部分。路由级权限控制的是这个用户能不能访问某个页面按钮级权限控制的是即使进了这个页面能不能看到或点击“新增”“删除”之类的按钮。我在源码里把这两种权限拆成两个独立的机制。路由级权限走的是动态路由注册用户登录后遍历菜单树能访问的路由才addRoute进去。按钮级权限挂了一个自定义指令模板里写v-permissionuser:add如果当前用户权限码里没有user:add这个值就直接把元素从DOM里移除。这个设计最直观的好处是判断逻辑从业务组件里彻底抽离出来。不在每个页面的created钩子里写一大段权限判断代码而是在模板声明层面就完成控制。同样一套页面组件不同权限的人打开看到的是不同密度的操作按钮。3.3 el-select全选联动一个容易翻车的交互热搜里有个词条是“vue2和elementui中el-select全部选择后其他也选上”这正好是后台管理系统里很典型的一个交互坑。场景是这样的用一个el-select做多选筛选下拉数据项里第一项是“全部”后面跟着“部门A”“部门B”“部门C”。用户点“全部”时预期是所有部门都被选中但el-select默认的逻辑不是这样你选中“全部”后其他部门可能也莫名其妙被带上了或者只选中了“全部”这一项部门实际没选上。问题本质在于手动控制勾选值和el-select内部维护的选中值之间发生了不一致。ElementUI的el-select接收的是绑定value它自己内部的时候其实有两种处理逻辑一种是当前选中项本身就是“全部”那直接替换成全部选项的value数组另一种是用户手动取消了某个部门选项那“全部”这个虚拟选项就要自动被剔除。我在这套源码里遇到这个场景时采用了一个更稳的方案把“全部”设计为value等于all的特殊选项不在选项列表里混在一起单独用一行或者分组显示。在change事件回调里判断const handleSelectChange (val) { // 选了“全部”直接把所有选项的value填进去 if (val.includes(all)) { form.value.departments departmentList.value.map(item item.id) return } // 手动取消到选中数少于总数时自动把“全部”从选中项里剔除 //el-select的选中值是纯数组不会自动处理all需要手动维护 }具体实现上更推荐的做法是用el-select的collapse-tags配合手动维护的selectedAll标记而不是真的把“全部”作为value塞进数组里。原因很简单后端接口不认“全部”这个值提交的部门id列表里掺了一个all后端就会报参数错误。所以前端的做法应该是界面显示上把“全部”做得像一个可勾选项但实际提交时永远提交真实的部门id数组。3.4 树形表格多勾选父子关联没你想的那么简单另一个高频坑是“elementui树形表格多勾选”。el-table有树形数据的懒加载和展开功能结合typeselection多选列时默认的父子节点勾选是联动的勾选父节点子节点全部选中取消父节点子节点全部取消。这个默认行为在小权限树、组织架构树里挺好用但业务稍微复杂一点就会出现两个绕不开的问题。第一个问题父节点勾选时父节点的id会不会跟着被提交默认情况会。但在组织架构这种场景里用户想选的是“这个部门下的所有人”如果提交请求时把父部门id也带上后端就要额外判断是把这个父节点当组织处理还是把人当成员处理。我在源码里会在提交前做一个过滤把父节点id从勾选集合里剔除只保留叶子节点。第二个问题部分勾选时怎么处理如果你希望实现“只勾选某些子节点父节点严格不联动但是有半选中状态”默认行为是做不到的。这时候要设置el-table的check-strictly属性。注意传true表示父子节点不联动父节点的选中状态完全独立但又不显示半选状态了这就跟需求冲突了。我的折中方案是check-strictly保持默认false父子联动但在变更事件里根据勾选状态动态调整提交数据。后端需要什么就提交什么。而不是跟前端表格的展示状态纠缠。因为el-table的树形多选本质上是“选择组的展示”提交的数据结构才决定业务逻辑是否正确。3.5 在线预览Excel后台管理系统里被低估的功能很多后台管理系统的业务场景里用户会要求“能直接在浏览器里预览Excel表格”而不是下载下来再用本地软件打开。这个需求听着小真做起来比想象中麻烦。网上能搜到“后台管理系统在线预览excel表格”这类词说明大家普遍在找现成方案。我在这套源码里用了xlsx库解析Excel数据再配合HTML表格渲染的方案。核心思路是解析.xlsx文件把每个sheet里的单元格数据读成二维数组然后把第一行当表头生成HTML表格样式。这样做的优点是不依赖任何在线服务本地就能跑也适合企业内网离线环境。要注意的是这种解析方案难免有样式丢失的问题。Excel里合并单元格、背景色、边框、公式xlsx库能识别一部分但还原度有限。如果业务对样式还原要求很高只能上服务端转换成HTML或者PDF再返回给前端。我通常的做法是给预览功能加一个“excel解析中”的加载状态提示同时把文件名和sheet切换功能一起做进去让用户至少能看数据样式要求高的场景另说。很多后台项目在这块只是“能用”和“较好用”的差距花半天做一下比被业务方吐槽强很多。4. 源码拿到手之后环境配置、调试与二次开发的落地姿势4.1 安装依赖阶段就翻车先看版本很多开发者在跑别人源码的时候最容易倒在第一关npm安装依赖。尤其是老项目的源码node-sass和node版本不匹配是最大的坑。node-sass是在安装时编译本地二进制文件的Node.js版本一升级它就可能编译失败报错信息一长串新手看一眼就懵。我整理这套源码时把样式方案换成了官方推荐的dart-sasssass彻底避开node-sass的版本地狱。如果你是从旧源码二次开发遇到node-sass报错最快的解决办法是把package.json里的node-sass替换成sass或者sass-embedded然后再npm安装。语法上大部分scss代码都是兼容的唯一要注意的是旧版import规则可能需要改成新版推荐的use/forward。还有一个常见的“白屏坑”装完依赖、npm run dev跑起来页面一片空白控制台报了一个错误。这个问题往往不是源码问题而是你的Node.js版本太新或者Vite版本和Node版本不匹配。Vite 2要求Node 12以上Vite 3要求Node 14.18以上Vite 4要求Node 14.18或者16。如果版本跨度太大建议直接把lock文件删了重装让依赖版本按package.json里面允许的语义化版本范围重新解析一遍。4.2 Vue Devtools的正确用法拿到一套后台管理系统源码第一步肯定不是上来就看代码而是把项目跑起来点一点界面看数据流。我强烈建议调试环境装上Vue Devtools浏览器插件。Vue3项目要装对应版本的插件Vue2项目要装Vue.js devtools的相应版本装错版本插件根本不会生效。Devtools最大的价值是看组件状态你点开某一个表格页面可以看到当前组件实例的data、props、computed、pinia状态一目了然。实际排查问题时我常用的几个标签页分工是这样组件树看组件嵌套关系找“这个弹窗为什么显示不出来”之类跟渲染层级相关的问题Pinia/Vuex标签页看全局状态排查“侧边栏折叠状态刷新后怎么丢了”这类问题Router标签页可以看当前路由记录、导航守卫跳转是否正常。还有一个非常实用的场景是排查el-select全选联动这种问题的时候直接在Devtools里改选中数组立刻就能验证是不是渲染层的问题还是事件回调逻辑的问题省去一遍遍重新操作界面。4.3 二次开发时别在源码里硬改这是我最想强调的一点。很多人拿到源码第一反应是直接改node_modules里的依赖或者把公共组件内部逻辑改得面目全非结果项目一升级依赖所有改动灰飞烟灭。我的原则是能不动公共源码就不动实在要动通过扩展、二次封装实现。比如ElementUI的table表格满足不了当前业务的列拖拽需求不要直接改node_modules里element-ui的源码而是封装一个业务表格组件在内部基于el-table做二次包装上层页面使用这个业务组件。这样升级依赖时你只改一个封装文件就行不影响几十个页面。同理接口请求封装、权限指令、动态路由工具函数这些基础设施在源码里尽量做成可配置的参数从配置文件或接口返回值里读不要写死。我在这套源码里做了一个约定凡是标注了FIXME或者CUSTOM的代码区域就是二次开发时需要重点查看的扩展点其他区域可以放心升级依赖。5. 写这套源码之后我的一些个人体会5.1 选项式还是组合式不要盲目跟风热搜里有“vue选项式和组合式区别”说明这是很多人面试和实际开发都绕不开的话题。我的观点是同一个项目里最好统一风格但不必强行全用组合式API。选项式的data/methods/computed在页面逻辑简单的场景下非常直观组合式API在复杂业务逻辑复用的场景下优势明显。如果团队水平参差不齐我经历过的一个比较稳的方案是页面组件用选项式保持直观公共逻辑用组合式函数composables来抽取复用两种模式各司其职。5.2 设计源码不是写给自己看的是写给维护者看的写这套源码的过程中我最大的体会是好的源码最重要的评价标准不是技术多炫而是你两个月后再打开这个项目还能不能快速定位到一个功能的入口。所以我在源码里加了大量的中文注释不是那种解释代码语法的废话注释而是说明业务意图的注释比如“这里的权限码来自后端的menu表不能随意改动”“此处修改会影响角色配置页的数据回显”。5.3 如果是从零开始学一条更省力的路径最后分享一个学习路径上的小建议。如果你没有公司项目练手想靠后台管理系统源码提升水平不要一上来就研究动态路由和权限设计。先照着官方文档把ElementPlus的表格、表单、弹窗这几个核心组件玩熟然后用Vite手动搭一个只有登录页和首页的极简后台跑通了之后再逐步加权限、加路由懒加载、加组件封装。一到两周时间你会发现市面上大部分后台管理系统模板的源码你都能看懂了。这就是这篇文章想传达的最终价值——源码不是一个结果而是一套思考过程你把它拆开看懂了下一次遇到类似需求就能自己设计了。本文还有配套的精品资源点击获取