(一)pnpm+Vue3 JS Setup 组合式 仿若依后台管理系统 手把手搭建

发布时间:2026/8/28 5:47:11
(一)pnpm+Vue3 JS Setup 组合式 仿若依后台管理系统 手把手搭建 一pnpmVue3 JS Setup 组合式 仿若依后台管理系统 手把手搭建技术栈pnpm Vue3 (JavaScript) script setup Vue‑Router4 Pinia Axios Element Plus (unplugin 自动按需导入)改造点全部使用 Setup 组合式语法摒弃选项式目录优化layout和components同级不和 views 嵌套分离环境变量.env.development/.env.production支持mock 本地模拟数据 / 真实网络接口一键切换修正原版若依部分不合理目录、全局变量写法从pnpm create vuelatest从零开始分节操作复制代码即可跑通第一节初始化 Vue3 项目1.1 前置条件已安装 Node.js ≥18 版本pnpm 已安装# 没有pnpm先安装 npm install-g pnpm1.2 创建 vue 项目pnpm create vuelatest交互式选择严格按照下面选✔ Project name:› vue3‑ruoyi‑setup ✔ Add TypeScript?… No/Yes →No(我们用JavaScript)✔ Add JSX Support?… No/Yes → No ✔ Add Vue RouterforSingle Page Application development?… No/Yes → Yes ✔ Add Piniaforstate management?… No/Yes → Yes ✔ Add VitestforUnit testing?… No/Yes → No ✔ Add an End‑to‑End Testing Solution?… No/Yes → No ✔ Add ESLintforcode quality?… No/Yes → Yes ✔ Add Prettierforcode formatting?… No/Yes → Yescd vue3‑ruoyi‑setup pnpm install pnpm dev访问http://localhost:5173基础项目跑起来。⚠️ 此时生成的代码部分还是选项式后面我们全部改成script setup。第二节安装全部依赖Element‑Plus unplugin 按需导入 axios mock 相关2.1 安装依赖包pnpm add element-plus axios pnpm add-D unplugin-vue-components unplugin-auto-importunplugin-auto-import自动导入 vue、pinia、router api不用每次写import ref,computedunplugin-vue-componentsElement Plus 组件自动按需导入无需手动 import 组件2.2 修改 vite.config.js替换全部内容import{defineConfig}fromviteimport vue fromvitejs/plugin-vueimport{fileURLToPath,URL}fromnode:urlimport AutoImport fromunplugin-auto-import/viteimport Components fromunplugin-vue-components/viteimport{ElementPlusResolver}from unplugin-vue-components/resolvers// https://vitejs.dev/config/exportdefaultdefineConfig({plugins:[vue(),AutoImport({resolvers:[ElementPlusResolver()],// 自动生成auto‑imports.d.tsjs项目可以忽略类型imports:[vue,vue-router,pinia],dts:false}),Components({resolvers:[ElementPlusResolver()],dts:false})],resolve:{alias:{:fileURLToPath(newURL(./src,import.meta.url))}},server:{port:5173,open:true}})现在不需要import { ElButton } from element-plus页面直接写el‑button就生效ref/reactive 不用 import。第三节目录层级重构重点仿若依但优化结构❗原版若依 layout 放在/layoutviews 另外我们保持 layout 和 components同级不嵌套在 views 下面删除初始化自带无用文件最终 src 目录结构src ├── api # 接口请求函数 ├── assets # 静态资源 图片、css ├── components # 公共小组件和layout同级 ├── layout # 后台布局组件侧边栏、头部、主内容区仿若依layout ├── router # vue‑router路由 ├── pinia # pinia仓库 ├── mock # 本地mock模拟数据 ├── utils # 工具类request请求封装、auth、常量 ├── views # 业务页面 ├── App.vue └── main.js执行删除删除src/components/HelloWorld.vue删除src/views/About.vue、src/views/HomeView.vue清空App.vue、router/index.js后面重写。第四节环境变量分离开发 / 生产分开在项目根目录不是 src 下新建两个文件.env.development开发环境#.env.development VITE_APP_TITLEVue3‑Setup仿若依后台 # 是否开启mock模拟数据 true本地mockfalse请求真实后端接口 VITE_USE_MOCKtrue # 后端接口基础地址 VITE_API_BASE_URL/api.env.production生产环境#.env.production VITE_APP_TITLEVue3‑Setup仿若依后台 VITE_USE_MOCKfalse VITE_API_BASE_URLhttps://api.example.com使用方式代码中import.meta.env.VITE_USE_MOCK获取环境变量切换 mock / 真实接口只需要修改.env.development的VITE_USE_MOCK即可。第五节Axios 请求封装 utils/request.js新建src/utils/request.jsimport axios fromaxios// 创建axios实例constserviceaxios.create({baseURL:import.meta.env.VITE_API_BASE_URL,timeout:10000})// 请求拦截器service.interceptors.request.use(config{// 可以在这里携带tokenconsttokenlocalStorage.getItem(token)if(token){config.headers[Authorization]Bearer token}returnconfig},error{returnPromise.reject(error)})// 响应拦截器service.interceptors.response.use(response{returnresponse.data},error{console.error(请求错误,error)returnPromise.reject(error)})exportdefaultservice新建src/utils/auth.js简单 token 工具// token本地存储 export function getToken() { return localStorage.getItem(token) } export function setToken(token) { return localStorage.setItem(token, token) } export function removeToken() { return localStorage.removeItem(token) }第六节Mock 本地模拟数据支持开关切换目标当VITE_USE_MOCKtrue拦截请求返回本地假数据false 直接走真实 axios。不使用 vite‑mock‑plugin 插件配置复杂做简易 mock 适配适合学习。新建src/mock/index.js// mock模拟接口数据constmockData{// 登录接口/login:{code:200,msg:登录成功,data:{token:mock‑admin‑token‑123456}},// 获取用户信息/getUserInfo:{code:200,data:{username:admin,avatar:,roles:[admin]}}}// mock请求函数export functionmockRequest(url){returnnewPromise((resolve){setTimeout((){resolve(mockData[url])},300)})}新建src/api/login.js接口层实现 mock 和真实请求自动切换import request from/utils/requestimport{mockRequest}from/mockconstUSE_MOCKimport.meta.env.VITE_USE_MOCKtrue// 登录接口export functionloginApi(data){if(USE_MOCK){returnmockRequest(/login)}else{returnrequest({url:/login,method:post,data})}}// 获取用户信息export functiongetUserInfoApi(){if(USE_MOCK){returnmockRequest(/getUserInfo)}else{returnrequest({url:/getUserInfo,method:get})}}✅ 切换 mock 只需要修改环境变量业务 api 代码不用改动。第七节Pinia 状态仓库搭建新建src/pinia/user.js用户仓库import{defineStore}frompiniaimport{setToken,getToken,removeToken}from/utils/authimport{loginApi,getUserInfoApi}from/api/loginexportconstuseUserStoredefineStore(user,{state:()({token:getToken()||,userInfo:{}}),actions:{// 登录asynclogin(loginForm){constresawaitloginApi(loginForm)if(res.code200){this.tokenres.data.tokensetToken(res.data.token)}returnres},// 获取用户信息asyncgetUserInfo(){constresawaitgetUserInfoApi()this.userInfores.datareturnres},// 登出logout(){this.tokenthis.userInfo{}removeToken()}}})新建src/pinia/index.jsexport * from ./user第八节Vue‑Router4 路由配置仿若依路由登录页 Layout 布局嵌套路由layout 作为父路由组件子页面嵌套在 layout 内部显示。修改src/router/index.jsimport{createRouter,createWebHistory}fromvue-routerimport{getToken}from/utils/auth// 路由守卫没有token跳登录constrequireAuth(to,from){if(getToken()){returntrue}else{return/login}}constroutes[{path:/login,name:Login,component:()import(/views/login/index.vue)},{path:/,component:()import(/layout/index.vue),redirect:/dashboard,beforeEnter:requireAuth,children:[{path:dashboard,name:Dashboard,component:()import(/views/dashboard/index.vue),meta:{title:首页}}]},{path:/:pathMatch(.*)*,redirect:/}]constroutercreateRouter({history:createWebHistory(import.meta.env.BASE_URL),routes})exportdefaultrouter修改src/main.jsimport./assets/main.cssimport{createApp}fromvueimport{createPinia}frompiniaimport App from./App.vueimport router from./routerconstappcreateApp(App)app.use(createPinia())app.use(router)app.mount(#app)修改src/App.vuetemplaterouter-view//templatescript setup/script第九节Layout 布局组件和 components 同级 /layout仿若依后台骨架新建src/layout/index.vue后台主布局分为头部、侧边栏、内容区域templateel-container styleheight:100vh;!--侧边栏--el-aside width220pxstylebackground-color:#304156;div classlogoVue3‑Setup后台/divel-menudefault-active$route.pathbackground-color#304156text-color#fffactive-text-color#409effrouterel-menu-item index/dashboardtemplate #title首页/template/el-menu-item/el-menu/el-asideel-container!--顶部header--el-header stylebackground:#fff;border-bottom:1px solid #eee;display:flex;justify-content:flex-end;align-items:center;el-button clickhandleLogouttypetext退出登录/el-button/el-header!--主内容区域--el-main stylebackground:#f2f3f5;router-view/router-view/el-main/el-container/el-container/templatescript setupimport{useUserStore}from/pinia/userimport{useRouter}fromvue-routerconstuserStoreuseUserStore()constrouteruseRouter()consthandleLogout(){userStore.logout()router.push(/login)}/scriptstyle scoped.logo{height:50px;line-height:50px;color:#fff;text-align:center;font-size:16px;}/style第十节编写登录页面 views/login/index.vuetemplatediv classlogin-containerel-card stylewidth:420px;h2 styletext-align:center;margin-bottom:20px;系统登录/h2el-form refloginFormRef:modelloginFormlabel-width0el-form-item propusernameel-input v-modelloginForm.usernameplaceholder账号/el-input/el-form-itemel-form-item proppasswordel-input v-modelloginForm.passwordtypepasswordplaceholder密码/el-input/el-form-itemel-form-itemel-button typeprimarystylewidth:100%clickhandleLogin登录/el-button/el-form-item/el-form/el-card/div/templatescript setupimport{reactive}fromvueimport{useUserStore}from/pinia/userimport{useRouter}fromvue-routerconstuserStoreuseUserStore()constrouteruseRouter()constloginFormreactive({username:admin,password:123456})consthandleLoginasync(){await userStore.login(loginForm)await userStore.getUserInfo()router.push(/dashboard)}/scriptstyle scoped.login-container{height:100vh;background:#283443;display:flex;justify-content:center;align-items:center;}/style第十一节首页页面 views/dashboard/index.vuetemplateel-cardh2欢迎来到后台管理系统/h2pMock开关状态{{USE_MOCK}}/pp当前用户{{userStore.userInfo.username}}/p/el-card/templatescript setupimport{useUserStore}from/pinia/userconstUSE_MOCKimport.meta.env.VITE_USE_MOCKconstuserStoreuseUserStore()/script第十二节运行测试、切换 Mock / 真实接口pnpm dev访问http://localhost:5173/#/login账号 admin密码随便填mock 环境直接登录成功跳首页。切换真实网络请求修改.env.developmentVITE_USE_MOCKfalse此时登录就会走 axios请求后端/api/login接口。vite 会自动读取 env 文件修改后重启 dev 服务生效。后续拓展方向模仿若依剩下功能动态路由、菜单从后端返回菜单渲染侧边栏 el‑menutags‑view 多标签页组件放到/componentssvg 图标封装权限控制按钮指令全局错误处理、页面分页封装组件封装文件上传、表格 CRUD 通用页面模板关键改造对比原版若依表格若依 vue2/vue3 原版本项目优化选项式 setup 混合全部script setup组合式 JSlayout 下嵌套很多业务组件layout 和 components同级职责清晰mock 深度耦合插件环境变量一键开关 mock / 真实接口代码侵入小环境变量写死代码.env.development.env.production分离全局 this 大量使用全部 pinia/composition api无 thisElement‑Plus 完整引入unplugin 自动按需导入打包体积小常见坑修改.env.*文件必须重启 vite 开发服务器否则变量不更新unplugin 自动导入template 直接用 el 组件script 里 ref/reactive 不需要 importimport.meta.envvite 环境变量必须以VITE_开头否则读不到mock 模式打开时不会走 axios关闭 mock 才会触发代理。

相关新闻