动态路由添加导致页面刷新报警告No match found for location with path "..." 的解决方案

2,599 阅读3分钟

技术选择

· VUE3
· VUE-ROUTER@4

问题发现

· 路由表分为 静态路由动态路由 ,动态路由在 路由守卫 中判断用户登录后请求的 菜单权限 进行 动态添加
· 在 动态路由路径页面 中刷新浏览器时会导致控制台 报出警告 ,但是页面可以正常跳转

// 动态添加路由的判断逻辑,如果没有菜单列表,就要重新请求菜单列表并添加动态路由
  const authStore = useAuthStore() // 用户的权限仓库
  if(!authStore.authRouterList.length) { // 用户权限仓库为空说明还没有鉴权添加动态路由
    await initDynamicRouter() // 此处方法为判断动态路由表和用户权限从而添加路由
    return next({...to, replace: true}) // 中断此次跳转并携带此次跳转的所有信息重新进入路由
  }

问题逐步解决

Q 首先刷新浏览器后报出警告,发现页面 初次进入 时,守卫拦截到的 to 路由信息中匹配到的路由为空(hash路由方式)
[Vue Router warn]: No match found for location with path "/acl/user"

{
    "fullPath": "/acl/user",
    "path": "/acl/user",
    "query": {},
    "hash": "",
    "params": {},
    "matched": [], // 匹配为空
    "meta": {},
    "href": "#/acl/user"
}

A 在 静态路由表 中添加 全匹配路由 (注意全匹配写法),这样第一次路由表中不存在该 路由(动态路由) 时也能匹配到一个路由

{
    path: '/:pathMatch(.*)*',
    name: 'NotFound',
    meta: {
      isHide: true
    },
    component: () => import("@/views/error/error-404.vue")
},

Q 再次刷新尝试发现控制台 警告消失,但是路由俩次跳转 (第一次因为 鉴权添加动态路 由被打断),发现应用仍然会停留在 404页面
查看打印的俩次 to 路由找寻答案(俩次打印除了 redirectedFrom 属性外一模一样)

{
    "fullPath": "/acl/user",
    "path": "/acl/user",
    "query": {},
    "hash": "",
    "name": "NotFound",
    "params": {
        "pathMatch": [
            "acl",
            "user"
        ]
    },
    "matched": [
        {
            "path": "/:pathMatch(.*)*",
            "name": "NotFound",
            ...
        }
    ],
    "meta": {
        "isHide": true
    },
    "href": "#/acl/user"
}

A 发现仅仅只有一个 redirectedFrom 属性不同,第一个 to 路由中该属性为 undefined,第二个 to 路由中该属性为第一个 to 路由对象
再细看发现匹配的居然都是 NotFound,而在俩次 to 路由中的 name 属性也都是 undefined
( 这里我感觉是不是 to 中携带的 name 属性优先级高于 path 属性,导致 第二次匹配 的时候直接识别了 name 属性去匹配了 NotFound 路由 )
在鉴权打断的 next 方法中 {...to} 是期望路由器 携带所有路由信息 进入 动态路由添加完毕 之后的路由表匹配,直接对

return next({...to, replace: true}) // 中断此次跳转并携带此次跳转的所有信息重新进入路由

修改成

return next({path: to.fullPath, replace: true})

可能导致携带的 路由信息 丢失!!

解决方案一

判断 name 进行修改

  const authStore = useAuthStore()
  console.log(to)
  if(!authStore.authRouterList.length) {
    await initDynamicRouter()
    if(to.name == "NotFound") { // 添加判断条件
      to.name = ""
    }
    return next({...to, replace: true})
  }
解决方案二

直接去掉 全匹配路由 中的 name 属性就行啦(我一开始用方案一还 *沾沾自喜* 😂)

{
    path: '/:pathMatch(.*)*',
    // name: 'NotFound', // 直接去掉
    meta: {
      isHide: true
    },
    component: () => import("@/views/error/error-404.vue")
},

写在后面:上班......