Vue3中使用vue-router刷新获取动态路由时页面丢失的问题

动态菜单来源于接口,当第一次请求菜单数据后,需要进行缓存(vuex或者pinna),同时也需要进行本地持久化存储(localStorage或者sessionStroage)

  // 获取当前用户菜单权限
      const userMenusResult = await requestUserMenusByRoleId(userInfo.role.id)
      const userMenus = userMenusResult.data
      commit("changeUserMenus", userMenus)
      localCache.setCache("userMenus", userMenus)

存储后需要进行菜单匹配来加载前端页面组件,前端预先配置所有权限的菜单组件,然后在获取菜单方法中对接口获取的userMenu和前端的页面组件进行匹配

在webpack+vuex中:

export function mapMenuToRoutes(userMenus: any[]): RouteRecordRaw[] {
  const routes: RouteRecordRaw[] = []
  // 加载所有的routes
  const allRoutes: RouteRecordRaw[] = []
  const routeFiles = require.context("../router/main", true, /\.ts/)
  routeFiles.keys().forEach((key) => {
    const route = require("../router/main" + key.split(".")[1])
    allRoutes.push(route.default)
  })

  const _recurseGetRoute = (menus: any[]) => {
    for (const menu of menus) {
      if (menu.type === 2) {
        const route = allRoutes.find((item) => item.path === menu.url)
        route && routes.push(route)
      } else {
        _recurseGetRoute(menu.children)
      }
    }
  }
  _recurseGetRoute(userMenus)
  firstMenu = routes[0]
  return routes
}

在vite + pinia中

function loadLocalRoutes() {
  // 6. 动态添加路由
  const localRoutesArr: RouteRecordRaw[] = []
  // 6.1 动态加载router文件夹中的ts
  const filesSystem = import.meta.glob('../router/SystemMain/**/*.ts', { eager: true })
  const filesAnalysis = import.meta.glob('../router/AnalysisMain/**/*.ts', { eager: true })
  const filesProduct = import.meta.glob('../router/ProductCenter/**/*.ts', { eager: true })
  const filesStory = import.meta.glob('../router/StoryChat/**/*.ts', { eager: true })

  const files: Record<string, any> = {
    ...filesSystem,
    ...filesAnalysis,
    ...filesProduct,
    ...filesStory
  }
  // 6.1.2 将加载的对象放到localRoutesArr
  for (const key in files) {
    const module = files[key]
    localRoutesArr.push(module.default)
  }
  return localRoutesArr
}
// 第一次的路由 active
export let firstMenu: any = null
export const mapMenuToRoute = (userMenus: any[]) => {
  // 加载本地路由
  //   console.log(localRoutesArr)
  const localRoutesArr = loadLocalRoutes()
  // 6.2 根据菜单去匹配正确的路由
  const routes: RouteRecordRaw[] = []

  for (const menu of userMenus) {
    for (const submenu of menu.children) {
      // console.log(submenu)
      // 如果建立动态路由文件夹和服务器给的路由地址相同
      // const route = localRoutesArr.find((item) => item.path === submenu.url)
      // console.log(route)
      // 创建文件名与路由不同 所以要找相同点
      const submenuUrl = submenu.url.split('/')[3]
      // console.log('submenuUrl', submenuUrl)
      localRoutesArr.forEach((item) => {
        const route = item.path.toLowerCase().split('/')[2]
        if (route.includes(submenuUrl)) {
          item.path = submenu.url
          // console.log('路由:', item.path, submenu.url)
          // 一级路由菜单
          if (!routes.find((item) => item.path === menu.url)) {
            routes.push({ path: menu.url, redirect: item.path } as RouteRecordRaw)
          }
          // 二级路由菜单
          routes.push(item)
          if (!firstMenu && item) firstMenu = submenu
          //   router.addRoute('main', item)
        }
      })
    }
  }
  return routes
}

经过测试后路由已经匹配,但是在当前路由刷新页面后,无法再次匹配到页面组件

分析出现的问题可能有两种:

第一: 刷新后vuex或者pinia中的菜单数据被清除,此时需要再次从本地缓存中拿到菜单数据,然后再次对state进行赋值和路由匹配

 initStateInfo(state) {
      const token = localCache.getCache("token")
      const userInfo = localCache.getCache("userInfo")
      const userMenus = localCache.getCache("userMenus")
      if (token && userInfo && userMenus) {
        state.token = token
        state.userInfo = userInfo
        state.userMenus = userMenus
        const routes = mapMenuToRoutes(userMenus)
        routes.forEach((route) => router.addRoute("main", route))
      }
    }

其二:vuex与pinia的state已经更新了,但是页面依然无法加载页面组件,经过排查发现,在main.ts中需要把store的注册提前到router之前,然后问题就解决了,意思就是当进行路由匹配的时候,此时store中的动态路并没有被添加到routes中,所以导致在刷新页面时,只有静态路由可访问,动态路由并没生效,因此与之匹配的页面组件没有被找到

;(async () => {
  const app = createApp(App)
  app.use(global)
  await app.use(store)
  app.use(router)
  app.mount("#app")
})()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值