简体   繁体   English

vue-router 的 beforeEach 守卫偶尔会表现出奇怪的行为

[英]vue-router's beforeEach guard exhibiting weird behaviour occasionally

I've got the following code:我有以下代码:

const routes = [
    { path: '/', component: FooView },
    { path: '/bar', component: BarView } 
];

const router = new VueRouter({
    routes
});

router.beforeEach(function(to, from, next) {
    if (to.path === '/bar') {
        next('/');    
    }

    next();
});

If I've omitted too much and you need to see other pieces of code related to the router let me know so I can fill it in.如果我省略了太多,而您需要查看与路由器相关的其他代码段,请告诉我,以便我填写。

If I open up a new tab and navigate to '/#/bar' I'm successfully redirected to '/#'.如果我打开一个新选项卡并导航到“/#/bar”,我将成功重定向到“/#”。 However, if I then go into the address bar and manually add '/#/bar' and hit enter I am not redirected.但是,如果我随后进入地址栏并手动添加“/#/bar”并按回车键,则不会被重定向。 If I then hit enter in the address bar again I am redirected.如果我再次在地址栏中按 Enter 键,我将重定向。

I've stepped through the code in the console and I see that it is calling next('/') and I see where it calls push('/') inside of next('/') but it doesn't take affect until I've hit enter in the address bar a second time.我已经通过在控制台代码阶梯,我看到它在呼唤next('/')我看到它调用push('/')的内部next('/')但它没有考虑影响直到我第二次在地址栏中按回车键。

I've tried using router.replace('/') but the behaviour is the same.我试过使用router.replace('/')但行为是一样的。 I've tried using beforeEnter on the individual route but the behaviour is also the same.我试过在单独的路线上使用beforeEnter但行为也是一样的。

Two links I've found where similar behaviour is discussed are: https://github.com/vuejs/vue-router/issues/748 and https://forum.vuejs.org/t/router-beforeeach-if-manually-input-adress-in-browser-it-does-not-work/12461/2 but neither helped me.我发现讨论类似行为的两个链接是: https : //github.com/vuejs/vue-router/issues/748https://forum.vuejs.org/t/router-beforeeach-if-manually -input-adress-in-browser-it-does-not-work/12461/2但都没有帮助我。

Is someone able to explain this?有人能解释一下吗? Is there a disconnect between what I'm trying to do and what functionality vue-router provides?我正在尝试做的事情与 vue-router 提供的功能之间是否存在脱节? If this behaviour isn't expected can someone propose a work around?如果这种行为不是预期的,有人可以提出解决方法吗?

In the vue-router official documentation, the way you implement the beforeEach() is not recommended. vue-router官方文档中,不推荐你实现beforeEach()的方式。 Here is what the documentation says:以下是文档中的内容:

Make sure that the next function is called exactly once in any given pass through the navigation guard.确保在通过导航守卫的任何给定传递中,下一个函数只被调用一次。 It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors.它可以出现多次,但前提是逻辑路径没有重叠,否则钩子永远不会被解析或产生错误。 Here is an example of redirecting to user to /login if they are not authenticated:这是一个重定向用户到 /login 的示例,如果他们未通过身份验证:

// BAD
router.beforeEach((to, from, next) => {
  if (!isAuthenticated) next('/login')
  // if the user is not authenticated, `next` is called twice
  next()
})
// GOOD
router.beforeEach((to, from, next) => {
  if (!isAuthenticated) next('/login')
  else next()
})

Not sure why the first one is a bad example, since both sample code should work exactly the same logically.不知道为什么第一个是一个不好的例子,因为两个示例代码在逻辑上应该完全相同。 My code pops error when the first time redirect the path using next('/'), however, the rerouting still success.我的代码在第一次使用 next('/') 重定向路径时弹出错误,但是,重新路由仍然成功。 Looking for answer from pros.寻找专业人士的答案。

Without getting too excited (a lot of testing left to do) it appears as though I've managed to fix my issue.没有太兴奋(还有很多测试要做),看来我已经设法解决了我的问题。

Instead of:而不是:

router.beforeEach(function(to, from, next) {
    if (to.path === '/bar') {
        next('/');    
    }

    next();
});

I changed the code to the following:我将代码更改为以下内容:

router.beforeEach(function(to, from, next) {
    if (to.path === '/bar') {
        next('/');

        return;
    }

    next();
});

Note the added return;注意增加的return; in the if statement.在 if 语句中。

I still have questions about the behaviour.我仍然对行为有疑问。 In particular I need too investigate deeper why sometimes it would hit the route when the only difference is whether it is the first or second time I entered the URL into the address bar.特别是我需要更深入地调查为什么有时它会命中路由,唯一的区别是我第一次还是第二次将 URL 输入到地址栏中。 I'm sure diving deeper into next will answer my question.我相信深入研究next会回答我的问题。

Anyway, adding the return;无论如何,添加return; turned this into a non blocker.把它变成了一个非阻塞器。

As other answers mention, the next() function should be called exactly once inside the same guard.正如其他答案所提到的, next()函数应该在同一个守卫内被调用一次。
It is important that it is called at least once or the guard will never complete and block the navigation.重要的是它至少被调用一次,否则守卫将永远不会完成并阻止导航。

As taken from the docs -->取自文档-->

Make sure that the next function is called exactly once in any given pass through the navigation guard.确保在通过导航守卫的任何给定传递中,下一个函数只被调用一次。 It can appear more than once, but only if the logical paths have no overlap, otherwise the hook will never be resolved or produce errors它可以出现多次,但前提是逻辑路径没有重叠,否则钩子永远不会被解析或产生错误

The next() function signals that this guard has finished and the next guard may be called. next()函数表示这个守卫已经完成并且可以调用下一个守卫。
By doing this it is possible to create asynchronous guards that only finish when the next() function is called.通过这样做,可以创建仅在调用 next() 函数时完成的异步保护。

However the rest of the code inside the guard is still executed.然而,守卫内的其余代码仍然被执行。
This means that if you call next() several times it will cause unpredictable behavior.这意味着如果多次调用next()将导致不可预测的行为。

// This will work
if(condition){
  next();
}
else{
  next();
}

// This cause you pain!
next();
next();



The 'next' function also takes parameters: 'next' 函数也接受参数:
 // This aborts the current navigation and "stays" on the same route next(false) // These navigate to a different route than specified in the 'to' parameter next('/'); next({path: '/'}) next({path: '/', query: {urlParam: 'value'}}) // or any option used in router.push -> https://router.vuejs.org/api/#router-forward // If the argument passed to next is an instance of Error, // the navigation will be aborted and the error // will be passed to callbacks registered via router.onError(). next(new Error('message'))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM