当前位置: 首页 > Web前端 > vue.js

SPA不要陷入路由的死循环

时间:2023-03-31 21:12:53 vue.js

在vue路由中,我们会使用navigationguards来控制页面是否可以访问和查看。最后一步是调用next()函数以继续中断的导航。触发导航时,将按创建顺序调用全局前卫。守卫是异步执行的。这个时候导航就等着守卫全部解决了。所以一定要调用next方法,否则hook无法解析路由循环关键点:next()可以传入参数,实现跳转到其他页面或取消导航的功能。这时候需要注意的是不能阻塞通道,需要保证每个条件最终都能调用next()方法不传参。否则页面会陷入刷新的死循环。因为传入参数的next()方法会导致路由再次执行预导航守卫,从而陷入循环。示例1:验证token,如果失败,返回登录页面="/login"){next({path:"/dashboard"})}else{alert("1")next()}}else{next({path:"/login"})//将执行前面的导航再次守卫,因为路径改变}})上面的代码看起来没问题:如果sessionStorage有token,输入的目标路径是登陆页面,则跳转到/dashboard页面;如果它是另一个页面,直接转到它;如果sessionStorage没有token就跳转到登录页面,但是代码执行会造成死循环,因为没有出口,执行next({path:"/login"})会再次执行全局预导航守卫。在进入/login页面之前,再次触发守卫,把入口代码改成下面这样就正常了:router.beforeEach((to,from,next)=>{lettoken=window.sessionStorage.getItem('token');if(to.path!='/login'&&!token){next({path:'/login'})}else{if(to.path=='/login'&&token){next('/dashboard')}else{next()}}})示例2:动态添加路由router.beforeEach((to,from,next)=>{functiongetRouteAndMenu(){//如果没有保存可访问的路由本地需要计算store.dispatch('d2admin/user/GenerateRoutes')//获取可访问的路由并保存在vuex中routesconstrouteArray=routes.concat(store.state.d2admin.user.accessedRouters)//处理路由获取每一级路由设置store.commit('d2admin/page/init',routeArray)//设置顶栏菜单store.dispatch('d2admin/menu/GenerateHeaderMenu',{角色:store.state.d2admin.user.info.role,menuHeader})//设置侧边栏菜单store.dispatch('d2admin/menu/GenerateMenu',{role:store.state.d2admin.user.info.role,menuAside})//获取侧边栏菜单并保存到vuexstore.dispatch('d2admin/menu/setMenuAside',{menuAside})next({...to,replace:true})//hack以确保在跳转之前添加路由}if(from.name===null&&to.name==='404'){//避免刷新404页面getRouteAndMenu()}//验证当前路由的所有匹配都需要登录验证if(to.matched.some(r=>r.meta.auth)){//这里临时检查cookie中是否有token作为验证登录条件//请根据自己的业务需要修改consttoken=util.cookies.get('token')if(token&&token!=='undefined'){constaccessedRouters=store.state.d2admin.user.accessedRoutersif(accessedRouters.length<=0){getRouteAndMenu()}else{next()}}else{//未登录时跳转到登录界面//携带登录成功后需要跳转的页面全路径next({名称:'登录',查询:{红色irect:to.fullPath}})}}else{//不需要身份验证直接通过next()}})上面代码主要是实现动态路由的计算,并在原来的菜单中添加可以在路由和计算中显示的bar,然后跳转到对应的页面功能其中next({...to,replace:true})方法是一个hack方法,可以保证在跳转之前添加路由。问题是这里内存中只保存了动态计算的路由,所以当页面刷新时,需要重新计算添加,所以添加了如下代码:if(from.name===null&&to.name==='404'){//避免刷新404页面getRouteAndMenu()}会导致页面重复执行getRouteAndMenu()操作,浏览器会重复导航到当前刷新的页面。原因:getRouteAndMenu除了hack方法外没有提供next()通道,每次hack都会重新执行navigationguard。解决方法:不用hack,使用asyncawait,按顺序执行,最后next()router.beforeEach((to,from,next)=>{asyncfunctiongetRouteAndMenu(){//如果本地没有保存可访问的路由,你需要计算awaitstore.dispatch('d2admin/user/GenerateRoutes')//获取可访问的路由并保存在vuex中router.addRoutes(store.state.d2admin.user.accessedRouters)//与原来的固定路由合并constrouteArray=routes.concat(store.state.d2admin.user.accessedRouters)//处理路由获取每一级路由设置store.commit('d2admin/page/init',routeArray)//设置顶栏菜单awaitstore.dispatch('d2admin/menu/GenerateHeaderMenu',{role:store.state.d2admin.user.info.role,menuHeader})//设置侧边栏菜单awaitstore.dispatch('d2admin/menu/GenerateMenu',{role:store.state.d2admin.user.info.role,menuAside})//获取侧边栏菜单并保存在vuex中awaitstore.dispatch('d2admin/menu/setMenuAside',{menuAside})next()}if(from.name===null&&to.name==='404'){//避免刷新404页面getRouteAndMenu()}//验证当前所有路由是否匹配时需要进行登录验证if(to.matched.some(r=>r.meta.auth)){//这里暂时以cookie中是否有token作为验证是否登录的条件//请根据自己的业务需要修改consttoken=util.cookies.get('token')if(token&&token!=='undefined'){constaccessedRouters=store.state.d2admin.user.accessedRoutersif(accessedRouters.length<=0){getRouteAndMenu()}else{next()}}else{//未登录时跳转到登录界面//携带登录成功后需要跳转的页面全路径next({名称:'登录',查询:{红色irect:to.fullPath}})}}else{//不需要身份验证直接通过next()}})另外路由导航守卫的调用顺序