news 2026/8/28 5:47:10

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(一)pnpm+Vue3 JS Setup 组合式 仿若依后台管理系统 手把手搭建

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

技术栈:pnpm + Vue3 (JavaScript) +<script setup>+ Vue‑Router4 + Pinia + Axios + Element Plus (unplugin 自动按需导入)
改造点:

  1. 全部使用 Setup 组合式语法,摒弃选项式
  2. 目录优化:layoutcomponents同级,不和 views 嵌套
  3. 分离环境变量:.env.development/.env.production
  4. 支持mock 本地模拟数据 / 真实网络接口一键切换
  5. 修正原版若依部分不合理目录、全局变量写法
  6. pnpm create vue@latest从零开始,分节操作,复制代码即可跑通

第一节:初始化 Vue3 项目

1.1 前置条件

已安装 Node.js ≥18 版本,pnpm 已安装

# 没有pnpm先安装 npm install-g pnpm

1.2 创建 vue 项目

pnpm create vue@latest

交互式选择,严格按照下面选

✔ 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 → Yes
cd 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-import
  • unplugin-auto-import:自动导入 vue、pinia、router api,不用每次写import ref,computed
  • unplugin-vue-components:Element Plus 组件自动按需导入,无需手动 import 组件

2.2 修改 vite.config.js

替换全部内容

import{defineConfig}from'vite'import vue from'@vitejs/plugin-vue'import{fileURLToPath,URL}from'node:url'import AutoImport from'unplugin-auto-import/vite'import Components from'unplugin-vue-components/vite'import{ElementPlusResolver}from 'unplugin-vue-components/resolvers'// https://vitejs.dev/config/exportdefaultdefineConfig({plugins:[vue(),AutoImport({resolvers:[ElementPlusResolver()],// 自动生成auto‑imports.d.ts,js项目可以忽略类型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 放在@/layout,views 另外;我们保持 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.vuesrc/views/HomeView.vue
    清空App.vuerouter/index.js,后面重写。

第四节:环境变量分离(开发 / 生产分开)

在项目根目录(不是 src 下)新建两个文件

.env.development开发环境

#.env.development VITE_APP_TITLE=Vue3‑Setup仿若依后台 # 是否开启mock模拟数据 true=本地mock;false=请求真实后端接口 VITE_USE_MOCK=true # 后端接口基础地址 VITE_API_BASE_URL='/api'

.env.production生产环境

#.env.production VITE_APP_TITLE=Vue3‑Setup仿若依后台 VITE_USE_MOCK=false VITE_API_BASE_URL='https://api.example.com'

使用方式:代码中import.meta.env.VITE_USE_MOCK获取环境变量
切换 mock / 真实接口,只需要修改.env.developmentVITE_USE_MOCK即可。


第五节:Axios 请求封装 utils/request.js

新建src/utils/request.js

import axios from'axios'// 创建axios实例constservice=axios.create({baseURL:import.meta.env.VITE_API_BASE_URL,timeout:10000})// 请求拦截器service.interceptors.request.use(config=>{// 可以在这里携带tokenconsttoken=localStorage.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_MOCK=true,拦截请求返回本地假数据;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/request'import{mockRequest}from'@/mock'constUSE_MOCK=import.meta.env.VITE_USE_MOCK==='true'// 登录接口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}from'pinia'import{setToken,getToken,removeToken}from'@/utils/auth'import{loginApi,getUserInfoApi}from'@/api/login'exportconstuseUserStore=defineStore('user',{state:()=>({token:getToken()||'',userInfo:{}}),actions:{// 登录asynclogin(loginForm){constres=awaitloginApi(loginForm)if(res.code===200){this.token=res.data.tokensetToken(res.data.token)}returnres},// 获取用户信息asyncgetUserInfo(){constres=awaitgetUserInfoApi()this.userInfo=res.datareturnres},// 登出logout(){this.token=''this.userInfo={}removeToken()}}})

新建src/pinia/index.js

export * from './user'

第八节:Vue‑Router4 路由配置(仿若依路由:登录页 + Layout 布局嵌套路由)

