【Vue3-Element-Admin 动态路由】涉及到的配置

Vue3-Element-Admin 动态路由 涉及到的配置

  • 0. Vue3-Element-Admin 项目地址
  • 1. router/index.ts
  • 2. Mock接口模拟数据
  • 3. store/permission
  • 4. api/menu
  • 5. plugins/permission

这篇文章讲的主要是 Vue3-Element-Admin 差不多内置的动态路由配置 (根据后端接口渲染)

先把开发环境(.env.development)中的 VITE_MOCK_DEV_SERVER 设置为 true 这代表启用 Mock 服务
Mock 数据模拟 在 vite 中已经配置好了
在这里插入图片描述

0. Vue3-Element-Admin 项目地址

Vue3-Element-Admin:Vue3-Element-Admin

1. router/index.ts

这个文件主要放一些静态初始路由,可以不用管

import type { App } from 'vue'
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'export const Layout = () => import('@/layout/index.vue')// 静态路由
export const constantRoutes: RouteRecordRaw[] = [{path: '/redirect',component: Layout,meta: { hidden: true },children: [{path: '/redirect/:path(.*)',component: () => import('@/views/redirect/index.vue')}]},{path: '/login',component: () => import('@/views/login/index.vue'),meta: { hidden: true }},{path: '/',name: '/',component: Layout,redirect: '/dashboard',children: [{path: 'dashboard',component: () => import('@/views/dashboard/index.vue'),name: 'Dashboard', // 用于 keep-alive, 必须与SFC自动推导或者显示声明的组件name一致// https://cn.vuejs.org/guide/built-ins/keep-alive.html#include-excludemeta: {title: 'dashboard',icon: 'homepage',affix: true,keepAlive: true,alwaysShow: false}},{path: '401',component: () => import('@/views/error-page/401.vue'),meta: { hidden: true }},{path: '404',component: () => import('@/views/error-page/404.vue'),meta: { hidden: true }}]}
]/*** 创建路由*/
const router = createRouter({history: createWebHistory(),routes: constantRoutes,// 刷新时,滚动条位置还原scrollBehavior: () => ({ left: 0, top: 0 })
})// 全局注册 router
export function setupRouter(app: App<Element>) {app.use(router)
}/*** 重置路由*/
export function resetRouter() {router.replace({ path: '/login' })
}export default router

2. Mock接口模拟数据

如果目前没有后端接口支持的话,可以先去文件根目录 mock 文件夹中的 menu.mock.ts 查看,一开始可能会有很多数据,全改成我的就好,可以先模拟看一下

import { defineMock } from './base'export default defineMock([{url: 'menus/routes',method: ['GET'],body: {code: '00000',data: [{path: '/dashboard',component: 'Dashboard',redirect: '/dashboard',name: '/dashboard',meta: {title: '首页',icon: 'dashboard',hidden: true,roles: ['ADMIN'],alwaysShow: false,params: null}},{path: '/nihao',component: 'Layout',redirect: '/nihao/hello',name: '/nihao',meta: {title: '你好',icon: 'system',hidden: false,roles: ['ADMIN'],alwaysShow: true,params: null},children: [{path: 'hello',component: 'nihao/hello/index',name: 'Hello',meta: {title: 'Hello',icon: 'user',hidden: false,roles: ['ADMIN'],keepAlive: true,alwaysShow: false,params: null}}]},{path: '/system',component: 'Layout',redirect: '/system/user',name: '/system',meta: {title: '系统管理',icon: 'system',hidden: false,roles: ['ADMIN'],alwaysShow: true,params: null},children: [{path: 'user',component: 'system/user/index',name: 'User',meta: {title: 'Test1',icon: 'user',hidden: false,roles: ['ADMIN'],keepAlive: true,alwaysShow: false,params: null}},{path: 'user',component: 'system/user/index',name: 'User',meta: {title: 'Test2',icon: 'user',hidden: false,roles: ['ADMIN'],keepAlive: true,alwaysShow: false,params: null}}]}],msg: '一切ok'}}// ... 其他接口
])

3. store/permission

查看权限配置相关页面,这边主要是做一些角色鉴权、角色菜单权限,差不多都是菜单相关配置,主要看一下 generateRoutes 方法,它是配置动态路由所需要用到的方法,这边我是使用了我上面那个 Mock 接口,你可以看到
MenuAPI.getRoutes() .then(data => { //... })

import { RouteRecordRaw } from 'vue-router'
import { constantRoutes } from '@/router'
import { store } from '@/store'
import MenuAPI from '@/api/menu'
import { RouteVO } from '@/api/menu/model'const modules = import.meta.glob('../../views/**/**.vue')
const Layout = () => import('@/layout/index.vue')/*** Use meta.role to determine if the current user has permission** @param roles 用户角色集合* @param route 路由* @returns*/
const hasPermission = (roles: string[], route: RouteRecordRaw) => {if (route.meta && route.meta.roles) {// 角色【超级管理员】拥有所有权限,忽略校验if (roles.includes('ROOT')) {return true}return roles.some(role => {if (route.meta?.roles) {return route.meta.roles.includes(role)}})}return false
}/*** 递归过滤有权限的动态路由** @param routes 接口返回所有的动态路由* @param roles 用户角色集合* @returns 返回用户有权限的动态路由*/
const filterAsyncRoutes = (routes: RouteVO[], roles: string[]) => {const asyncRoutes: RouteRecordRaw[] = []routes.forEach(route => {const tmpRoute = { ...route } as RouteRecordRaw // 深拷贝 route 对象 避免污染if (hasPermission(roles, tmpRoute)) {// 如果是顶级目录,替换为 Layout 组件if (tmpRoute.component?.toString() == 'Layout') {tmpRoute.component = Layout} else {// 如果是子目录,动态加载组件const component = modules[`../../views/${tmpRoute.component}.vue`]if (component) {tmpRoute.component = component} else {tmpRoute.component = modules[`../../views/error-page/404.vue`]}}if (tmpRoute.children) {tmpRoute.children = filterAsyncRoutes(route.children, roles)}asyncRoutes.push(tmpRoute)}})return asyncRoutes
}
// setup
export const usePermissionStore = defineStore('permission', () => {// stateconst routes = ref<RouteRecordRaw[]>([])// actionsfunction setRoutes(newRoutes: RouteRecordRaw[]) {routes.value = constantRoutes.concat(newRoutes)}/*** 生成动态路由** @param roles 用户角色集合* @returns*/function generateRoutes(roles: string[]) {return new Promise<RouteRecordRaw[]>((resolve, reject) => {// 接口获取所有路由MenuAPI.getRoutes().then(data => {// 过滤有权限的动态路由const accessedRoutes = filterAsyncRoutes(data, roles)setRoutes(accessedRoutes)resolve(accessedRoutes)}).catch(error => {reject(error)})})}/*** 获取与激活的顶部菜单项相关的混合模式左侧菜单集合*/const mixLeftMenus = ref<RouteRecordRaw[]>([])function setMixLeftMenus(topMenuPath: string) {const matchedItem = routes.value.find(item => item.path === topMenuPath)if (matchedItem && matchedItem.children) {mixLeftMenus.value = matchedItem.children}}return {routes,setRoutes,generateRoutes,mixLeftMenus,setMixLeftMenus}
})// 非setup
export function usePermissionStoreHook() {return usePermissionStore(store)
}

4. api/menu

上面的 MenuAPI.getRoutes() 就是在 api/menu 里面定义的接口请求

import request from "@/utils/request";
import { MenuQuery, MenuVO, MenuForm, RouteVO } from "./model";class MenuAPI {/*** 获取路由列表*/static getRoutes() {return request<any, RouteVO[]>({url: "/api/v1/menus/routes",method: "get",});}// ... 其它接口
export default MenuAPI;

5. plugins/permission

这个文件内也是一些权限配置,按钮鉴权,路由守卫都放在这里面了,主要看 setupPermission 中的 router.addRoute(route) 跳转时会把动态路由塞到原本路由表内

import router from '@/router'
import { useUserStore, usePermissionStore } from '@/store'
import NProgress from '@/utils/nprogress'
import { RouteRecordRaw } from 'vue-router'
import { TOKEN_KEY } from '@/enums/CacheEnum'// 是否有权限
export function hasAuth(value: string | string[], type: 'button' | 'role' = 'button') {const { roles, perms } = useUserStore().user//「超级管理员」拥有所有的按钮权限if (type === 'button' && roles.includes('ROOT')) {return true}const auths = type === 'button' ? perms : rolesreturn typeof value === 'string'? auths.includes(value): auths.some(perm => {return value.includes(perm)})
}export function setupPermission() {// 白名单路由const whiteList = ['/login', '/404']router.beforeEach(async (to, from, next) => {NProgress.start()const hasToken = localStorage.getItem(TOKEN_KEY)if (hasToken) {if (to.path === '/login') {// 如果已登录,跳转首页next({ path: '/' })NProgress.done()} else {const userStore = useUserStore()const hasRoles = userStore.user.roles && userStore.user.roles.length > 0if (hasRoles) {// 未匹配到任何路由,跳转404if (to.matched.length === 0) {from.name ? next({ name: from.name }) : next('/404')} else {next()}} else {const permissionStore = usePermissionStore()try {const { roles } = await userStore.getUserInfo()const accessRoutes = await permissionStore.generateRoutes(roles)accessRoutes.forEach((route: RouteRecordRaw) => {router.addRoute(route)})next({ ...to, replace: true })} catch (error) {// 移除 token 并跳转登录页await userStore.resetToken()next(`/login?redirect=${to.path}`)NProgress.done()}}}} else {// 未登录可以访问白名单页面if (whiteList.indexOf(to.path) !== -1) {next()} else {next(`/login?redirect=${to.path}`)NProgress.done()}}})router.afterEach(() => {NProgress.done()})
}

差不多是这样的,大概页面就这样了
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/341488.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue 引用第三方库 Swpier轮播图

本文全程干货&#xff0c;没有废话 1.使用 npm 安装 swiper&#xff0c;使用 save 保存到 packjson 中 npm install --save swiper 2、把 swiper看成是第三方库或者是组件&#xff0c;然后按照&#xff0c;引用&#xff0c;挂载组件&#xff0c;使用组件三步法。 3、在 script…

完美的移动端 UI 风格

完美的移动端 UI 风格

文件上传漏洞之upload-labs

前提&#xff1a; 本文中的以xshell命名的均为以密码为admin的一句话木马&#xff0c;而shell命名的则是由冰蝎工具生成的木马。 pass-01&#xff1a;js前端验证 测试性的上传一个一句话木马&#xff0c;发现被拦截了&#xff0c;而且根据推测大概率是前端检测&#xff0c;于…

爬楼梯——动态规划第一步

本问题其实常规解法可以分成多个子问题&#xff0c;爬第 n 阶楼梯的方法数量&#xff0c;等于两个部分之和 爬上 n−1 阶楼梯的方法数量。因为再爬 1 阶就能到第 n 阶爬上 n−2 阶楼梯的方法数量&#xff0c;因为再爬 2 阶就能到第 n 阶 所以我们得到公式 dp[n] dp[n−1] d…

人脸识别——OpenCV

人脸识别 创建窗口创建按钮设置字体定义标签用于显示图片选择并显示图片检测图片中的人脸退出程序返回主界面 创建窗口 导入tkinter库&#xff0c;创建窗口&#xff0c;设置窗口标题和窗口大小。 import tkinter as tkwin tk.Tk() win.title("人脸识别") win.geom…

【康耐视国产案例】Nvidia/算能+智能AI相机:用AI驱动 | 降低电动车成本的未来之路

受环保观念影响、政府激励措施推动与新能源技术的发展&#xff0c;消费者对电动汽车(EV)的需求正在不断增长&#xff0c;电动汽车已经成为了未来出行方式的重要组成部分。然而&#xff0c;电动汽车大规模取代燃油汽车的道路还很漫长。最大的障碍就是电动汽车的售价相对过高。尽…

【云原生】Kubernetes----PersistentVolume(PV)与PersistentVolumeClaim(PVC)详解

目录 引言 一、存储卷 &#xff08;一&#xff09;存储卷定义 &#xff08;二&#xff09;存储卷的作用 1.数据持久化 2.数据共享 3.解耦 4.灵活性 &#xff08;三&#xff09;存储卷的分类 1.emptyDir存储卷 1.1 定义 1.2 特点 1.3 示例 2.hostPath存储卷 2.1 …

ArcGIS中几个好用的空间分析工具

ArcGIS是一款经典的GIS应用&#xff0c;其空间分析能力很强&#xff0c;有着丰富的空间分析工具。今天&#xff0c;我们一起来了解几个好用的空间分析工具的功用及操作。 注&#xff1a;演示版本为ArcMap10.4.1 1.方向分布&#xff08;标准差椭圆&#xff09; 路径&#xff…

四川汇聚荣聚荣科技有限公司综合实力怎么样?

在科技日新月异的今天&#xff0c;企业的综合实力成为衡量其市场竞争力的重要指标。四川汇聚荣聚荣科技有限公司作为一家在行业内具有一定影响力的企业&#xff0c;其综合实力如何&#xff0c;自然成为外界关注的焦点。以下将从多个维度深入分析该公司的实力。 一、公司概况与核…

Java利用POI绘制表格

前提需求 最近公司要求写一些记录的表格&#xff0c;并且带有导出功能。再深入学习后&#xff0c;表格的底层其实就是list遍历塞值&#xff0c;导出功能的话可以由前端&#xff0c;后端实现&#xff0c;但技多不压身嘛&#xff0c;这里我自己就写了后端的导出功能&#xff0c;…

【小白专用 已验证24.5.30】ThinkPHP6 视图

ThinkPHP6 视图 模板引擎支持普通标签和XML标签方式两种标签定义&#xff0c;分别用于不同的目的 标签类型描述普通标签主要用于输出变量、函数过滤和做一些基本的运算操作XML标签也称为标签库标签&#xff0c;主要完成一些逻辑判断、控制和循环输出&#xff0c;并且可扩展 c…

双指针法 ( 三数之和 )

题目 &#xff1a;给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复…

计算机网络学习笔记——网络层(b站)

目录 网络层概述 网络层提供的两种服务 ①面向连接的虚电路服务 ②无连接的数据报服务 IPv4 路由选择 路由器转发IP数据报 静态路由选择 动态路由选择 路由信息协议RIP 开放最短路径优先OSPF&#xff08;Open Shortest Path First&#xff09; 内部网关协议IGP&…

Linux网络编程:回顾网络通信

1.数据从应用层到数据链路层的本质 数据的封装&#xff1a; 用户在用户级缓冲区输入数据&#xff0c;经过应用层协议进行序列化成字节流数据&#xff0c;拷贝到传输层的缓冲区。而操作系统在传输层维护了sk_buff这一个结构体&#xff0c;然后data指针指向这段数据的开头&#x…

【C++面试50题】

以下是针对C程序员面试可能遇到的一些问题&#xff0c;涵盖了从基础语法、面向对象、STL、内存管理、模板、异常处理、并发编程等多个方面。 ### 基础概念与语法 1. C与C的主要区别是什么&#xff1f; 2. 什么是构造函数和析构函数&#xff1f;它们何时被调用&#xff1f; 3. 什…

xml 取值错误 #{} boolean 一直为 false

取值时 #{param.msgStatus} 一直是false&#xff0c;java代码里面显示true。 <select id"findPageOaReading" resultType"com.focusin.data.office.func.dto.ProcessMessageInfoDTO">select i.*, t.template_name procdefNamefrom process_message_…

常见的Web漏洞——CORS

渗透做了多年的朋友都知道&#xff0c;大洞小洞都是漏洞。因此也学习、沉淀一下以前没重视的漏洞。 简介 CORS&#xff08;Cross-Origin Resource Sharing&#xff0c;跨源资源共享&#xff09;是一种由Web浏览器实现的安全策略&#xff0c;用于控制一个Web页面&#xff08;服…

Unity DOTS技术(五)Archetype,Chunk,NativeArray

文章目录 一.Chunk和Archetype什么是Chunk?什么是ArchType 二.Archetype创建1.创建实体2.创建并添加组件3.批量创建 三.多线程数组NativeArray 本次介绍的内容如下: 一.Chunk和Archetype 什么是Chunk? Chunk是一个空间,ECS系统会将相同类型的实体放在Chunk中.当一个Chunk…

机器学习18个核心算法模型

1. 线性回归&#xff08;Linear Regression&#xff09; 用于建立自变量&#xff08;特征&#xff09;和因变量&#xff08;目标&#xff09;之间的线性关系。 核心公式&#xff1a; 简单线性回归的公式为&#xff1a; , 其中 是预测值&#xff0c; 是截距&#xff0c; 是斜…

leetcode第867题:转置矩阵

matrix[i][j]需要放在转置矩阵的(j,i)位置 public class Solution {public int[][] Transpose(int[][] matrix) {int rows matrix.Length; int columns matrix[0].Length; int[][] array2 new int[columns][];// 初始化内部数组&#xff08;列数&#xff09;for (int i 0…