如何解决vue中避免冗余导航到当前位置错误?

Rob*_*ngh 48 vue.js

我是 vue 新手,在用户登录并重定向到另一条路线后出现错误。基本上我是一名 PHP 开发人员,我在 vue 中使用 laravel。请帮我解决这个错误。

未捕获(承诺)错误:避免了到当前位置的冗余导航:“/admin”。

这里也是截图

在此处输入图片说明

代码

 methods: {
        loginUser() {
            var data = {
                email: this.userData.email,
                password: this.userData.password
            };
            this.app.req.post("api/auth/authenticate", data).then(res => {
                const token = res.data.token;
                sessionStorage.setItem("chatbot_token", token);
                this.$router.push("/admin");
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)

Vue 路线

const routes = [
    {
        path: "/admin",
        component: Navbar,
        name: "navbar",
        meta: {
            authGuard: true
        },
        children: [
            {
                path: "",
                component: Dashboard,
                name: "dashboard"
            },
            {
                path: "users",
                component: Users,
                name: "user"
            }
        ]
    },
    {
        path: "/login",
        component: Login,
        name: "login"
    }
];

const router = new VueRouter({
    routes,
    mode: "history"
});

router.beforeEach((to, from, next) => {
    const loggedInUserDetail = !!sessionStorage.getItem("chatbot_token");
    if (to.matched.some(m => m.meta.authGuard) && !loggedInUserDetail)
        next({ name: "login" });
    else next();
});

Run Code Online (Sandbox Code Playgroud)

bar*_*zko 69

我记得很清楚,你可以在 this.$router.push 之后使用 catch 子句。然后它看起来像:

this.$router.push("/admin").catch(()=>{});
Run Code Online (Sandbox Code Playgroud)

这使您只能避免错误显示,因为浏览器认为异常已处理。

  • 这可以扩展为 `if (this.$route.name !== 'navbar') this.$router.push("/admin").catch(()=>{});` (20认同)
  • 这并不能解决问题,只能避免显示任何问题以更改路线 (15认同)
  • 如果这是调用 `push()` 可能引起的唯一可能有意义的错误,那么当然......但事实并非如此,因此您将抑制来自那里的每个错误消息。这不应该是公认的答案。 (10认同)
  • 这是错误的答案,因为它没有解决 @EmilianoPamont 所说的隐藏的问题。 (3认同)

Luc*_*oke 42

我不认为抑制来自路由器的所有错误是一种好习惯,我只是选择了某些错误,如下所示:

router.push(route).catch(err => {
    // Ignore the vuex err regarding  navigating to the page they are already on.
    if (
      err.name !== 'NavigationDuplicated' &&
      !err.message.includes('Avoided redundant navigation to current location')
    ) {
      // But print any other errors to the console
      logError(err);
    }
  });
Run Code Online (Sandbox Code Playgroud)

  • 这是正确答案! (2认同)

Ado*_*zis 20

也许这是因为您正在尝试路由到现有的$route.matched.path.

对于原始海报

您可能希望通过阻止路由到同一路径来防止错误:

if (this.$route.path != '/admin') {
    this.$router.push("/admin");
}
Run Code Online (Sandbox Code Playgroud)

通用解决方案

如果您要发送动态路由,您可以创建一种方法来检查这一点,使用多个选项之一

  1. 简单:忽略错误
  2. Hard : 比较$route.matched想要的路线

1.忽略错误

您可以捕获NavigationDuplicated异常并忽略它。

pushRouteTo(route) {
    try {
        this.$router.push(route);
    } catch (error) {
       if (!(error instanceof NavigationDuplicated)) {
           throw error;
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然这要简单得多,但它让我感到困扰,因为它会产生一个异常。

2.$route.matched与所需路线进行比较

您可以将其$route.matched与所需路线进行比较

pushRouteTo(route) {
    // if sending path:
    if (typeof(route) == "string") {
        if (this.$route.path != route) {
            this.$router.push(route);
        }
    } else { // if sending a {name: '', ...}
        if (this.$route.name == route.name) {
            if ('params' in route) {
                let routesMatched = true;
                for (key in this.$route.params) {
                    const value = this.$route.params[key];
                    if (value == null || value == undefined) {
                        if (key in route.params) {
                            if (route.params[key] != undefined && route.params[key] != null) {
                                routesMatched = false;
                                break;
                            }
                        }
                    } else {
                        if (key in route.params) {
                            if (routes.params[key] != value) {
                                routesMatched = false;
                                break
                            }
                        } else {
                            routesMatched = false;
                            break

                        }
                    }
                    if (!routesMatched) {
                        this.$router.push(route);
                    }
                }
            } else {
                if (Object.keys(this.$route.params).length != 0) {
                    this.$router.push(route);
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这显然要长得多,但不会引发错误。选择你的毒药。

可运行的演示

您可以在此演示中尝试两种实现:

const App = {
  methods: {
    goToPageCatchException(route) {
      try {
        this.$router.push(route)
      } catch (error) {
        if (!(error instanceof NavigationDuplicated)) {
          throw error;
        }
      }
    },
    goToPageMatch(route) {
    if (typeof(route) == "string") {
        if (this.$route.path != route) {
            this.$router.push(route);
        }
    } else { // if sending a {name: '', ...}
        if (this.$route.name == route.name) {
            if ('params' in route) {
                let routesMatched = true;
                for (key in this.$route.params) {
                    const value = this.$route.params[key];
                    if (value == null || value == undefined) {
                        if (key in route.params) {
                            if (route.params[key] != undefined && route.params[key] != null) {
                                routesMatched = false;
                                break;
                            }
                        }
                    } else {
                        if (key in route.params) {
                            if (routes.params[key] != value) {
                                routesMatched = false;
                                break
                            }
                        } else {
                            routesMatched = false;
                            break

                        }
                    }
                    if (!routesMatched) {
                        this.$router.push(route);
                    }
                }
            } else {
                if (Object.keys(this.$route.params).length != 0) {
                    this.$router.push(route);
                }
            }
        } else {
          this.$router.push(route);
        }
    }
    },
  },
  template: `
  <div>
    <nav class="navbar bg-light">
          <a href="#" @click.prevent="goToPageCatchException({name:'page1'})">Catch Exception</a>
          <a href="#" @click.prevent="goToPageMatch({name:'page2'})">Match Route</a>
    </nav>
    <router-view></router-view>
  </div>`
}
const Page1 = {template: `
  <div class="container">
    <h1>Catch Exception</h1>
    <p>We used a try/catch to get here</p>
  </div>`
}
const Page2 = {template: `
  <div class="container">
    <h1>Match Route</h1>
    <p>We used a route match to get here</p>
  </div>`
}

const routes = [
  { name: 'page1', path: '/', component: Page1 },
  { name: 'page2', path: '/page2', component: Page2 },
]

const router = new VueRouter({
  routes
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
Run Code Online (Sandbox Code Playgroud)
<link href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app"></div>
Run Code Online (Sandbox Code Playgroud)

  • 您可以将完整路径与用作“this.$router.resolve(params).route.fullPath”的路由器解析器进行比较。这将为您提供带有查询参数的完整路径,然后您可以将 === 与当前的 `this.$route.fullPath` 进行比较。 (3认同)

Jac*_* Ng 10

我通过添加以下代码找到了解决方案router.js

import router from 'vue-router'; 

const originalPush = router.prototype.push
router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}
Run Code Online (Sandbox Code Playgroud)


Gki*_*kan 5

为了使这个完整,您还可以比较fromto路由 fullPaths 并将它们相互比较,这在我看来是一个简单、有效和可重用的解决方案。

这是组件方法中的示例:

 move(params){
    // get comparable fullPaths
    let from  = this.$route.fullPath
    let to    = this.$router.resolve(params).route.fullPath

    if(from === to) { 
        // handle any error due the redundant navigation here
        // or handle any other param modification and route afterwards
        return 
    }

    // route as expected
    this.$router.push(params)
}
Run Code Online (Sandbox Code Playgroud)

如果您想使用它,只需将您的路线参数放入其中,例如this.move({ name: 'something' }). 这是在不遇到 try catch 语法的情况下处理重复路由的最简单方法。而且您还可以导出该方法,Vue.prorotype.$move = ...该方法将在整个应用程序中工作。


小智 5

您可以定义和使用这样的函数:

routerPush(path) {
  if (this.$route.path !== path) {
    this.$router.push(path);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这个不是内置的?应该是默认行为,然后可能有强制推送选项。 (3认同)

bra*_*yce 5

提供打字稿解决方案

这个想法是覆盖router.push函数。你可以在一个地方处理(忽略)错误,而不是catch到处写来处理它。

这是覆盖的功能

export declare class VueRouter {
  // ...
  push(
    location: RawLocation,
    onComplete?: Function,
    onAbort?: ErrorHandler
  ): void
}
Run Code Online (Sandbox Code Playgroud)

这是代码

// in router/index.ts

import Vue from 'vue';
import VueRouter, { RawLocation, Route } from 'vue-router';

Vue.use(VueRouter);

const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location: RawLocation): Promise<Route> {
  return new Promise((resolve, reject) => {
    originalPush.call(this, location, () => {
      // on complete

      resolve(this.currentRoute);
    }, (error) => {
      // on abort

      // only ignore NavigationDuplicated error
      if (error.name === 'NavigationDuplicated') {
        resolve(this.currentRoute);
      } else {
        reject(error);
      }
    });
  });
};

// your router configs ...
Run Code Online (Sandbox Code Playgroud)