vue3+vite+ts+pinia+router4后台管理-动态路由生成
创始人
2025-01-11 06:05:40
0

动态路由功能写法因人而异,本文只做参考!

实现思路

1.在路由钩子里面判断是否首次进入系统(permission.ts)
2.判断token是否有值。没有值回到登陆页面,
3.token有值判断MenusList是否有值,没有则获取路由
4.解析路由,拼接路由,放行路由

1. 引入vue-router 设置静态路由 登陆,首页

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'  const routes: RouteRecordRaw[] = [   {     path: '/',     redirect: '/home/index'   },   {     path: '/login',     name: 'login',     component: () => import('@/views/login/index.vue')   },   {     path: '/layout',     name: 'layout',     component: () => import('@/layout/layout.vue'),     redirect: '/home/index',     children: []   },    {     path: '/:pathMatch(.*)*',     component: () => import('@/views/404.vue')   },  ] // qiankun 子应用路由  (项目中接入qiankun微前端路由写法) // import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper' // const router = createRouter({ //   history: createWebHistory( //     qiankunWindow.__POWERED_BY_QIANKUN__ //       ? '/cms/' //       : '/' //   ), //   routes // })  //  正常路由写法 const router = createRouter({     history: createWebHistory(),// HTML5的history模式     routes: constantRoutes })  export default router  

2. 动态获取后端路由 (stores/menu.ts)

递归解析路由 根据后端返回文件路径匹配路由

