如何解决vue中避免冗余导航到当前位置错误?
Posted
技术标签:
【中文标题】如何解决vue中避免冗余导航到当前位置错误?【英文标题】:How to solve Avoided redundant navigation to current location error in vue? 【发布时间】:2020-10-09 05:40:15 【问题描述】:我是 vue 新手,在用户登录并重定向到另一条路线后出现错误。 基本上我是一名 php 开发人员,我使用 laravel 和 vue。请帮我解决这个错误。
未捕获(承诺)错误:避免重复导航到当前位置:“/admin”。
这也是截图
Vue 代码
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");
);
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();
);
【问题讨论】:
【参考方案1】:除了上面提到的解决方案:一个方便的方法是把这个sn-p放到main.js中,让它成为一个全局函数
Vue.mixin(
/**
* Avoids redundand error when navigating to already active page
*/
routerPush(route)
this.$router.push(route).catch((error) =>
if(error.name != "NavigationDuplicated")
throw error;
)
,
)
现在你可以调用任何组件了:
this.routerPush('/myRoute')
【讨论】:
【参考方案2】:在router/index.js
,初始化后
// init or import router..
// keep original function
const _push = router.__proto__.push
// then override it
// error handler
const onError = (e) =>
if (e.name !== 'NavigationDuplicated') throw e
// avoid NavigationDuplicated
const _push = router.__proto__.push
router.__proto__.push = function push (...args)
try
const op = _push.call(this, ...args)
if (op instanceof Promise) op.catch(onError)
return op
catch (e)
onError(e)
【讨论】:
【参考方案3】:清洁解决方案;)
将代码移至 util 函数。所以你可以用它替换所有this.$router.push
。
import router from '../router'; // path to the file where you defined
// your router
const goToRoute = (path) =>
if(router.currentRoute.fullPath !== path) router.push(path);
export
goToRoute
【讨论】:
【参考方案4】:-
对于组件
<router-link>
您可以创建一个新组件来代替<router-link>
。
组件名称:<to-link>
<template>
<router-link :to="to" :event="to === $route.path || loading ? '' : 'click'" :class="classNames">
<slot></slot>
</router-link>
</template>
<script>
export default
name: 'ToLink',
props:
to:
type: [String, Number],
default: ''
,
classNames:
type: String,
default: ''
,
loading:
type: Boolean,
default: false
</script>
对于绑定:
import ToLink from '@/components/to-link'
Vue.component('to-link', ToLink)
$router.push()
需要创建全局方法。
toHttpParams(obj)
let str = ''
for (const key in obj)
if (str !== '')
str += '&'
str += key + '=' + encodeURIComponent(obj[key])
return str
,
async routerPush(path, queryParams = undefined, params = undefined, locale = true)
let fullPath = this.$route.fullPath
if (!path)
path = this.$route.path
if (!params)
params = this.$route.params
if (queryParams && typeof queryParams === 'object' && Object.entries(queryParams).length)
path = path + '?' + this.toHttpParams(queryParams)
if (path !== fullPath)
const route = path, params, query: queryParams
await this.$router.push(route)
【讨论】:
【参考方案5】:聚会迟到了,但想加我的 10 美分。大多数答案 - 包括被接受的答案都试图隐藏异常而不找到导致错误的根本原因。我在我们的项目中确实遇到了同样的问题,并且感觉这与 Vue/Vue 路由器有关。最后,我设法证明自己错了,这是由于我们在 App.vue 中的代码段替换了路由以及与 index.ts 中类似的逻辑。
this.$router.replace( name: 'Login' )
因此,请尝试搜索并查找是否有任何代码调用 $router.replace 或 $router.push 来表示您担心的路线 - “/admin”。只是您的代码必须多次调用该路由,而不是 Vue 神奇地尝试多次调用它。
【讨论】:
【参考方案6】:我通过将以下代码添加到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)
【讨论】:
谢谢你的这段代码解决了我的问题【参考方案7】:为了使这个完整,您还可以比较 from
和 to
路由 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)
如果您想使用它,只需将您的路由参数放入其中,例如 this.move( name: 'something' )
。这是处理重复路由而不遇到 try catch 语法的最简单方法。您还可以在Vue.prorotype.$move = ...
中导出该方法,该方法适用于整个应用程序。
【讨论】:
谢谢。这个解决方案很简单,解决了我的问题。【参考方案8】:短解:
if (this.$router.currentRoute.name !== 'routeName1')
this.$router.push(
name: 'routeName2',
)
【讨论】:
【参考方案9】:我遇到了这个问题,我就这样解决了。
通过在我的路由器文件中添加它
从'vue-router'导入路由器
Vue.use(路由器)
const originalPush = Router.prototype.push
Router.prototype.push = function push(location)
return originalPush.call(this, location).catch(err => err)
【讨论】:
【参考方案10】:提供 Typescript 解决方案
这个想法是覆盖router.push
函数。您可以在一个地方处理(忽略)错误,而不是到处写catch
来处理它。
这是要覆盖的函数
export declare class VueRouter
// ...
push(
location: RawLocation,
onComplete?: Function,
onAbort?: ErrorHandler
): void
这里是代码
// 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 ...
【讨论】:
谢谢你! Vue 更适合让人们提供 Typescript 示例! 很好的解决方案,虽然检查是否忽略错误应该是error.name === 'NavigationDuplicated' || error.message.includes('Avoided redundant navigation to current location')
。检查错误名称对我不起作用。【参考方案11】:
我遇到了同样的问题,当我寻找解决方案时,我发现了.catch(() => )
,它实际上是在告诉浏览器我们已经处理了错误,请不要在开发工具中打印错误:) 呵呵呵呵不错的hack!但我认为忽略错误不是解决方案。所以我做了什么,我创建了一个实用函数,它接受两个参数router, path
,并将其与当前路线的路径进行比较,如果两者相同,则意味着我们已经在该路线上并且它忽略了路线更改。这么简单:)
这里是代码。
export function checkCurrentRouteAndRedirect(router, path)
const
currentRoute: path: curPath
= router;
if (curPath !== path) router.push( path );
checkCurrentRouteAndRedirect(this.$router, "/dashboard-1");
checkCurrentRouteAndRedirect(this.$router, "/dashboard-2");
【讨论】:
【参考方案12】:这意味着 - 您想要导航到与当前路线相同的路线,而 Vue 不想再次触发一切。
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);
// Here you conditioally navigate to admin page to prevent error raised
if(this.$route.name !== "/admin")
this.$router.push("/admin");
);
【讨论】:
【参考方案13】:你可以定义和使用这样的函数:
routerPush(path)
if (this.$route.path !== path)
this.$router.push(path);
【讨论】:
为什么不是内置的??应该是默认行为,然后可能会有强制推送选项。【参考方案14】:我想这个答案来得太晚了。我没有发现错误,而是寻找一种防止错误出现的方法。因此,我通过一个名为pushSave
的附加功能增强了路由器。可能这也可以通过 navGuards 完成
VueRouter.prototype.pushSave = function(routeObject)
let isSameRoute = true
if (this.currentRoute.name === routeObject.name && routeObject.params)
for (const key in routeObject.params)
if (
!this.currentRoute.params[key] ||
this.currentRoute.params[key] !== routeObject.params[key]
)
isSameRoute = false
else
isSameRoute = false
if (!isSameRoute)
this.push(routeObject)
const router = new VueRouter(
routes
)
您可能已经意识到,这只有在您提供类似的 routeObject 时才有效
this.$router.pushSave( name: 'MyRoute', params: id: 1 )
因此您可能需要对其进行增强以使其也适用于字符串
【讨论】:
【参考方案15】:我在项目的main.js
文件中添加了以下代码,错误消失了。
import Router from 'vue-router'
const routerPush = Router.prototype.push
Router.prototype.push = function push(location)
return routerPush.call(this, location).catch(error => error)
;
【讨论】:
【参考方案16】:这可能是因为您正在尝试路由到现有的$route.matched.path
。
原始海报
您可能希望通过阻止指向同一路径的路由来防止错误:
if (this.$route.path != '/admin')
this.$router.push("/admin");
通用解决方案
如果您正在发送动态路由,您可以创建一个方法来检查这一点,使用几个选项之一
-
简单:忽略错误
困难:将
$route.matched
与所需路线进行比较
1。忽略错误
您可以捕获NavigationDuplicated
异常并忽略它。
pushRouteTo(route)
try
this.$router.push(route);
catch (error)
if (!(error instanceof NavigationDuplicated))
throw error;
虽然这要简单得多,但它让我很困扰,因为它会产生异常。
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);
这显然要长得多,但不会引发错误。选择你的毒药。
可运行的演示
您可以在此演示中尝试这两种实现:
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')
<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>
【讨论】:
您可以将完整路径与用作this.$router.resolve(params).route.fullPath
的路由器解析器进行比较。这将为您提供带有查询参数的完整路径,然后您可以将 === 与当前的 this.$route.fullPath
进行比较。【参考方案17】:
我记得很清楚,你可以在 this.$router.push 之后使用 catch 子句。然后它看起来像:
this.$router.push("/admin").catch(()=>);
这允许您只避免显示错误,因为浏览器认为异常已被处理。
【讨论】:
这个可以扩展为if (this.$route.name !== 'navbar') this.$router.push("/admin").catch(()=>);
不解决问题,只避免显示任何问题改变路线
如果这是调用push()
可能产生的唯一可能的有意义的错误,那么当然......但事实并非如此,因此您将抑制来自那里的每条错误消息。这不应该是公认的答案。
太棒了! tnks这么多
这是错误的答案,因为它不能解决 @EmilianoPamont 所说的隐藏的问题。【参考方案18】:
我认为抑制路由器的所有错误并不是一个好习惯,我只是挑选了某些错误,如下所示:
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);
);
【讨论】:
以上是关于如何解决vue中避免冗余导航到当前位置错误?的主要内容,如果未能解决你的问题,请参考以下文章