vue3 动态路由设计

设计流程

1.准备一个请求,从后端获取路由数据

2.这个请求放置在路由守卫(router.beforeEach)next的前面,阻塞next(),当动态组件添加好了在进入页面。

import { createRouter, createWebHistory } from 'vue-router'
// 基础路由 一般回放一个Login页面的对象
import { baseRoutes } from '@/router/basicRoutes'
import {  getUsermMenu } from "@/api";

// 在js/ts里面使用pinia,需要这么使用,多导出一个Pinia,这里就不展开说了,大家自行百度
import { routerListAddCountStore, routerListStore } from '@/stores/index'
import pinia from '@/stores/index'
const routerListAddCountV = routerListAddCountStore(pinia)
const routerListStoreV = routerListStore(pinia)



// 创建路由对象
let router = createRouter({
  // 路由模式hash
  // history:  createWebHashHistory(),
  history: createWebHistory(),
  routes: [...baseRoutes]
})


// 配置路由守卫
router.beforeEach((to, from, next) => {
  //  routerListAddCountV.routerListAddCount 控制整个项目只会请求一次后端路由 (请求后这个Pinia+=1就行了,简单判断)
  // routerListAddCountV.routerListAddCount 是 pinia
  if (routerListAddCountV.routerListAddCount >= 1) {
    console.log('我走不请求数据')
    next()

  } else {
    console.log('我走请求数据')
    // 这个是后端请求路由
    // !!!!!第一个知识点来了,如果你想阻塞next,你必须使用.then的方式调用,将next,放在.then中,看别人是这么解释的,next只能放在同步逻辑中,你写settiomeout 和 async await是不行的。
    getUsermMenu().then(res => {
      // 路由
      let TempRouterList = res.data.menuList
      // !!!!第二个知识点来了,我们的路由都是使用懒加载的,但是后端直接传过来()=》一个箭头函数是不能用的,所以我们要使用vue3(vite)的写法import.meta.glob,注意webpack不是这么写的,webpack的话需要自己去查一下。
      //   ../views/*/*.vue  这个的意思就是会将views/任意/任意.vue 复合这个格式的vue转换成箭头函数
      const modules = import.meta.glob(['../views/*/*.vue', '../views/*/*/*.vue'])

      // 这一段代码的意思就是
      TempRouterList.forEach(element => {
        // 具体的xi
        //  拆解一下    element.component是后端传过来的,是 '/home/layout.vue'
        //  加上 ../views  相当与是补全一下    ,这里用../(相对路径) 是因为不能写@(绝对路径)    
        // 最后打印 element.component  出来是    () => import("/src/views/home/layout.vue")  是这样的
        element.component = modules[`../views${element.component}`]
        if (element?.children.length > 0) {
          // 如果有嵌套路由也记得 懒加载一下
          element.children.forEach(Sonelement => {
            Sonelement.component = modules[`../views${Sonelement.component}`]
          })
        }
        // !!!!第三个知识点,  router就是上面创建的router 一页代码直接使用,  我们先说addRoute这个方法。就是将这个路由关系加进去我们路由的一个方法,添加一个最大的父级即可
        router.addRoute(element)
      });

      // !!!第四个知识点,404页面必须放在我们动态拿来的数据后面,如果放在前面会先匹配404
      let Route404 = {
        path: '/404',
        component: modules[`../views/404/index.vue`],
        name: '404',//命名路由
        meta: {       // 增加
          title: '丢失页面',
          show: false
        }
      }
      // 找不到的页面
      let ANyRoute = {
        path: '/:pathMatch(.*)*',
        redirect: '/404',
        name: 'Any',
        meta: {       // 增加
          title: '任意',
          show: false
        }
      }

      router.addRoute(Route404)
      router.addRoute(ANyRoute)

      TempRouterList.push(Route404)
      TempRouterList.push(ANyRoute)

      // 这个是将我们编辑好的这个路由数组,加入到pinia中,渲染的左侧菜单的时候使用这个Pinia就行
      routerListStoreV.setRouterList(TempRouterList)
      // 这个就是最开始判断》=1的哪个逻辑,这里面其实就是个pinia,pinia的方法是  +=1,这样加载过一次后,就会走不请求的判断
      routerListAddCountV.setRouterListAddCount()

  // !!!第5个知识点, router.getRoutes() 可以获取到你最新addrouter的注册路由, router.opetion并不是最新的
      let newRoutes = router.getRoutes()
      //  默认去第一个
      let goUrl = newRoutes[0].path

      // 如果被注册就去注册的
      newRoutes.some(item=>{
        if(item.path == to.path){
          goUrl = to.path
          return true
        }
      })

      // !!!第6个知识点来了,当你使用addroute加入,并用光杆next(),是会白屏的!必须加上replace: true,这个官方的解释就是等路由更新好再跳转的意思。
      next({ path: goUrl, replace: true })

    })
  }
});








// 配置路由对象
export default router