import { defineStore } from 'pinia' import { getShowMenuList, generateRouter, arrayToTree } from "@/utils/tool" import { getAllMenuByUserName } from '@/api/commonApi'  export const useMenuStore = defineStore({   id: 'menu',   state: (): any => ({     menusList: [],     cmsMenusList: []   }),   getters: {     showMenuListGet: state => getShowMenuList(state.cmsMenusList)   },   actions: {     async getMenu() {       await getAllMenuByUserName({}).then(res => {         if (res.data?.status == 200) {           // 过滤出 parentId 为 2 的菜单项           let filteredA = res.data.data.sysMenuResp.filter((item: any) => item.parentId === 2) || [];            // 过滤出其 parentId 存在于 filteredA 中的菜单项           let filteredB = res.data.data.sysMenuResp.filter((item: any) => {             return filteredA.some((itemA: any) => itemA.menuId == item.parentId);           }) || [];            // 将 filteredA 和 filteredB 合并为一个扁平化的树结构数组           let flattenedArray = generateRouter(arrayToTree([...filteredA, ...filteredB]));            // 构建最终的菜单列表,包括固定的首页菜单项和动态生成的菜单项           this.cmsMenusList = [             {               name: 'home',               path: '/home/index',               component: () => import('@/views/home/index.vue'),               meta: {                 icon: 'home-outlined',                 title: '首页',                 isKeepAlive: false               }             },             ...flattenedArray,           ];         }       });     }   } })  //  import { getShowMenuList, generateRouter, arrayToTree } from "@/utils/tool"  // 过滤菜单  不需要在菜单栏中显示 export function getShowMenuList(menuList: Menu.MenuOptions[]) {   let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList));   let arr: any = newMenuList.filter(item => {     item.children?.length && (item.children = getShowMenuList(item.children));     return !item.meta?.isHide;   });   return arr }   // 数组转树 export function arrayToTree(array: any) {   const map: any = {}; // 使用对象存储每个节点的引用   // 遍历数组,将每个节点的引用存储到 map 中   array.forEach((item: any) => {     map[item.menuId] = { ...item, children: [] } // 创建一个包含子节点数组的新节点对象   })   const tree: any = []   // 遍历数组,将每个节点添加到其父节点的 children 数组中   array.forEach((item: any) => {     const node = map[item.menuId]     // 注意:这里是父级菜单的id,本项目中返回的数据是多个系统菜单的集合数据,      // 在项目开发中后端可能返回只属于当前系统的数据,     if (item.parentId === 2) {       // 没有父节点,说明是根节点       tree.push(node)     } else {       const parent = map[item.parentId]       parent.children.push(node)     }   })   // console.log(tree)   return tree }  const modules = import.meta.glob("../views/**/*.vue") export const generateRouter = (routerMap: any) => {   return routerMap.map((item: any) => {     const currentRouter: any = {       path: item.singlePath,       name: item.query,       redirect: item.redirect,       meta: {         icon: item.icon,         title: item.menuName,         isKeepAlive: true, // keepAlive 缓存 可以根据菜单设置动态显示,此处写死的,         isHide: item.visible == 0 ? false : true  // 显示隐藏 0 显示  1隐藏       }     };     if (item.singleComponent && typeof item.singleComponent == "string") {       currentRouter.component = modules[`../views/${item.singleComponent}.vue`]     }     // 是否存在子路由     item?.children?.length && (currentRouter.children = generateRouter(item.children))     return currentRouter;   }) }  

切记 keepAlive 缓存需要绑定组件name!!


const modules = import.meta.glob(“…/views//*.vue") : 解析
动态导入符合模式 "…/views//*.vue” 的模块(文件)

import.meta.glob 函数:这是一个特殊的函数,在ES模块环境中它允许根据文件模式动态导入模块
文件模式 (“…/views/**/*.vue”):该模式指定了要导入的所有以 .vue 扩展名结尾的模块(或文件),这些文件位于 …/views/ 目录下的任何子目录中
import.meta.glob 函数返回一个对象,对象的键是匹配到的文件路径,对应的值是一个函数。这个函数调用时返回一个 Promise,该 Promise 解析为导入模块的默认导出。

3.动态挂载路由permission.ts

import type { RouteRecordRaw } from 'vue-router' import { useMenuStore } from '@/stores/menu' import router from './index' import nprogress from 'nprogress' import 'nprogress/nprogress.css' import { useCounterStore } from '@/stores/counter' import { useLocalStore } from '@/stores/local' import { qiankunWindow, } from 'vite-plugin-qiankun/dist/helper'  /** 免登录白名单 */ const whiteList: Array = ['/login', '404']   router.beforeEach(async (to, from, next) => {   const menuStore = useMenuStore()   // const counterStore = useCounterStore()   const localStore = useLocalStore()   nprogress.start()    // ps  qiankun子应用处理菜单特殊处理 不用看   // counterStore.latoutStatus = !qiankunWindow.__POWERED_BY_QIANKUN__   // !qiankunWindow.__POWERED_BY_QIANKUN__ ? window.document.title = (to.meta.title || localStore.homeBasic?.sysName) as string : ''   const token = localStorage.token    if (token) {     if (!menuStore.cmsMenusList.length) {       await localStore.getInfo()   // 获取个人信息       await menuStore.getMenu()    // 获取菜单       await localStore.getUserPermiss()  // 获取 按钮权限数据       menuStore.cmsMenusList.forEach((item: any) => {         if (item.meta.isFull) {           router.addRoute(item as unknown as RouteRecordRaw)         } else {           router.addRoute('layout', item as unknown as RouteRecordRaw)         }       })       return next({ ...to, replace: true })     } else {       next()     }     // next();   } else {     if (whiteList.indexOf(to.path) !== -1) {       next()     } else {       next('/login')       nprogress.done()     }   } })  router.onError((error) => {   localStorage.clear()   router.replace('/login')   location.reload()   console.warn('路由错误', error.message) })  router.afterEach(() => {   const counterStore = useCounterStore()   counterStore.showVisible = 1   nprogress.done() })   

左侧菜单栏组件 使用

 const menus: any = computed(() => menuStore.showMenuListGet) 

// 菜单组件

      

// 全局icon组件 在main.ts 引入

import * as Icons from '@ant-design/icons-vue'  Object.keys(Icons).forEach((key) => {     app.component(key, Icons[key as keyof typeof Icons])   }) 

相关内容

热门资讯

专业讨论!德扑之星真破解套路(... 专业讨论!德扑之星真破解套路(辅助挂)软件透明挂(有挂了解)-哔哩哔哩;人气非常高,ai更新快且高清...
每日必看!智星德州菠萝外挂检测... 每日必看!智星德州菠萝外挂检测(辅助挂)软件透明挂(有挂教学)-哔哩哔哩1、玩家可以在智星德州菠萝外...
透视透明挂!轰趴十三水有后台(... 轰趴十三水有后台赢率提升策略‌;透视透明挂!轰趴十三水有后台(辅助挂)软件透明挂(有挂详情)-哔哩哔...
发现玩家!德扑ai助手软件(辅... 发现玩家!德扑ai助手软件(辅助挂)透视辅助(有挂教学)-哔哩哔哩;玩家在德扑ai助手软件中需先进行...
一分钟了解!x-poker辅助... 一分钟了解!x-poker辅助软件(辅助挂)辅助透视(有挂攻略)-哔哩哔哩1、每一步都需要思考,不同...
一分钟揭秘!德州最新辅助器(辅... 一分钟揭秘!德州最新辅助器(辅助挂)透视辅助(有挂攻略)-哔哩哔哩;德州最新辅助器最新版本免费下载安...
玩家攻略推荐!德州辅助(辅助挂... 玩家攻略推荐!德州辅助(辅助挂)辅助透视(有挂了解)-哔哩哔哩是由北京得德州辅助黑科技有限公司精心研...
揭秘真相!pokernow德州... 《揭秘真相!pokernow德州(辅助挂)辅助透视(有挂介绍)-哔哩哔哩》 pokernow德州软件...
五分钟了解!德州之星辅助器(辅... 五分钟了解!德州之星辅助器(辅助挂)辅助透视(有挂透明)-哔哩哔哩1、很好的工具软件,可以解锁游戏的...
推荐一款!pokermaste... 1、推荐一款!pokermaster有外挂(辅助挂)透视辅助(有挂教学)-哔哩哔哩;详细教程。2、p...