Icce___ 2023-11-24 09:09 采纳率: 66.7%
浏览 215
已结题

vite+vue3+pinia 动态路由刷新页面失效

使用的vite+vue3+pinia来实现动态路由
pinia已经做了持久化

问题:
从登录进入页面一切正常,所有动态路由能够添加到router,控制台打印也是正常;按f5刷新后,在登录逻辑里动态添加的路由都消失了。打印存在pinia中的用户路由发现其他属性都有,但是component属性直接不见了。求解惑

添加动态路由代码:

router.beforeEach((to, from, next) => {
    const user = userStore()
    const { token, roles, routes } = storeToRefs(user)
    if (token.value) {
        if (to.path === routePaths.login) {
            next({ path: routePaths.default })
        } else {
            if (roles.value.length === 0) {
                user.getRoles().then(() => {
                    user.initRoutes().then(() => {
                        resetRouter()
                        routes.value.forEach(route => {
                            let index = constantRoutes.findIndex(r => r.name === route.name)
                            if (index != -1) {
                                constantRoutes[index].children = route.children
                            }
                        });
                        constantRoutes.forEach(route => {
                            router.addRoute(route)
                        })
                        
                console.log(routes.value)
                        const redirect = decodeURIComponent(from.query.redirect as string || to.path)
                        if (to.path === redirect) {
                            next({ ...to, replace: true })
                        } else {
                            next({ path: redirect })
                        }
                    })
                })
            } else {
                console.log(routes.value)
                console.log(router.getRoutes())
                next()
            }
        }
    } else {
        if (whiteList.includes(to.name as string) || whiteList.includes(to.path)) {
            next()
        } else {
            next({ path: routePaths.login, query: { redirect: to.fullPath } })
        }
    }
})

        initRoutes(): Promise<void> {
            return new Promise((resolve, reject) => {
                generatorDynamicRouter().then(res => {
                    this.routes = res
                    console.log(this.routes)
                    resolve()
                }).catch(err => {
                    reject(err)
                })
            })

generatorDynamicRouter就是请求list数据,然后将list转换成tree返回一个树状结构的路由数组,输出的数据样子

img

vite的组件动态引入:


const  modules = import.meta.glob(['../views/**/*.vue', '../components/**/*.vue'])

export const generatorDynamicRouter = (): Promise<Array<RouteRecordRaw>> => {
  return new Promise((resolve, reject) => {
    getMenus()
      .then(res => {
        const { data } = res
        const menuNav = []
        const childrenNav = []
        listToTree(data, childrenNav, '')
        rootRouter.children = childrenNav
        menuNav.push(rootRouter)
        const asyncRoutes = generator(menuNav)
        //  routers.push(notFoundRouter)
        resolve(asyncRoutes)
      })
      .catch(err => {
        reject(err)
      })
  })
}

export const generator = (routerMap, parent?) => {
  return routerMap.map(item => {
    const { title, show, hideChildren, hiddenHeaderContent, target, icon } = item.meta || {}
    const currentRouter = {
      path: item.path || `${(parent && parent.path) || ''}/${item.name}`,
      name: item.name || '',
      label: item.label || '',
      component:  modules[`../views/${item.component}.vue`],
      children: []
    }
    if (item.children && item.children.length > 0) {
      currentRouter.children = generator(item.children, currentRouter)
    }
    return currentRouter
  })
}

这是正常登陆后
打印存储的用户路由(44行打印),和router.getRoutes()方法获取到的路由

img

刷新页面后变成这样了

img

  • 写回答

12条回答 默认 最新

  • 社区专家-Monster-XH 2023-11-24 15:03
    关注

    根本原因在导入的组件引用在页面刷新时没有被正确地持久化和恢复。component 是一个函数,返回一个 Promise,这个 Promise 解析为一个组件。当你刷新页面时,由于 Promise 并没有被执行,所以你在 Pinia 中存储的 routes 数组的 component 函数会丢失,因为函数不能直接被序列化或者存储。

    • 解决这个问题的一个方法是,不要直接存储 component 函数,而是存储一个能够用来在需要的时候重新导入组件的标识符(例如文件路径)。然后,你可以在页面加载时使用这个标识符来重新导入组件。

    解决步骤:

    1.在存储路由配置时,不要存储 component 函数,而是存储表示组件的字符串路径。

    // 在存储之前,转换routes数组
    this.routes = routes.map(route => ({
      ...route,
      component: route.component.toString(),
      // 确保子路由也进行同样的转换
      children: route.children.map(childRoute => ({
        ...childRoute,
        component: childRoute.component.toString()
      }))
    }));
    
    
    

    2.当你需要将路由添加到路由器时,使用这个字符串路径重新导入组件。

    // 添加路由之前,重新导入组件
    routes.value.forEach(route => {
      route.component = () => import(route.componentPath);
      // 同样为子路由重新导入组件
      if (route.children) {
        route.children.forEach(childRoute => {
          childRoute.component = () => import(childRoute.componentPath);
        });
      }
      router.addRoute(route);
    });
    
    
    

    3.确保你的 import.meta.glob 能够处理这种字符串路径的动态导入。

    // 修改你的dynamic import语句来处理字符串路径
    const modules = import.meta.glob('../views/**/*.vue');
    const componentPath = '../views/home/index.vue'; // 这是一个例子
    const component = modules[componentPath](); // 动态导入组件
    
    
    

    这样,每次页面刷新时,你都可以从 Pinia 存储中获取字符串路径,并使用它们重新导入必要的组件,从而恢复动态路由。这就要求你的动态路由生成器和添加路由的逻辑都能够处理这种情况。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(11条)

报告相同问题?

问题事件

  • 系统已结题 12月5日
  • 已采纳回答 11月27日
  • 修改了问题 11月24日
  • 修改了问题 11月24日
  • 展开全部

悬赏问题

  • ¥20 遥感植被物候指数空间分布图制作
  • ¥15 安装了xlrd库但是import不了…
  • ¥20 Github上传代码没有contribution和activity记录
  • ¥20 SNETCracker
  • ¥15 数学建模大赛交通流量控制
  • ¥15 为什么我安装了open3d但是在调用的时候没有报错但是什么都没有发生呢
  • ¥50 paddleocr最下面一行似乎无法识别
  • ¥15 求某类社交网络数据集
  • ¥15 靶向捕获探针方法/参考文献
  • ¥15 很抱歉出现错误word不能启动(24),如何解决?