资讯动态

基于Node.js与Vue的幼儿园管理系统开发实录:从架构设计到上线部署

发布时间:2026/9/28 9:22:18 来源:尧图企业网站定制
接手这个项目的时候我正帮亲戚家的私立幼儿园做一套日常管理系统。园长提的需求很直接孩子档案、每日出勤、家长接送、收费统计最好还能让家长在手机上看到孩子在园里的情况。技术栈锁定在 Node.js Vue 这对组合上一方面是我自己熟悉另一方面这套东西轻量、开发快小团队一两个人就能搞定后期维护也不挑人。标题里的 elx46 是我给项目起的内部代号后端是 Node.js 提供的 RESTful API前端用 Vue 全家桶做单页应用数据库用的 MySQL。这篇文章把整个开发过程里值得记录的东西整理成文包括为什么这么设计、环境搭建里的坑、核心模块怎么实现、以及最后上线遇到的问题和排查思路。想自己动手做类似管理系统的人或者正在用 Vue Node.js 写课程设计、毕业设计的同学应该能从这里找到不少可以直接抄作业的内容。1. 项目定位与整体设计思路1.1 幼儿园管理系统到底在管什么很多没接触过幼教行业的人以为幼儿园管理系统就是简单记录一下孩子的名字和家长电话实际梳理完需求才发现这里面的业务线比想象中复杂得多。从核心业务来看幼儿园的日常管理可以拆成六大块。第一块是幼儿档案管理每个孩子从入园登记开始就有完整的档案基本信息、过敏史、既往病史、监护人信息、紧急联系方式这些数据是后续所有业务的底座。第二块是班级与教职工管理一个园所有十几个班每个班有主班老师、配班老师、保育员老师的信息和排班情况也要纳入系统。第三块是出勤与接送管理这是家长和园方交互最频繁的场景每天早上入园打卡、下午离园打卡谁接的孩子、几点接走的必须留痕。第四块是收费管理不同班型的收费标准不一样还有餐费、校车费、延时服务费每个月生成账单、记录缴费状态。第五块是健康与食谱管理晨检记录、用药嘱咐、每周食谱公告这类信息家长关注度非常高。第六块是消息通知与家校互动园方通知、班级动态、孩子的在园照片和视频都要通过系统推送给家长。这些模块单独看都不复杂但合在一起对数据一致性、权限控制和操作便利性就有了要求。比如一个老师登录系统她应该只能看到自己班级的数据不能越权访问其他班家长登录后只能看到自家孩子的信息园长端则要看到全园所有维度的统计报表。这些权限边界在数据库设计和接口设计阶段就必须想清楚不然后期补权限模型成本会翻好几倍。1.2 为什么选 Node.js Vue 这套技术组合选型的时候我也认真考虑过 Spring Boot Vue、Python Django Vue甚至全栈 Next.js 这些方案但最终还是定了 Node.js 生态。最核心的考量是开发效率。幼儿园管理系统本质上是典型的 CRUD 应用数据模型清晰、业务流程固定这类系统最怕的不是技术难题而是开发周期拖太长。Node.js 的 Express 框架写 RESTful API 非常简洁JavaScript 语言在前后端保持统一不需要维护两套技术栈的知识体系。对于一个人或两三个人的小团队来说前后端同语言带来的心智负担降低是实打实的优势。第二个原因是前端生态的成熟度。Vue 在国内有非常庞大的用户群体和社区资源Element Plus 提供了一套开箱即用的后台管理 UI 组件表格、表单、弹窗、日期选择器这些后台系统的标配组件拿来就能用。Vue Router Pinia Axios 这套组合前后端分离项目的标准模式已经非常成熟踩坑资料一搜一大把个人员工的个人博客上就能找到各种维护经验。第三点是部署成本低。服务端只需要一个 Node.js 运行时前端打包后是一堆静态文件用 Nginx 托管即可。小园所的服务器配置通常不会太高Node.js 本身内存占用量小、单进程事件驱动的模型应对中小并发量完全够用。当然这套方案也有明显的短板比如 CPU 密集型的业务做起来吃力、生态里可靠的事务处理和 ORM 方案比 Java 生态少一些。但就幼儿园管理系统这个体量来说这些短板基本碰不到。1.3 模块划分与数据表设计整体架构采用前后端完全分离的方式。前端项目跑在 8080 端口通过 Axios 调用后端接口后端项目跑在 3000 端口所有接口以 /api 为前缀。前端用 Vue Router 做路由控制根据登录用户的角色动态生成可访问的路由表后端用 JWT 做无状态鉴权每个请求都携带 Token由统一的中间件校验身份和权限。数据库设计是整个系统里最需要提前花心思的部分。核心表有这些幼儿信息表children存储孩子的档案数据字段包括姓名、性别、出生日期、入园日期、所在班级 ID、过敏史、既往病史、家长联系方式等。班级表classes存储班级名称、年级阶段、教室位置、当前班主任 ID。教职工表staff存储教师和保育员的信息包括姓名、手机号、岗位、所属班级、入职时间。用户表users与教职工表是一对一关系存储登录账号、加密密码、角色标识。出勤记录表attendance记录每个孩子每天的入园和离园时间、接送人信息。收费记录表payments记录每个孩子的账单、缴费金额、缴费方式、缴费状态。食谱表menus记录每周每天的餐食安排按日期索引。通知公告表notices记录园方发布的各类通知关联发布人、发布时间和推送范围。这些表之间的外键关系在设计时要克制不要在数据库层面建立过多物理外键而是通过应用层逻辑维护关联关系。原因在于 MySQL 的物理外键在数据量增大后会带来锁竞争问题而且后期删除、归档数据的操作会被外键约束卡住。把表结构设计清楚在代码里保证引用的完整性是更灵活的做法。幼儿档案表特别设计了几个容易忽略的字段。过敏史和既往病史我用了 TEXT 类型而非字符串枚举因为不同孩子的过敏源千奇百怪枚举类型根本枚举不完直接存文本配合前端文本输入框简单实用。接送人字段也做了扩展一个孩子可能同时有爸爸妈妈、爷爷奶奶、外公外婆多个接送人所以没有用固定字段而是单独建了一张接送人表关联孩子 ID 和接送人姓名、电话、与孩子关系。2. 环境搭建新手最容易栽的跟头2.1 Node.js 安装与环境变量配置整个项目的第一步就是装 Node.js这一步看似基础实际上一半以上的环境问题都出在这里。下载安装包时强烈建议从官网nodejs.org下载 LTS 版本而不是追求最新版。LTS 的意思是长期支持版本稳定性经过了大量生产环境验证。我的项目用的是 Node 18 LTS 版本这个版本对 Vue 3 的 Vite 构建工具支持得非常好同时自带 npm 9 版本避免了老版本 npm 的一些兼容性问题。环境变量配置是另一个重灾区。Windows 下安装完成后系统会自动把 Node.js 的安装路径加入 PATH但有时候因为安装时取消了某些勾选项或者用了绿色免安装版解压PATH 里就没有 Node.js 的路径。验证方法是在命令行输入 node -v 和 npm -v如果提示无法识别 node 命令说明 PATH 配置有问题。此时需要手动配置环境变量具体步骤是右键此电脑选择属性点击高级系统设置进入环境变量面板在系统变量里找到 PATH点击编辑把 Node.js 的安装目录路径添加进去。还需要新建一个 NODE_HOME 变量变量值填 Node.js 的安装路径。配置完成后重新打开命令行输入 node -v正常情况下会显示类似 v18.20.4 的版本号。注意修改完环境变量后务必重新打开命令行窗口才能生效。如果是在 VSCode 里打开的终端VSCode 本身也要重启否则环境变量读取不到。npm 的全局包安装路径也值得配置一下。默认情况下npm 全局安装的包会放在 Node.js 安装目录的 node_modules 下这会导致两个问题一是权限限制某些目录需要管理员权限才能写入二是升级 Node.js 时会连带影响全局包。所以我在环境变量里新增了一个 NPM_GLOBAL_PATH指向自定义的全局包目录然后执行 npm config set prefix 命令指定到该路径。2.2 npm.ps1 禁止运行脚本的根治方案这个坑相信每一个用 PowerShell 跑 npm 命令的人都见过。当你第一次在 VSCode 终端里敲 npm install 或 npm run dev 时系统突然弹出一行红色报错npm : 无法加载文件 D:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本。原因很简单Windows 默认的 PowerShell 执行策略是 Restricted禁止运行任何 .ps1 脚本文件而 npm 在 PowerShell 下是通过 npm.ps1 这个脚本包装器运行的于是就被拦截了。当时我第一次遇到这个报错第一反应是重新安装 Node.js结果装完依然报错这才意识到问题出在 PowerShell 执行策略上。解决方式有两种。第一种是临时绕过在 PowerShell 里输入命令时改用 npm.cmd 来代替 npm。比如安装依赖输入 npm.cmd install启动项目输入 npm.cmd run dev。这种方式不改变系统的安全策略但每次输入都要带后缀非常麻烦。第二种是彻底解决把当前用户的 PowerShell 执行策略改为 RemoteSigned。在管理员权限的 PowerShell 里执行Set-ExecutionPolicy RemoteSignedRemoteSigned 的含义是本地创建的脚本可以运行从网络下载的脚本必须经过数字签名才能运行。这个策略既保持了基本的安全性又允许 npm 这类本地脚本正常工作。执行后系统会提示确认输入 Y 回车即可。改完执行策略后重新打开终端npm 命令就能正常使用了。这个方法我在多个 Windows 版本上验证过Win 10 和 Win 11 都适用。还有一个小技巧如果你觉得 PowerShell 太麻烦可以直接把 VSCode 的默认终端改成 cmd 或 Git Bash。这些终端不依赖 ps1 脚本完全没有执行策略限制。但说实话这属于绕路走治标不治本因为后续很多工具链比如 PowerShell 命令脚本可能还会用到 PowerShell。2.3 Vue 脚手架初始化与依赖安装环境准备好之后就是创建前端项目了。我用了 Vite 作为构建工具相比 Vue CLIWebpack 版来说Vite 的开发服务器启动速度要快得多热更新的体验也更流畅。创建项目的命令很简单npm create vitelatest kindergarden-frontend -- --template vue这条命令会创建一个名为 kindergarden-frontend 的项目并且使用 Vue 3 的模板。进入项目目录后执行 npm install 安装基础依赖。依赖安装环节我踩的最大的一个坑就是网络速度。npm 默认的官方源在国外国内访问时经常慢到崩溃或者中途断掉导致 node_modules 残缺。解决办法是配置淘宝镜像源npm config set registry https://registry.npmmirror.com配置完成后可以执行 npm config get registry 验证是否切换成功。切换镜像源之后安装速度可以用飞来形容之前要等十分钟的安装现在几十秒就完成了。但镜像源也会带来一个问题某些私有包比如公司内部的 npm 包不在镜像源的同步范围内。如果是个人项目这一步不需要担心。除了基础依赖需要额外安装的核心依赖还有这些vue-router路由管理、pinia状态管理、axiosHTTP 请求库、element-plusUI 组件库、sass样式预处理。安装命令npm install vue-router4 pinia axios element-plus sass这里有两个细节值得注意。第一vue-router 必须指定版本。Vue 2 和 Vue 3 的路由库版本完全不同如果不加版本号npm 会默认安装当下最新的包但如果项目用的是 Vue 2就需要用 vue-router3。我们项目用的是 Vue 3所以必须显式指定 vue-router4。第二element-plus 的按需导入问题。如果整个 UI 库全量打包产物体积会很大首屏加载时间明显变长。我采用了按需引入的方式配合 unplugin-auto-import 和 unplugin-vue-components 这两个插件在 Vite 配置文件里做自动导入组件和 API 用到了才会打包进去。// vite.config.js import AutoImport from unplugin-auto-import/vite import Components from unplugin-vue-components/vite import { ElementPlusResolver } from unplugin-vue-components/resolvers export default { plugins: [ AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] }) ] }配置完成后在 Vue 组件里直接写 el-table、el-dialog 等标签就能生效不需要手动 import 组件和样式非常省事。3. 前端核心模块实现3.1 基于 vue-router 的角色权限路由设计幼儿园管理系统涉及三种角色园长、教师、家长。不同角色的功能权限差异巨大园长能看到所有统计报表和收费数据教师只能管理本班事务家长只能查看自家孩子的内容。这个需求在路由层面如何设计决定了整个系统的安全性和可维护性。我的做法是把路由分成两类静态路由和动态路由。静态路由是所有人都能访问的基础页面比如登录页、首页重定向。动态路由是在用户登录后根据角色从后端获取可访问的路由配置通过 router.addRoute 动态添加。在后端接口设计上我专门提供了一个 /api/auth/routes 接口根据当前用户的角色返回一组路由元数据包含路由路径、组件映射、菜单名称、图标等信息。前端拿到这份路由配置后动态注册到 vue-router 实例中。这里的难点在于组件映射。后端返回的只是字符串形式的组件路径比如dashboard/index前端需要把它转换成实际的组件对象。解决方案是使用 import.meta.glob 批量导入所有页面组件const modules import.meta.glob(../views/**/*.vue) function loadView(viewPath) { return modules[../views/${viewPath}.vue] }这样前端就能根据后端下发的路由配置动态加载对应的组件。路由守卫是权限控制的最后一道防线。我在全局前置守卫里做了三个判断第一用户是否已登录检查 localStorage 里有没有 Token没有就跳转登录页第二用户的路由表是否已经生成如果没有先调用接口获取用户的角色信息和动态路由配置添加到路由表后再继续导航第三访问的路径是否在当前用户的路由表里如果不在跳转到 403 或 404 页面。注意动态路由的核心原则是后端不下发前端就没有。千万不要在静态路由里把全部页面都注册好然后用 v-if 隐藏。因为 Vue Router 的路由表本身是响应式的用户可以通过修改浏览器地址来访问未授权的页面。真正的控制必须在路由层面而不是页面渲染层面。3.2 自定义 v-model 封装业务组件Vue 3 里自定义 v-model 是一个非常重要的特性项目中我用它做了一套班级选择器组件效果非常理想。先说一下背景。在收费管理、出勤统计、消息通知等多个模块里都需要选择一个或多个班级。如果每个页面单独写一遍班级选择逻辑代码冗余严重而且后续如果班级筛选条件变了比如增加年级维度改动量会很大。所以我决定封装一个班级选择器组件 SchoolClassSelect。自定义 v-model 的核心原理是Vue 3 中v-model 在组件上等价于 modelValue 属性和 update:modelValue 事件的组合。父组件这样写SchoolClassSelect v-modelselectedClass /等价于SchoolClassSelect :modelValueselectedClass update:modelValueselectedClass $event /在子组件内部接收的 prop 是 modelValue需要更新时通过 emit 抛出 update:modelValue 事件父组件的值就会自动更新。script setup defineProps({ modelValue: [Number, Array], multiple: { type: Boolean, default: false } }) const emit defineEmits([update:modelValue]) function handleChange(value) { emit(update:modelValue, value) } /script用这种方式封装的组件内部实现对外部完全不可见。外部调用者不需要关心组件内部是调接口拿班级数据还是本地写死只需要使用 v-model 双向绑定数据即可。这就是自定义 v-model 带来的最大价值封装复杂细节保持统一的使用方式。项目中我还用同样的方式封装了带搜索功能的家长选择器、支持单选和多选的孩子选择器整个复用体系成型之后开发新页面的效率明显提升基本上一个业务页面只要写页面布局和调用接口的逻辑复杂的业务数据交互都交给封装组件去处理。3.3 家校互动与 m3u8 视频监控播放家长端需求量最大的功能之一就是查看孩子在园视频。很多幼儿园在教室和活动区装了摄像头会向家长开放实时画面。技术实现上这些摄像头输出的一般是 HLS 流视频地址以 .m3u8 结尾。Vue 前端播放 m3u8 视频是一个比较典型的场景。默认情况下HTML5 的 video 标签不能直接播放 m3u8 格式因为浏览器原生不支持 HLS 协议除了 Safari 是天然支持的Chrome 和 Edge 等主流浏览器都需要借助 flv.js 或 hls.js 这类第三方库来转封装。项目里用的方案是 hls.js。安装依赖npm install hls.js然后封装一个视频播放组件template video refvideoRef controls playsinline/video /template script setup import Hls from hls.js import { ref, onMounted, watch } from vue const props defineProps({ src: { type: String, required: true } }) const videoRef ref(null) function playStream(src) { const video videoRef.value if (Hls.isSupported()) { const hls new Hls() hls.loadSource(src) hls.attachMedia(video) } else { video.src src // 原生支持 HLS 的浏览器直接赋值 } } onMounted(() playStream(props.src)) watch(() props.src, (newVal) playStream(newVal)) /script这个组件有几点值得注意。第一必须用 watch 监听视频地址的变化因为在实际使用中用户可能切换不同的监控画面地址变了要重新初始化播放器。第二组件卸载时要调用 hls.destroy() 释放资源不然会有内存泄漏。第三直播流往往有延迟hls.js 默认的配置适合点播直播场景需要设置一个较短的 manifest 加载时长。除了实时视频家长端还有每日照片的功能。老师上传孩子一天活动的照片集家长在手机上查看。这一块是通过后端提供的图片上传接口实现的上传后的图片存储在服务器指定目录数据库只存相对路径前端通过域名拼接得到完整的图片 URL。4. 后端 API 与前后端联调4.1 RESTful API 设计与 Token 鉴权后端我用 Express 框架搭建虽然 Express 4 已经非常成熟但为了统一处理异步错误我选择了 Express 5 的中间件风格配合 asyncHandler 包装器让异步接口的异常能够统一交给全局错误处理中间件。接口设计遵循 RESTful 原则。资源用名词复数表示操作使用 HTTP 方法。例如GET /api/children 获取幼儿列表 POST /api/children 新增幼儿 PUT /api/children/:id 更新幼儿信息 DELETE /api/children/:id 删除幼儿这个方法设计天然地覆盖了常规增删改查需求。需要注意的是在实现分页查询和条件筛选时不要用动词混合在 URL 里而是通过查询参数实现GET /api/children?page1pageSize10classId3keyword张。对于有权限边界的业务在接口层面必须做二次验证。例如教师角色调用 GET /api/children 接口时后端需要从 JWT 中解析出教师的班级 ID在查询语句中自动加上 class_id 条件而不是让前端传班级 ID 然后后端无条件信任。前端的过滤只是用户体验层面的真正的防越权过滤必须发生在后端。Token 鉴权我用的是 JWTJSON Web Token。登录成功后后端生成一个签名后的 Token前端存储在 localStorage 中每次请求时在请求头带上 Authorization: Bearer 。后端使用一个统一的鉴权中间件const jwt require(jsonwebtoken) function authMiddleware(req, res, next) { const authHeader req.headers.authorization if (!authHeader) { return res.status(401).json({ code: 401, message: 未登录 }) } const token authHeader.split( )[1] try { const decoded jwt.verify(token, process.env.JWT_SECRET) req.user decoded next() } catch (error) { return res.status(401).json({ code: 401, message: 登录状态已过期 }) } }JWT 有一个容易踩坑的点token 一旦签发在有效期内无法主动作废。如果玩家的账号被盗攻击者可以在 token 过期前一直持有登录状态。针对这个问题我在 JWT 的 payload 里存放了用户 ID 和角色但没有放太多其他信息避免 token 过长。对于普通管理系统把过期时间设置为 12 小时配合前端的自动登录过期检测基本够用。4.2 文件上传与头像管理幼儿园管理系统的文件上传需求非常多幼儿头像、老师发布的动态图片、食谱图片甚至家长上传的请假条照片。我使用 multer 中间件处理文件上传存储到本地磁盘。const multer require(multer) const path require(path) const storage multer.diskStorage({ destination: (req, file, cb) { cb(null, path.join(__dirname, ../uploads)) }, filename: (req, file, cb) { const uniqueName Date.now() - Math.round(Math.random() * 1e9) const ext path.extname(file.originalname) cb(null, uniqueName ext) } }) const upload multer({ storage })文件上传接口app.post(/api/upload, authMiddleware, upload.single(file), (req, res) { const filePath /uploads/ req.file.filename res.json({ code: 200, data: { url: filePath } }) })上传后的文件路径保存在数据库对应记录里前端展示时用 Nginx 配置的静态资源路由来访问 /uploads 目录。文件上传有几个安全细节必须处理。第一限制上传文件大小multer 可以设置 limits 字段比如图片最大 5MB防止有人恶意上传超大文件拖垮服务器。第二对文件类型做白名单校验只允许 jpg、png、gif、webp 等常见图片格式不能只依赖前端限制因为攻击者可以绕过前端直接调接口。第三文件命名不能用原始文件名必须重命名为随机名称防止路径遍历攻击和文件名冲突。4.3 前后端联调技巧与跨域处理前后端分离开发时跨域问题是逃不掉的一环。前端跑在 8080 端口后端在 3000 端口浏览器会因为同源策略拦截跨域请求。解决跨域有几种方案我在开发阶段用的是 Vite 的代理功能生产环境用的是 Nginx 反向代理。Vite 代理配置在 vite.config.js 中export default { server: { port: 8080, proxy: { /api: { target: http://localhost:3000, changeOrigin: true } } } }这样前端的请求实际是发给自己的 8080 端口由 Vite 服务器转发到后端的 3000 端口。浏览器感觉不到跨域的存在后端也无需设置 CORS 头。生产环境部署时Nginx 配置类似这样server { listen 80; server_name your-domain.com; location / { root /var/www/kindergarden-frontend; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /uploads { alias /var/www/kindergarden-backend/uploads; } }关键点在 location / 的 try_files 配置。Vue Router 默认是 history 模式的直接访问路由路径时比如 /children请求到了 NginxNginx 会寻找 /children 对应的静态文件但实际不存在必须通过 try_files 重定向到 index.html由前端路由接管否则刷新页面就会 404。联调过程中我发现一个非常有用的调试方法在 Chrome 网络面板里把请求筛选器切换到 Fetch/XHR能看到所有 API 请求的状态、耗时、响应体。当接口返回非 200 状态码时快速定位是后端逻辑错误还是前端参数传错。一个经验是后端接口返回的所有结构化响应都要统一格式code、message、data这样前端 Axios 拦截器可以统一处理错误和提示axios.interceptors.response.use( (response) { if (response.data.code 200) { return response.data.data } else { ElMessage.error(response.data.message) return Promise.reject(response.data) } }, (error) { ElMessage.error(网络请求失败) return Promise.reject(error) } )统一状态码和拦截器的好处是业务代码里不需要每个接口都做错误处理只需要关心成功返回的数据。但注意要区分 HTTP 状态码和业务状态码HTTP 200 不代表业务成功业务状态码放在响应体里。这个规范从第一个接口就要定好不然中途改动所有接口工作量巨大。5. 常见问题与排查实录5.1 依赖安装失败的几个典型场景项目开发中 npm install 失败是高频问题我遇到并解决的几个场景值得写下来。第一个场景是提示 ERESOLVE unable to resolve dependency tree。这个报错通常出现在依赖版本相互冲突时。比如我的项目里某个包要求 element-plus 2.3.0而另一个包 lock 住了 element-plus 2.2.xnpm 就会因为无法解析依赖树而报错。解决办法是先执行 npm cache clean --force 清理缓存再删除 node_modules 和 package-lock.json最后重新执行 npm install。如果还不行可以尝试 npm install --legacy-peer-deps这个参数会跳过 peerDependencies 的自动安装检查虽然不推荐长期使用但临时解决问题很有效。第二个场景是提示 Unsupported platform for...。这通常是因为操作系统和某些平台相关包不兼容。比如某些包默认包含 Windows 和 Mac 的二进制文件但实际安装到某个平台时该文件不适合。解决办法是检查依赖是否支持当前 Node 版本npm 官方文档里每个包都有 engines 字段说明支持范围。第三个场景是安装 Electron 或 node-sass 这类原生模块时长时间卡住不动或者下载失败。这类模块需要下载预编译的二进制文件国内的网络环境访问其下载地址很慢。解决办法是给 npm 配置二进制文件镜像源不同包有不同的镜像地址以 Electron 为例npm config set electron_mirror https://npmmirror.com/mirrors/electron/第四个场景是 Windows 下 npm install 时出现文件占用错误node_modules 里某些文件被进程锁住了。解决办法是关闭相关进程特别是 VSCode、PowerShell 窗口删除 node_modules 后重试。5.2 Vue DevTools 插件与调试排查 Vue 应用问题时Vue DevTools 是绕不开的工具。开发阶段我先在 Chrome 应用商店安装了 Vue DevTools 插件但有一个细节要注意Vue 3 需要使用 Vue DevTools 6.0 以上版本并且开发模式下才能正常连接。如果用 Vue 2 的 DevTools 插件去调试 Vue 3 项目控制台会报错或者插件完全没有反应。DevTools 插件的核心用途有三个。第一是查看组件树可以看到当前页面上所有组件的层级结构、props 属性、emits 事件、slots 插槽内容。排查一个组件的数据为何没有渲染出来最快的方式就是点开组件树查看它的 props 是否传递正确。第二是状态管理面板在 Pinia 版本里可以直接查看和修改状态调试用户权限变化、全局变量状态时特别方便。第三是路由面板可以看到当前路由的 path、name、params、query同时还能看到路由记录的完整匹配结构。除了 DevToolsVue 应用的另一个调试技巧是使用 vite-plugin-inspect 插件它可以查看每个组件的编译后代码和插件处理过程对排查模板编译错误和样式处理问题很有效。5.3 打包部署与桌面化扩展项目开发完成后前端打包比较简单npm run build打包产物会生成在 dist 目录把 dist 目录内容上传到服务器的 Nginx 站点目录即可。但有几个细节要注意。第一是资源路径问题默认情况下 Vite 打包后的资源路径是绝对路径 /assets/xxx如果站点部署在子目录下需要在 vite.config.js 里设置 base 配置改成相对路径或指定的子目录路径export default { base: process.env.NODE_ENV production ? / : ./, }第二是 history 模式问题前面已经提过Nginx 必须配置 try_files 才能让前端路由刷新时正常响应。还有一个后端部署细节也要强调。Node.js 的后端服务在服务器上运行时需要一个进程管理工具来保证服务常驻我用的是 PM2。启动命令pm2 start app.js --name kindergarden-api pm2 savePM2 的好处是服务崩溃后会自动重启开机时可以随系统自启日志管理也非常方便。用 pm2 logs 命令可以实时查看后端日志排查线上问题很高效。项目后期我还做了一个 Electron 打包的尝试把管理端桌面化。在网上搜索electron 打包 vue 项目能看到大量现成方案核心思路是创建 Electron 主进程文件在开发模式下指向 Vite 开发服务器生产模式下加载打包后的 dist 目录。这个方向适合做园所本地的离线管理终端但考虑到团队维护成本和打包体积Electron 打包后的应用动辄 100MB最终只做了一个内部预览版没有作为正式方案发布。我的实操体会整个项目从规划到上线大约用了六周时间。回头复盘我觉得最值得说的不是某个具体的代码技巧而是技术选型和需求理解的关系。幼儿园管理系统的代码量不大核心业务逻辑也算不上复杂但它有一个典型特征角色多、权限边界多、业务状态多。任何一个管理类系统如果在一开始没有把角色权限和数据边界定义清楚后面几乎必然会出现越权访问和数据错乱的问题。Node.js Vue 这个组合在开发效率上的优势是实打实的前后端代码同语言的特性让我省去了大量切换上下文的时间。但坦白讲这个方案对开发者自身的代码规范和模块拆分能力要求比较高因为 Node.js 生态不像 Java 生态那样有强约束的工程化标准全靠自觉。如果再给我一次机会我会在项目启动的第一天就把接口文档和数据库设计文档写完而不是边开发边补。前端和后端并行的时候没有接口文档意味着经常要根据对方的临时改动调整代码非常消耗耐心。最后分享一个提升效率的小技巧开发阶段我会用 Nodemon 来自动重启后端服务每次修改代码后不用手动重启配合 Vite 的热更新前后端的开发体验都接近即时反馈。配置方法很简单全局安装 nodemon然后用 nodemon app.js 启动后端即可。这一点小投入能明显提升日常开发的流畅度。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