这是最基础的逻辑,如果需要用到项目中,需要自行加上判断是是否有token,并跳转到Login页面等等

### Vue3动态权限路由的实现方式 在 Vue3 中实现动态权限路由是一项常见的需求,尤其是在企业级应用中。以下是详细的实现过程以及注意事项。 #### 1. 路由配置 为了支持动态权限路由,首先需要定义所有的静态路由 `allRoutes` 和默认公共路由(如登录页)。这些路由通常存储在一个单独的文件中以便管理: ```javascript // src/router/all-routes.ts import { RouteRecordRaw } from 'vue-router'; const allRoutes: RouteRecordRaw[] = [ { path: '/dashboard', name: 'Dashboard', component: () => import('@/views/Dashboard.vue'), meta: { auth: true }, }, { path: '/profile', name: 'Profile', component: () => import('@/views/Profile.vue'), meta: { auth: true, roles: ['admin', 'editor'] }, // 权限控制 }, ]; export default allRoutes; ``` --- #### 2. 后端数据处理与格式化 假设后端返回的是用户的权限菜单列表,可以通过以下函数将其转换为可被 Vue Router 接受的格式[^3]: ```typescript function formatRoutes(routes: any[]): RouteRecordRaw[] { const formattedRoutes: RouteRecordRaw[] = []; routes.forEach((item) => { if (item.children && Array.isArray(item.children)) { item.children = formatRoutes(item.children); // 处理子路由 } formattedRoutes.push({ path: item.path, name: item.name, component: () => import(`@/views/${item.component}.vue`), meta: item.meta || {}, children: item.children || [], }); }); return formattedRoutes; } ``` --- #### 3. 动态加载路由逻辑 当用户成功登录并获取其角色权限后,可以调用如下方法将动态路由注入到 Vue Router 实例中[^2]: ```typescript import { useRouter } from 'vue-router'; import allRoutes from './router/all-routes'; // 导入所有可能的路由 async function loadDynamicRoutes(userMenus: []) { const router = useRouter(); const matchedRoutes = []; for (const menu of userMenus) { const route = allRoutes.find((r) => r.path === menu.route); if (route) { matchedRoutes.push(route); } } matchedRoutes.forEach((route) => { router.addRoute(route); // 将匹配路由添加至当前实例 }); console.log('Dynamic Routes Loaded:', matchedRoutes); } // 假设从服务端获取到了用户菜单信息 loadDynamicRoutes([ { id: 1, route: '/dashboard' }, { id: 2, route: '/profile' }, ]); ``` --- #### 4. 解决刷新页面导致动态路由丢失的问题 由于浏览器刷新会清空 JavaScript 状态,因此需要在每次初始化时重新加载动态路由。可以在 Pinia 或 Vuex 中保存用户状态,并结合生命周期钩子完成此操作[^2]: ```typescript // src/stores/login.ts import { defineStore } from 'pinia'; import { ref } from 'vue'; export const useLoginStore = defineStore('login', () => { const roleMenu = ref([]); async function setRoleMenu() { try { const response = await fetch('/api/user/menu'); // 获取用户权限接口 roleMenu.value = await response.json(); } catch (error) { console.error('Failed to fetch menus:', error); } } return { roleMenu, setRoleMenu }; }); ``` 随后,在入口文件中设置监听器以确保动态路由始终可用: ```typescript // main.ts import { createApp } from 'vue'; import App from './App.vue'; import setupPinia from './setup/pinia'; import { useRouter } from 'vue-router'; import { useLoginStore } from './stores/login'; const app = createApp(App); setupPinia(app); app.mount('#app'); // 自动加载动态路由 const loginStore = useLoginStore(); if (!loginStore.roleMenu.length) { loginStore.setRoleMenu().then(() => { const dynamicRoutes = generateUserRoutes(loginStore.roleMenu); addDynamicRoutesToRouter(dynamicRoutes); }); } else { const dynamicRoutes = generateUserRoutes(loginStore.roleMenu); addDynamicRoutesToRouter(dynamicRoutes); } ``` --- #### 5. 页面导航守卫 最后,利用 Vue Router 提供的全局前置守卫来拦截授权访问的行为[^1]: ```typescript import { useRouter, onBeforeRouteUpdate } from 'vue-router'; import { useLoginStore } from './stores/login'; const router = useRouter(); router.beforeEach(async (to, from, next) => { const store = useLoginStore(); const isAuthenticated = !!store.token; if (to.matched.some((record) => record.meta.auth)) { if (!isAuthenticated) { next({ name: 'Login' }); // 如果目标页面需认证,则跳转到登录页 } else { next(); // 已经登录则继续执行 } } else { next(); // 不需要认证即可访问 } }); ``` --- ### 总结 以上展示了如何在 Vue3 中实现动态权限路由的核心流程,包括但不限于路由配置、后端数据解析、动态加载机制以及解决刷新问题的方法。通过合理设计和模块划分,能够有效提升代码维护性和扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值