layout 作为父路由组件,子页面嵌套在 layout 内部显示。

修改src/router/index.js

import{createRouter,createWebHistory}from'vue-router'import{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:'/'}]constrouter=createRouter({history:createWebHistory(import.meta.env.BASE_URL),routes})exportdefaultrouter

修改src/main.js

import'./assets/main.css'import{createApp}from'vue'import{createPinia}from'pinia'import App from'./App.vue'import router from'./router'constapp=createApp(App)app.use(createPinia())app.use(router)app.mount('#app')

修改src/App.vue

<template><router-view/></template><script setup></script>

第九节:Layout 布局组件(和 components 同级 @/layout)仿若依后台骨架

新建src/layout/index.vue后台主布局,分为头部、侧边栏、内容区域

<template><el-container style="height:100vh;"><!--侧边栏--><el-aside width="220px"style="background-color:#304156;"><div class="logo">Vue3‑Setup后台</div><el-menudefault-active="$route.path"background-color="#304156"text-color="#fff"active-text-color="#409eff"router><el-menu-item index="/dashboard"><template #title>首页</template></el-menu-item></el-menu></el-aside><el-container><!--顶部header--><el-header style="background:#fff;border-bottom:1px solid #eee;display:flex;justify-content:flex-end;align-items:center;"><el-button @click="handleLogout"type="text">退出登录</el-button></el-header><!--主内容区域--><el-main style="background:#f2f3f5;"><router-view></router-view></el-main></el-container></el-container></template><script setup>import{useUserStore}from'@/pinia/user'import{useRouter}from'vue-router'constuserStore=useUserStore()constrouter=useRouter()consthandleLogout=()=>{userStore.logout()router.push('/login')}</script><style scoped>.logo{height:50px;line-height:50px;color:#fff;text-align:center;font-size:16px;}</style>

第十节:编写登录页面 views/login/index.vue

