当前位置:网站首页 > R语言数据分析 > 正文

动态路由下的导航守卫--(to,from,next)

1. 导航守卫–(to,from,next)

router.beforeEach 注册一个全局前置守卫:

const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // ... }) 

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中(没有执行next就一直等待)。

每个守卫方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next(‘/’) 或者 next({ path: ‘/’ }):跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

确保要调用 next 方法,否则钩子就不会被 resolved

router.beforeEach((to, from, next) => { 
    if (to.matched.length ===0) { 
    //如果未匹配到路由 from.path? next({ 
    path:from.path}) : next('/'); //如果上级也未匹配到路由则跳转主页面,如果上级能匹配到则转上级路由 } else { 
    next(); //如果匹配到正确跳转 } }); 

2. 匹配所有路由–(按照书写的路由顺序匹配)

路由的匹配规则是按照书写的顺序执行的,第一条匹配成功则不去匹配下一条,利用这一特性,可以在所有匹配路由的下面拦截匹配所有路由:

//创建路由对象并配置路由规则 let router = new VueRouter({ 
    routes:[ { 
   path:'/',redirect:{ 
   name:"home"}}, // 重定向到主页 { 
   name:'home',path:'/home',component:Home}, { 
   name:'login',path:'/login',component:Login}, { 
   path:'*',component:NotFound},//全不匹配的情况下,匹配NotFound组件,路由按顺序从上到下,依次匹配。最后一个*能匹配全部, ] }); 

3,next的理解–(不带参是放行,带参是重新跳转)

其实在路由守卫中,只有next()是放行,其他的诸如:next('/logon') 、 next(to) 或者 next({ ...to, replace: true })都不是放行,而是:中断当前导航,执行新的导航

比如说现在我有一个守卫,在守卫中我使用next('/logon'),肯定有同学认为是会直接跳转到/logon路由:

beforeEach((to, from, next) => { 
    next('/logon') } 

然而实际上,它是中断这次导航,重新跳转到新的路由,于是又会触发新的路由守卫,也就是下图这样:

beforeEach((to, from, next) => { 
    beforeEach(('/logon', from, next) => { 
    beforeEach(('/logon', from, next) => { 
    beforeEach(('/logon', from, next) => { 
    beforeEac... // 一直循环下去...... , 因为我们没有使用 next() 放行 } } } } 

如果把这个守卫改一下,当我在地址栏输入/home时:

beforeEach((to, from, next) => { 
    if(to.path === '/home') { 
    next('/logon') } else { 
    // 如果要去的地方不是 /home , 就放行 next() } } 

这样一来,我第一次进入导航守卫是“/home”,但是被重新跳转到“/logon”,于是再次进入导航守卫,这回就走的else路径,next()放行,浏览器中变成/logon。

4,动态添加路由addRoutes()

动态添加路由addRoutes()是异步的,这会导致一个问题,当我们在addRoutes()之后第一次访问被添加的路由会白屏,这是因为刚刚addRoutes()就立刻访问被添加的路由,然而此时addRoutes()没有执行结束,因而找不到刚刚被添加的路由导致白屏。因此需要从新访问一次路由才行。

例如我今天遇到的代码时这样的:

image-20211120112427346

这样的写法,看起来好像没啥问题,但是忽略了请求资源是异步的,addRoutes()也是异步的

先按照代码的设计者的逻辑过一遍(假设这两者都是同步的):

1,登录成功后,to.path是“/home”,这时候路由资源为空,发起请求获取到路由资源,使用addRoutes()添加路由,然后执行next()放行路由,于是浏览器变成/home,匹配上vue-router的路由,懒加载home/index.vue页面,然后发现有嵌套路由,需要重定向,于是变成“/home/homePage(假设是这个)”,再次进入导航守卫,因为已经有路由资源了,就直接next()放行,浏览器变成“/home/homePage",懒加载homePage的组件,于是渲染出页面。 

然而,实际上呢,在第一次to.path是“/home”的时候,虽然发起获取路由资源的请求了,但它是异步的,还没执行完,更别提addRoutes()也是异步,更没执行完毕,于是就先执行底下的next()放行路由了!浏览器就变成/home了。

然而这时候,路由还没添加,肯定是匹配不到的对应路由的,于是白屏,需要等到路由资源请求回来了,并且添加到路由资源中了,才能匹配上路由(实际上这里又会进入一次守卫,可以简单理解为,浏览器在找不到路由时一直在轮询,直至查找到了再次进入导航守卫,执行next(),匹配路由,加载页面)

于是就可以知道,这个白屏的时间。其实取决于请求资源和添加路由的时间。

解决办法

此时就要使用next({ …to, replace: true })来确保addRoutes()时动态添加的路由已经被完全加载上去。

next({ …to, replace: true })中的replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。

因此next({ …to, replace: true })可以写成next({ …to }),不过你应该不希望用户在addRoutes()还没有完成的时候,可以点击浏览器回退按钮搞事情吧。

其实next({ …to })的执行很简单,它会判断:

如果参数to不能找到对应的路由的话,就再执行一次beforeEach((to, from, next)直到其中的next({ …to})能找到对应的路由为止。

也就是说此时addRoutes()已经完成啦,找到对应的路由之后,接下来将执行前往对应路由的beforeEach((to, from, next) ,因此需要用代码来判断这一次是否就是前往对应路由的beforeEach((to, from, next),如果是,就执行next()放行。

如果守卫中没有正确的放行出口的话,会一直next({ …to})进入死循环 !!!

因此你还需要确保在当addRoutes()已经完成时,所执行到的这一次beforeEach((to, from, next)中有一个正确的next()方向出口。

于是我把代码更改成如下的样子:

image-20211120121245756

因为登陆后第一次”/home“时,next({…to,replace:true})第一次执行时,资源必然没有加载好,于是再进入beforeRouter(to,from,next),这时候,如果还没准备好路由资源,则再进一层beforeRouter(to,from,next)直到路由资源准备好了,于是走else中的next()。

到此这篇动态路由下的导航守卫--(to,from,next)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • eslint+prettier+husky的配置说明2024-11-30 22:00:04
  • webpack5配置dev-server在控制台打印信息2024-11-30 22:00:04
  • webpack5学习与实战-(四)-loader2024-11-30 22:00:04
  • webpack5学习与实战-(十)-source_map2024-11-30 22:00:04
  • webpack5学习与实战-(十一)-devServer2024-11-30 22:00:04
  • typroa设置字体的颜色2024-11-30 22:00:04
  • uni.request在接口状态码403等还是走success2024-11-30 22:00:04
  • http抓包实践--(七)-fiddler弱网环境2024-11-30 22:00:04
  • http抓包实践--(六)-fiddler抓包手机2024-11-30 22:00:04
  • http抓包实践--(四)-http压缩和url encode2024-11-30 22:00:04
  • 全屏图片