【VUE】RuoYi-Vue3项目结构的分析
- 1. 项目地址
- 2. RuoYi-Vue3项目结构
- 2.1 整体结构
- 2.2 package.json
- 2.2.1 🧾 基本信息
- 2.2.2 🔧 脚本命令(scripts)
- 2.2.3 🌍 仓库信息
- 2.2.4 📦 项目依赖(dependencies)
- 2.2.5 开发依赖(devDependencies)
- 2.2.6 🔧 scripts 字段详解
- 2.2.6.1 🚀 dev: 开发模式启动
- 🔧 示例:
- 本质上是运行:
- 2.2.6.2 🏗️ build:prod: 构建生产环境
- 🔧 示例:
- 2.2.6.3 build:stage: 构建预发布环境
- 🔧 示例:
- 2.2.6.4 👀 preview: 本地预览构建结果
- 🔧 步骤:
- 🧩 补充:环境变量文件示例
- 2.2.7 ✅ 总结
- 2.3 env文件
- 2.3.1🔹 VITE_APP_TITLE
- 2.3.2 🔹 VITE_APP_ENV
- 2.3.3 🔹 VITE_APP_BASE_API
- 2.4 index.html
- 2.4.1 🧱 基本结构
- 2.4.2 🔧 `<head>` 区域说明
- 2.4.3 🎨 加载动画样式说明
- 2.4.4 🚀 Vue 应用入口加载
- 📝 总结功能
- 2.5 vite.config.js
- 2.5.1 🔧 文件头部
- 📌 自定义 mode 怎么办?
- 2.5.2 🧩 主体配置(defineConfig)
- 2.5.3 📌 base 配置
- 2.5.3 🔌 plugins 插件配置
- 2.5.4 🧭 resolve 路径配置
- 2.5.5 🌐 server 开发服务器配置
- 2.5.6 🎨 css 配置(PostCSS 处理)
- 2.5.7 ✅ 总结一下
- 2.6 main.js
- 2.6.1 📝 代码结构解析:
- 2.6.1.1 创建 Vue 应用
- 2.6.1.2 引入第三方库和插件
- 2.6.1.3 引入全局样式
- 2.6.1.4 引入应用所需的功能模块
- 2.6.1.5 引入全局组件
- 2.6.1.6 全局方法挂载
- 2.6.1.7 全局组件注册
- 2.6.1.8 路由、状态管理、插件注册
- 2.6.1.9 注册自定义指令
- 2.6.1.10 ElementPlus 配置
- 2.6.1.11 挂载应用
- 2.6.1.12 📚 小结
- 2.7 settings.js
- 2.8 App.vue
- 2.8.1 模板部分` (<template>)`
- 2.8.2 脚本部分 `(<script setup>)`
- 2.8.3 整体结构与功能
- 2.9 permission.js
- 3. RuoYi-Vue3 api文件夹下的内容
1. 项目地址
见官方文档 https://doc.ruoyi.vip/ruoyi-vue/document/xmkz.html
2. RuoYi-Vue3项目结构
2.1 整体结构
2.2 package.json
{
"name": "ruoyi",
"version": "3.8.9",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
"type": "module",
"scripts": {
"dev": "vite",
"build:prod": "vite build",
"build:stage": "vite build --mode staging",
"preview": "vite preview"
},
"repository": {
"type": "git",
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
},
"dependencies": {
"@element-plus/icons-vue": "2.3.1",
"@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.11.0",
"axios": "0.28.1",
"clipboard": "2.0.11",
"echarts": "5.5.1",
"element-plus": "2.7.6",
"file-saver": "2.0.5",
"fuse.js": "6.6.2",
"js-beautify": "1.14.11",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"nprogress": "0.2.0",
"pinia": "2.1.7",
"splitpanes": "3.1.5",
"vue": "3.4.31",
"vue-cropper": "1.1.1",
"vue-router": "4.4.0",
"vuedraggable": "4.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "5.0.5",
"sass": "1.77.5",
"unplugin-auto-import": "0.17.6",
"unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "5.3.2",
"vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1"
}
}
2.2.1 🧾 基本信息
"name": "ruoyi",
"version": "3.8.9",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
"type": "module",
2.2.2 🔧 脚本命令(scripts)
"scripts": {
"dev": "vite",
"build:prod": "vite build",
"build:stage": "vite build --mode staging",
"preview": "vite preview"
}
2.2.3 🌍 仓库信息
"repository": {
"type": "git",
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
}
指向源码托管的 Git 仓库(Gitee 上的 RuoYi-Vue 项目)。
2.2.4 📦 项目依赖(dependencies)
这些是运行时依赖,项目运行时需要用到的库:
2.2.5 开发依赖(devDependencies)
这些是开发时用的工具和插件:
2.2.6 🔧 scripts 字段详解
"scripts": {
"dev": "vite",
"build:prod": "vite build",
"build:stage": "vite build --mode staging",
"preview": "vite preview"
}
这些命令你可以通过终端运行,比如:
npm run dev
# 或者
yarn dev
2.2.6.1 🚀 dev: 开发模式启动
"dev": "vite"
- 启动开发服务器
- 默认监听 http://localhost:5173(可配置)
- 实时热更新(HMR)
- 使用 .env.development 配置文件(如果存在)
🔧 示例:
npm run dev
本质上是运行:
vite
2.2.6.2 🏗️ build:prod: 构建生产环境
"build:prod": "vite build"
-
打包生成生产环境的静态文件
-
输出目录:默认是 dist/
-
使用 .env.production 配置文件
-
会自动做:
-
Tree Shaking(移除无用代码)
-
压缩(JS/CSS/html)
-
资源版本化(加 hash)
🔧 示例:
npm run build:prod
📁 构建完成后,你可以部署 dist/ 到 Nginx、Apache、Node 服务器等。
2.2.6.3 build:stage: 构建预发布环境
"build:stage": "vite build --mode staging"
- 用于 预发布环境 构建
- 使用 .env.staging 环境变量文件
- 可以用于连接测试服务器或 UAT 环境
🔧 示例:
npm run build:stage
注意:Vite 会根据 --mode 参数加载对应.env.[mode]
配置文件,例如:
.env.staging
.env.production
2.2.6.4 👀 preview: 本地预览构建结果
"preview": "vite preview"
- 用来本地 预览打包后的项目
- 启动一个本地静态服务器,访问打包结果
- 不再是开发服务器!是查看最终构建效果。
🔧 步骤:
npm run build:prod
npm run preview
默认访问地址:http://localhost:4173
🧩 补充:环境变量文件示例
你可以在根目录创建多个 .env 文件来支持不同环境:
.env.development # 开发环境
.env.staging # 预发布环境
.env.production # 生产环境
这些文件里可以定义变量,比如:
VITE_APP_TITLE=RuoYi 管理后台
VITE_BASE_API=https://api.example.com
在代码中这样访问:
import.meta.env.VITE_APP_TITLE
2.2.7 ✅ 总结
这个 package.json 是 Vue 3 企业后台管理系统(若依前端)的核心配置文件,结合了:
- Vue 3 + Vite 的现代构建架构;
- Element Plus 提供强大的 UI 组件;
- Pinia 管理状态;
- 多种工具库(图表、剪贴板、富文本、拖拽等)提升开发效率;
- Vite 插件自动化构建优化。
2.3 env文件
.env.development
# 页面标题
VITE_APP_TITLE = 若依管理系统
# 开发环境配置
VITE_APP_ENV = 'development'
# 若依管理系统/开发环境
VITE_APP_BASE_API = '/dev-api'
2.3.1🔹 VITE_APP_TITLE
VITE_APP_TITLE = 若依管理系统
- 用于设置项目标题
- 可在
index.html
或 Vue 页面中使用,比如动态修改<title>
在 HTML 中使用(通过 Vite 的 HTML 插值语法):
<title><%= VITE_APP_TITLE %></title>
或者在 JS 中使用:
document.title = import.meta.env.VITE_APP_TITLE;
2.3.2 🔹 VITE_APP_ENV
VITE_APP_ENV = 'development'
- 表示当前运行的环境(开发、测试、生产等)
- 通常用于代码中进行环境判断:
if (import.meta.env.VITE_APP_ENV === 'development') {
console.log('当前是开发环境');
}
⚠️ 注意:值中用的引号 ‘development’ 会被作为字符串一部分保留。更推荐写法是不加引号:
VITE_APP_ENV=development
2.3.3 🔹 VITE_APP_BASE_API
VITE_APP_BASE_API = '/dev-api'
- 设置请求 API 的基础路径
- 会用于 axios 或 fetch 等接口请求中
假设你这样配置 axios:
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
});
那么访问 /api/user/list
,实际发送的请求就是:
http://localhost:5173/dev-api/user/list
这通常结合 Vite 的代理配置 实现跨域转发,比如在 vite.config.js
中:
server: {
proxy: {
'/dev-api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: path => path.replace(/^\/dev-api/, '')
}
}
}
这样前端写 /dev-api/user/list
,Vite 会自动代理请求到后端 /user/list
接口。
2.4 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<title>若依管理系统</title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
}
.chromeframe {
margin: 0.2em 0;
background: #ccc;
color: #000;
padding: 0.2em 0;
}
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #FFF;
-webkit-animation: spin 2s linear infinite;
-ms-animation: spin 2s linear infinite;
-moz-animation: spin 2s linear infinite;
-o-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
z-index: 1001;
}
#loader:before {
content: "";
position: absolute;
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #FFF;
-webkit-animation: spin 3s linear infinite;
-moz-animation: spin 3s linear infinite;
-o-animation: spin 3s linear infinite;
-ms-animation: spin 3s linear infinite;
animation: spin 3s linear infinite;
}
#loader:after {
content: "";
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #FFF;
-moz-animation: spin 1.5s linear infinite;
-o-animation: spin 1.5s linear infinite;
-ms-animation: spin 1.5s linear infinite;
-webkit-animation: spin 1.5s linear infinite;
animation: spin 1.5s linear infinite;
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
-ms-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#loader-wrapper .loader-section {
position: fixed;
top: 0;
width: 51%;
height: 100%;
background: #7171C6;
z-index: 1000;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
#loader-wrapper .loader-section.section-left {
left: 0;
}
#loader-wrapper .loader-section.section-right {
right: 0;
}
.loaded #loader-wrapper .loader-section.section-left {
-webkit-transform: translateX(-100%);
-ms-transform: translateX(-100%);
transform: translateX(-100%);
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
}
.loaded #loader-wrapper .loader-section.section-right {
-webkit-transform: translateX(100%);
-ms-transform: translateX(100%);
transform: translateX(100%);
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
}
.loaded #loader {
opacity: 0;
-webkit-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
}
.loaded #loader-wrapper {
visibility: hidden;
-webkit-transform: translateY(-100%);
-ms-transform: translateY(-100%);
transform: translateY(-100%);
-webkit-transition: all 0.3s 1s ease-out;
transition: all 0.3s 1s ease-out;
}
.no-js #loader-wrapper {
display: none;
}
.no-js h1 {
color: #222222;
}
#loader-wrapper .load_title {
font-family: 'Open Sans';
color: #FFF;
font-size: 19px;
width: 100%;
text-align: center;
z-index: 9999999999999;
position: absolute;
top: 60%;
opacity: 1;
line-height: 30px;
}
#loader-wrapper .load_title span {
font-weight: normal;
font-style: italic;
font-size: 13px;
color: #FFF;
opacity: 0.5;
}
</style>
</head>
<body>
<div id="app">
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载系统资源,请耐心等待</div>
</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
index.html 是 Vue3 + Vite 项目的入口 HTML 文件,用于 定义页面结构、加载样式、初始化页面,并最终挂载 Vue 应用。 它是 Vite 应用的基础模板,加载完毕后会将 #app
替换为渲染好的 Vue 内容。
2.4.1 🧱 基本结构
<!DOCTYPE html>
<html>
<head> ... </head>
<body>
<div id="app"> ... </div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
<!DOCTYPE html>
:声明文档类型为 HTML5。<div id="app">
:Vue 应用的挂载点,对应 main.js 中的createApp(App).mount('#app')
。<script type="module">
:使用 ES Module 加载入口文件src/main.js
。
2.4.2 🔧 <head>
区域说明
✅ 页面设置相关
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="/favicon.ico">
<title>若依管理系统</title>
- 设置页面字符编码、兼容性、渲染方式。
<meta viewport>
用于移动端响应式适配。<title>
设置网页标题(可以用环境变量动态设置)。favicon.ico
设置浏览器 tab 图标。
2.4.3 🎨 加载动画样式说明
整个 <style>
块实现了一个 加载中的页面动画效果,在 Vue 内容加载前提供视觉反馈。
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载系统资源,请耐心等待</div>
</div>
这些元素组合在一起构成了一个炫酷的加载动画,包括:
样式细节
#loader
是核心旋转圈,通过多个:before、:after
层实现三层圈圈动画。.loaded
类会触发消失动画,表示 Vue 应用加载完成。.no-js
是备用样式:如果 JS 不可用,隐藏 loading。
2.4.4 🚀 Vue 应用入口加载
<script type="module" src="/src/main.js"></script>
- 启动 Vue 应用的入口文件。
- 一般内容类似于:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(router).use(store).mount('#app')
加载完成后,会替换掉 <div id="app">
内容,把整个 Vue 项目渲染进去。
📝 总结功能
2.5 vite.config.js
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd())
const { VITE_APP_ENV } = env
return {
// 部署生产环境和开发环境下的URL。
// 默认情况下,vite 会假设你的应用是被部署在一个域名的根路径上
// 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
base: VITE_APP_ENV === 'production' ? '/' : '/',
plugins: createVitePlugins(env, command === 'build'),
resolve: {
// https://cn.vitejs.dev/config/#resolve-alias
alias: {
// 设置路径
'~': path.resolve(__dirname, './'),
// 设置别名
'@': path.resolve(__dirname, './src')
},
// https://cn.vitejs.dev/config/#resolve-extensions
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
// vite 相关配置
server: {
port: 80,
host: true,
open: true,
proxy: {
// https://cn.vitejs.dev/config/#server-proxy
'/dev-api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
}
}
},
//fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file
css: {
postcss: {
plugins: [
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
atRule.remove();
}
}
}
}
]
}
}
}
})
这份 vite.config.js
是 Vite 项目的核心配置文件,它配置了构建、开发服务器、路径别名、插件、代理、CSS处理等行为。 这个文件是 若依管理系统 Vue3 + Vite 版本 中的重要组成部分。
2.5.1 🔧 文件头部
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
- defineConfig:Vite 提供的辅助函数,可以获得类型提示。
- loadEnv(mode, root):根据当前模式加载
.env.[mode]
文件内容。 loadEnv 是 Vite 官方提供的函数,不是你自己写的,也不是第三方包,它来自于 vite 包本身。执行npm run dev
那么mode === ‘development’
vite 命令(开发模式) ⇒ mode = ‘development’
vite build 命令(生产构建) ⇒ mode = ‘production’ - path:Node.js 内置模块,用于路径拼接。
- createVitePlugins:引入封装好的插件函数(如 AutoImport、SVG 图标、压缩等)。
📌 自定义 mode 怎么办?
如果你想用别的环境变量文件,比如 .env.staging
,你可以这样写:
vite --mode staging
或者:
"scripts": {
"build:stage": "vite build --mode staging"
}
对应的执行命令就是
npm run build:stage
2.5.2 🧩 主体配置(defineConfig)
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd()) // 加载环境变量
const { VITE_APP_ENV } = env
- mode:当前环境(如 development、production)。
- command:当前操作(如 serve 或 build)。
- 使用 loadEnv() 加载
.env.*
文件内容并解构出VITE_APP_ENV
。
2.5.3 📌 base 配置
base: VITE_APP_ENV === 'production' ? '/' : '/',
- 设置打包后资源的 公共路径
- 如果部署在子目录下,这里应该设置成 /子目录名/
- 若依项目默认设置为根路径 /
2.5.3 🔌 plugins 插件配置
plugins: createVitePlugins(env, command === 'build'),
- 使用封装好的插件加载器,传入环境变量和是否是构建命令
- 常见插件可能包括:
unplugin-auto-import 自动导入
vite-plugin-svg-icons SVG 图标支持
vite-plugin-compression gzip 压缩等
2.5.4 🧭 resolve 路径配置
resolve: {
alias: {
'~': path.resolve(__dirname, './'),
'@': path.resolve(__dirname, './src')
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
}
设置路径别名:
~
代表根路径@ 代表 src/ 目录
,方便引用文件- extensions:导入文件时可省略的后缀名(默认已经包含大部分常用的)
2.5.5 🌐 server 开发服务器配置
server: {
port: 80,
host: true,
open: true,
proxy: {
'/dev-api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
}
}
}
- port: 80:开发服务器端口,设置为 80
- host: true:支持使用 IP 访问(0.0.0.0)
- open: true:自动打开浏览器
- proxy:配置代理,解决开发环境跨域问题
- 请求 /dev-api/xxx 会被代理到 http://localhost:8080/xxx
2.5.6 🎨 css 配置(PostCSS 处理)
css: {
postcss: {
plugins: [
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
atRule.remove()
}
}
}
}
]
}
}
- 作用:去除 CSS 中多余的
@charset
规则,避免构建时出现警告或错误:
warning: "@charset" must be the first rule in the file
- 些插件(比如 element-plus 的样式)可能导致这个问题,所以主动清理。
2.5.7 ✅ 总结一下
2.6 main.js
import { createApp } from 'vue'
import Cookies from 'js-cookie'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import '@/assets/styles/index.scss' // global css
import App from './App'
import store from './store'
import router from './router'
import directive from './directive' // directive
// 注册指令
import plugins from './plugins' // plugins
import { download } from '@/utils/request'
// svg图标
import 'virtual:svg-icons-register'
import SvgIcon from '@/components/SvgIcon'
import elementIcons from '@/components/SvgIcon/svgicon'
import './permission' // permission control
import { useDict } from '@/utils/dict'
import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi'
// 分页组件
import Pagination from '@/components/Pagination'
// 自定义表格工具组件
import RightToolbar from '@/components/RightToolbar'
// 富文本组件
import Editor from "@/components/Editor"
// 文件上传组件
import FileUpload from "@/components/FileUpload"
// 图片上传组件
import ImageUpload from "@/components/ImageUpload"
// 图片预览组件
import ImagePreview from "@/components/ImagePreview"
// 字典标签组件
import DictTag from '@/components/DictTag'
const app = createApp(App)
// 全局方法挂载
app.config.globalProperties.useDict = useDict
app.config.globalProperties.download = download
app.config.globalProperties.parseTime = parseTime
app.config.globalProperties.resetForm = resetForm
app.config.globalProperties.handleTree = handleTree
app.config.globalProperties.addDateRange = addDateRange
app.config.globalProperties.selectDictLabel = selectDictLabel
app.config.globalProperties.selectDictLabels = selectDictLabels
// 全局组件挂载
app.component('DictTag', DictTag)
app.component('Pagination', Pagination)
app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar)
app.component('Editor', Editor)
app.use(router)
app.use(store)
app.use(plugins)
app.use(elementIcons)
app.component('svg-icon', SvgIcon)
directive(app)
// 使用element-plus 并且设置全局的大小
app.use(ElementPlus, {
locale: locale,
// 支持 large、default、small
size: Cookies.get('size') || 'default'
})
app.mount('#app')
2.6.1 📝 代码结构解析:
2.6.1.1 创建 Vue 应用
import { createApp } from 'vue'
const app = createApp(App)
- createApp 是 Vue3 中用来创建应用实例的函数。
- App 是根组件,通常是 src/App.vue,它是整个应用的起始点。
2.6.1.2 引入第三方库和插件
import Cookies from 'js-cookie'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
- Cookies:用于管理 cookies,例如获取当前主题、界面大小等。
- ElementPlus:UI 组件库,提供丰富的组件和样式,支持主题、国际化等功能。
- 通过 import 加载了 ElementPlus 的样式以及中文语言包。
2.6.1.3 引入全局样式
import '@/assets/styles/index.scss' // global css
- 这行代码引入了全局的样式文件,通常是用来定义应用级别的样式。
2.6.1.4 引入应用所需的功能模块
import store from './store'
import router from './router'
import directive from './directive' // directive
import plugins from './plugins' // plugins
import { download } from '@/utils/request'
import './permission' // permission control
- store:Vuex 的状态管理(假设应用中使用了 Vuex)。
- router:Vue Router 路由配置。
- directive:自定义指令。
- plugins:应用的插件,如全局功能的注册(如事件总线等)。
- download:可能是封装好的下载方法,用于下载文件等。
2.6.1.5 引入全局组件
import SvgIcon from '@/components/SvgIcon'
import Pagination from '@/components/Pagination'
import RightToolbar from '@/components/RightToolbar'
import Editor from "@/components/Editor"
import FileUpload from "@/components/FileUpload"
import ImageUpload from "@/components/ImageUpload"
import ImagePreview from "@/components/ImagePreview"
import DictTag from '@/components/DictTag'
- 引入了一些自定义的全局组件,例如分页、富文本、文件上传、图片上传、字典标签等组件。
2.6.1.6 全局方法挂载
app.config.globalProperties.useDict = useDict
app.config.globalProperties.download = download
app.config.globalProperties.parseTime = parseTime
app.config.globalProperties.resetForm = resetForm
app.config.globalProperties.handleTree = handleTree
app.config.globalProperties.addDateRange = addDateRange
app.config.globalProperties.selectDictLabel = selectDictLabel
app.config.globalProperties.selectDictLabels = selectDictLabels
- 将一些工具函数挂载到 Vue 应用的全局属性上,方便在任何组件中访问。例如,useDict 是处理字典标签的方法,download 是下载方法等。
2.6.1.7 全局组件注册
app.component('DictTag', DictTag)
app.component('Pagination', Pagination)
app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar)
app.component('Editor', Editor)
- 通过 app.component 注册全局组件,这样在整个应用中可以直接使用这些组件,而无需在每个单独的组件中引入。
2.6.1.8 路由、状态管理、插件注册
app.use(router)
app.use(store)
app.use(plugins)
app.use(elementIcons)
app.component('svg-icon', SvgIcon)
- app.use(router):注册路由,所有页面的导航和路由逻辑都通过 Vue Router 进行。
- app.use(store):注册 Vuex 状态管理,管理整个应用的状态。
- app.use(plugins):注册自定义插件(如应用的全局功能、插件等)。
- app.component(‘svg-icon’, SvgIcon):注册 SvgIcon 作为全局组件,以便在任何地方使用。
2.6.1.9 注册自定义指令
directive(app)
- directive 函数用于注册应用中的自定义指令。这些指令可以在整个项目中复用。
2.6.1.10 ElementPlus 配置
app.use(ElementPlus, {
locale: locale,
size: Cookies.get('size') || 'default'
})
- 通过 app.use(ElementPlus) 安装 ElementPlus UI 组件库,并配置语言和大小。
- 默认的界面大小是从 Cookies 中获取的,如果没有设置则使用 ‘default’。
2.6.1.11 挂载应用
- 最后,应用会被挂载到 HTML 中的 #app 元素上,表示 Vue 实例已经成功启动并渲染。
2.6.1.12 📚 小结
- main.js 主要是 Vue 3 应用的初始化文件,涉及到全局插件、组件、方法的注册和配置。
- 核心流程是:创建 Vue 应用 → 挂载全局资源(如路由、状态管理、UI 组件等) → 启动应用。
2.7 settings.js
settings.js
是一个配置文件,通常用于 Vue.js 或其他前端应用中, 集中管理一些全局的应用设置,如主题、显示的组件、错误日志等。 它的目的是使应用的配置更加灵活和易于管理。
export default {
/**
* 网页标题
*/
title: import.meta.env.VITE_APP_TITLE,
/**
* 侧边栏主题 深色主题theme-dark,浅色主题theme-light
*/
sideTheme: 'theme-dark',
/**
* 是否系统布局配置
*/
showSettings: true,
/**
* 是否显示顶部导航
*/
topNav: false,
/**
* 是否显示 tagsView
*/
tagsView: true,
/**
* 是否固定头部
*/
fixedHeader: false,
/**
* 是否显示logo
*/
sidebarLogo: true,
/**
* 是否显示动态标题
*/
dynamicTitle: false,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: 'production'
}
2.8 App.vue
App.vue 是 Vue 3 应用的根组件,通常作为整个应用的入口。这个文件负责渲染主要的视图和组件,同时处理一些全局设置,如主题、布局等。
<template>
<router-view />
</template>
<script setup>
import useSettingsStore from '@/store/modules/settings'
import { handleThemeStyle } from '@/utils/theme'
onMounted(() => {
nextTick(() => {
// 初始化主题样式
handleThemeStyle(useSettingsStore().theme)
})
})
</script>
2.8.1 模板部分 (<template>)
<template>
<router-view />
</template>
<router-view />
是 Vue Router 提供的一个占位符组件,它会渲染与当前路由匹配的组件。在单页面应用(SPA)中,router-view 就是路由展示的地方。每当路由变化时,router-view 会根据新的路径自动加载相应的组件。- 例如,假设路由是
/home
,当你导航到这个路径时,router-view
就会显示与/home
路径相关联的组件。
2.8.2 脚本部分 (<script setup>)
<script setup>
import useSettingsStore from '@/store/modules/settings'
import { handleThemeStyle } from '@/utils/theme'
onMounted(() => {
nextTick(() => {
// 初始化主题样式
handleThemeStyle(useSettingsStore().theme)
})
})
</script>
-
import useSettingsStore from '@/store/modules/settings':
- 这里导入了一个自定义的 Vuex store 模块 settings,通过它来获取应用的设置,比如主题(theme)。
-
import { handleThemeStyle } from '@/utils/theme':
- 导入了一个工具函数 handleThemeStyle,它负责处理主题样式(如深色或浅色主题)。该函数会应用选定的主题样式。
-
onMounted():
onMounted
是 Vue 3 中的生命周期钩子,表示组件挂载到 DOM 后会执行这个回调函数。在这个函数中,使用了 nextTick 来确保 DOM 更新完成后再执行初始化操作。
-
nextTick():
- nextTick 是 Vue 提供的一个方法,用来在下次 DOM 更新循环结束后执行延迟回调。在这里,它确保在组件挂载完成并且 DOM 已经更新后,才去初始化主题样式。
-
handleThemeStyle(useSettingsStore().theme):
- 这行代码获取
settings store
中的 theme 值,并通过handleThemeStyle
函数来设置页面的主题样式。这是应用的主题初始化逻辑,确保页面在加载时使用正确的样式(如深色或浅色模式)。
- 这行代码获取
2.8.3 整体结构与功能
-
根组件:App.vue 是整个应用的根组件,它通过
<router-view />
加载并显示与当前路由匹配的组件。路由配置和组件内容的切换都由 Vue Router 来管理。 -
主题初始化:在 onMounted 钩子中,应用会读取 Vuex store 中的主题设置,并通过 handleThemeStyle 函数动态加载和应用相应的主题样式。这个过程确保了用户在使用应用时能够体验到一致的界面风格。
2.9 permission.js
import router from './router'
import { ElMessage } from 'element-plus'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isHttp, isPathMatch } from '@/utils/validate'
import { isRelogin } from '@/utils/request'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register']
const isWhiteList = (path) => {
return whiteList.some(pattern => isPathMatch(pattern, path))
}
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
to.meta.title && useSettingsStore().setTitle(to.meta.title)
/* has token*/
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else if (isWhiteList(to.path)) {
next()
} else {
if (useUserStore().roles.length === 0) {
isRelogin.show = true
// 判断当前用户是否已拉取完user_info信息
useUserStore().getInfo().then(() => {
isRelogin.show = false
usePermissionStore().generateRoutes().then(accessRoutes => {
// 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => {
if (!isHttp(route.path)) {
router.addRoute(route) // 动态添加可访问路由表
}
})
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
}).catch(err => {
useUserStore().logOut().then(() => {
ElMessage.error(err)
next({ path: '/' })
})
})
} else {
next()
}
}
} else {
// 没有token
if (isWhiteList(to.path)) {
// 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
这个 permission.js 文件的主要作用是处理应用的路由权限控制。它确保:
- 未登录用户只能访问白名单中的路由。
- 已登录用户可以根据角色动态生成可访问的路由。
- 如果用户的角色信息尚未加载,会先拉取用户信息并根据角色生成动态路由。
- 页面加载时展示进度条,增强用户体验。
工作流:
- 有 Token:检查路由权限并动态加载角色相关的路由。
- 无 Token:引导用户进入登录页面,并在登录后重定向回原本访问的路径。
3. RuoYi-Vue3 api文件夹下的内容
api文件夹下都是访问后端服务的文件。比如
import request from '@/utils/request'
// 查询缓存详细
export function getCache() {
return request({
url: '/monitor/cache',
method: 'get'
})
}
// 查询缓存名称列表
export function listCacheName() {
return request({
url: '/monitor/cache/getNames',
method: 'get'
})
}
// 查询缓存键名列表
export function listCacheKey(cacheName) {
return request({
url: '/monitor/cache/getKeys/' + cacheName,
method: 'get'
})
}
// 查询缓存内容
export function getCacheValue(cacheName, cacheKey) {
return request({
url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey,
method: 'get'
})
}
// 清理指定名称缓存
export function clearCacheName(cacheName) {
return request({
url: '/monitor/cache/clearCacheName/' + cacheName,
method: 'delete'
})
}
// 清理指定键名缓存
export function clearCacheKey(cacheKey) {
return request({
url: '/monitor/cache/clearCacheKey/' + cacheKey,
method: 'delete'
})
}
// 清理全部缓存
export function clearCacheAll() {
return request({
url: '/monitor/cache/clearCacheAll',
method: 'delete'
})
}
这个代码片段是使用 request 模块来进行缓存管理操作的 API 请求方法。它通过 HTTP 请求与后端服务器进行交互,以便对缓存数据进行查询和清理。下面是每个方法的解释:
- getCache:通过 GET 请求获取缓存的详细信息,访问 /monitor/cache 路径。
- listCacheName:通过 GET 请求获取缓存名称列表,访问 /monitor/cache/getNames 路径。
- listCacheKey:通过 GET 请求获取指定缓存名称下的键名列表。cacheName 是动态参数,传递给 URL 中,路径是 /monitor/cache/getKeys/{cacheName}。
- getCacheValue:通过 GET 请求获取指定缓存名称和缓存键名的内容。cacheName 和 cacheKey 是动态参数,路径是 /monitor/cache/getValue/{cacheName}/{cacheKey}。
- clearCacheName:通过 DELETE 请求清理指定缓存名称的缓存。cacheName 是动态参数,路径是 /monitor/cache/clearCacheName/{cacheName}。
- clearCacheKey:通过 DELETE 请求清理指定缓存键名的缓存。cacheKey 是动态参数,路径是 /monitor/cache/clearCacheKey/{cacheKey}。
- clearCacheAll:通过 DELETE 请求清理所有缓存,访问 /monitor/cache/clearCacheAll 路径。
- 这些方法为应用程序提供了对缓存的基本管理功能,包括查询缓存内容和清理缓存。