<template><div class="login-container"><el-card style="width:420px;"><h2 style="text-align:center;margin-bottom:20px;">系统登录</h2><el-form ref="loginFormRef":model="loginForm"label-width="0"><el-form-item prop="username"><el-input v-model="loginForm.username"placeholder="账号"></el-input></el-form-item><el-form-item prop="password"><el-input v-model="loginForm.password"type="password"placeholder="密码"></el-input></el-form-item><el-form-item><el-button type="primary"style="width:100%"@click="handleLogin">登录</el-button></el-form-item></el-form></el-card></div></template><script setup>import{reactive}from'vue'import{useUserStore}from'@/pinia/user'import{useRouter}from'vue-router'constuserStore=useUserStore()constrouter=useRouter()constloginForm=reactive({username:'admin',password:'123456'})consthandleLogin=async()=>{await userStore.login(loginForm)await userStore.getUserInfo()router.push('/dashboard')}</script><style scoped>.login-container{height:100vh;background:#283443;display:flex;justify-content:center;align-items:center;}</style>

第十一节:首页页面 views/dashboard/index.vue

<template><el-card><h2>欢迎来到后台管理系统</h2><p>Mock开关状态:{{USE_MOCK}}</p><p>当前用户:{{userStore.userInfo.username}}</p></el-card></template><script setup>import{useUserStore}from'@/pinia/user'constUSE_MOCK=import.meta.env.VITE_USE_MOCKconstuserStore=useUserStore()</script>

第十二节:运行测试、切换 Mock / 真实接口

pnpm dev
  1. 访问http://localhost:5173/#/login
    账号 admin,密码随便填,mock 环境直接登录成功跳首页。
  2. 切换真实网络请求:修改.env.development
VITE_USE_MOCK=false

此时登录就会走 axios,请求后端/api/login接口。

vite 会自动读取 env 文件,修改后重启 dev 服务生效


后续拓展方向(模仿若依剩下功能)

  1. 动态路由、菜单(从后端返回菜单渲染侧边栏 el‑menu)
  2. tags‑view 多标签页组件,放到@/components
  3. svg 图标封装
  4. 权限控制按钮指令
  5. 全局错误处理、页面分页封装组件
  6. 封装文件上传、表格 CRUD 通用页面模板

关键改造对比原版若依

表格

若依 vue2/vue3 原版本项目优化
选项式 + setup 混合全部<script setup>组合式 JS
layout 下嵌套很多业务组件layout 和 components同级,职责清晰
mock 深度耦合插件环境变量一键开关 mock / 真实接口,代码侵入小
环境变量写死代码.env.development.env.production分离
全局 this 大量使用全部 pinia/composition api,无 this
Element‑Plus 完整引入unplugin 自动按需导入,打包体积小

常见坑

  1. 修改.env.*文件必须重启 vite 开发服务器,否则变量不更新
  2. unplugin 自动导入:template 直接用 el 组件,script 里 ref/reactive 不需要 import
  3. import.meta.envvite 环境变量,必须以VITE_开头,否则读不到
  4. mock 模式打开时不会走 axios,关闭 mock 才会触发代理。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 5:46:21

XopProtector:开源 Android APK 加固项目对比,为什么值得重点关注?

开源 Android APK 加固项目横向对比 Android 开源 APK 加固项目并不少&#xff0c;但不同项目的技术路线和能力覆盖范围差别很大。 目前比较有代表性的开源项目包括&#xff1a; dpt-shellnmmpJiaguXopProtector 如果单纯从“有没有 DEX 加密”来看&#xff0c;它们似乎差别…

作者头像 李华
网站建设 2026/8/28 5:45:47

从芯片到模型再到硬件:端侧AI设备如何走向组合创新

看到“小米玄戒 O100 原型机、AI Cube 真机首秀”这个消息时&#xff0c;我第一反应不是去查跑分&#xff0c;而是想先弄清楚一个问题&#xff1a;这到底是一颗新芯片&#xff0c;一个新硬件&#xff0c;还是一条新链路&#xff1f;过去几年&#xff0c;我们看 AI 硬件已经形成…

作者头像 李华
网站建设 2026/8/28 5:45:06

MATLAB拟合算法实战:从最小二乘原理到过拟合诊断

1. 项目概述&#xff1a;从“拟合”到“清风数模课”的实战价值最近在整理资料&#xff0c;翻到了几年前带学生参加数学建模竞赛时&#xff0c;自己整理的一套关于“拟合算法”的讲义。当时为了让学生们快速上手&#xff0c;避开那些晦涩的数学推导&#xff0c;直接抓住核心思想…

作者头像 李华
网站建设 2026/8/28 5:44:07

线程局部存储:TLS(Thread Local Storage)

当多个线程需要访问同一个名称的全局或静态变量&#xff0c;但每个线程必须维护自己独立的变量副本且互不干扰时&#xff0c;使用 TLS&#xff08;Thread Local Storage&#xff0c;线程局部存储&#xff09;。如图&#xff0c;每个线程在 TLS 中维护独立的数据副本。从 C11 标…

作者头像 李华
网站建设 2026/8/28 5:44:00

量化交易策略全流程解析:从数据分析、模型构建到回测评估

1. 项目概述&#xff1a;一次竞赛题目的深度拆解之旅每年年初&#xff0c;对于全球数以万计的数模爱好者来说&#xff0c;美国大学生数学建模竞赛&#xff08;MCM/ICM&#xff09;的赛题发布都是一场盛事。2022年的C题&#xff0c;以其独特的背景和开放性的要求&#xff0c;再次…

作者头像 李华
网站建设 2026/8/28 5:43:45

蓝桥杯国赛真题解析:纯质数算法优化与Python实现

1. 项目概述&#xff1a;从一道国赛真题看质数算法的实战优化最近在复盘蓝桥杯的历年真题&#xff0c;第十二届国赛的这道“纯质数”题目让我印象挺深。它表面上是一道经典的数论问题&#xff0c;核心是筛选质数&#xff0c;但题目给出的数据范围和“纯质数”这个特殊定义&…

作者头像 李华