问题
您好,开发人员
我有一个问题,当我想进行多次搜索时会显示NavigationDuplicated
错误。我的搜索是在导航栏中,而我配置搜索的方式是使用模型获取值,然后将该值作为参数传递给ContentSearched组件,然后在该组件中接收搜索的值。
我知道正确的方法是使用发射器,但是我仍然不知道如何学习使用它。要访问发射,是context.emit('', someValue)
如果有人可以帮助我解决问题,我将不胜感激。
NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated", message: "Navigating to current location ("/search") is not allowed", stack: "Error↵ at new NavigationDuplicated (webpack-int…node_modules/vue/dist/vue.runtime.esm.js:1853:26)"}
NavBar.vue
<template>
<nav class="navbar navbar-expand-lg navbar-dark bg-nav" v-bind:class="{'navbarOpen': show }">
<div class="container">
<router-link to="/" class="navbar-brand">
<img src="../assets/logo.png" alt="Horizon Anime" id="logo">
</router-link>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" v-on:click.prevent="toggleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent" v-bind:class="{'show': show }">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<router-link class="nav-link" to="/" ><i class="fas fa-compass"></i> Series</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="{name: 'EpisodesSection'}" ><i class="fas fa-compact-disc"></i> Episodios</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="{name: 'MovieSection'}" ><i class="fas fa-film"></i> Peliculas</router-link>
</li>
</ul>
<div class="search-bar">
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" v-model="query" type="search" placeholder="Buscar películas, series ..." aria-label="Search">
<button class="btn btn-main my-2 my-sm-0" @click.prevent="goto()" type="submit"><i class="fas fa-search"></i></button>
</form>
</div>
</div>
</div>
</nav>
</template>
<script>
import {value} from 'vue-function-api';
import {useRouter} from '@u3u/vue-hooks';
export default {
name: "NavBar",
setup(context){
const {router} = useRouter();
const query = value("");
let show = value(true);
const toggleNavbar = () => show.value = !show.value;
const goto = () =>{
let to = {name: 'ContentSearched' , params:{query: query}}
router.push(to);
};
return{
show,
toggleNavbar,
goto,
query
}
}
}
</script>
ContentSearched.vue
<template>
<div class="container">
<BoxLink/>
<main class="Main">
<div class="alert alert-primary" role="alert">
Resultados para "{{query}}"
</div>
<div v-if="isLoading">
<!-- <img class="loading" src="../assets/loading.gif" alt="loading"> -->
</div>
<div v-else>
<ul class="ListEpisodios AX Rows A06 C04 D02">
<li v-for="(content, index) in contentSearched" :key="index">
<div v-if="content.type === 'serie'">
<Series :series="content"/>
</div>
<div v-if="content.type === 'pelicula'">
<Movies :movies="content"/>
</div>
</li>
</ul>
</div>
</main>
</div>
</template>
<script>
import {onCreated} from "vue-function-api"
import {useState , useRouter , useStore} from '@u3u/vue-hooks';
import BoxLink from "../components/BoxLink";
import Movies from "../components/Movies";
import Series from "../components/Series";
export default{
name: 'ContentSearched',
components:{
BoxLink,
Movies,
Series
},
setup(context){
const store = useStore();
const {route} = useRouter();
const state = {
...useState(['contentSearched' , 'isLoading'])
};
const query = route.value.params.query;
onCreated(() =>{
store.value.dispatch('GET_CONTENT_SEARCH' , query.value);
});
return{
...state,
query,
}
}
};
</script>
答案 0 :(得分:15)
我只想使NavigationDuplicated
错误保持沉默,空捕获可能很危险。所以我这样做了:
const router = new VueRouter({/* ... */})
function patchRouterMethod (router, methodName)
{
router['old' + methodName] = router[methodName]
router[methodName] = async function (location)
{
return router['old' + methodName](location).catch((error) =>
{
if (error.name === 'NavigationDuplicated')
{
return this.currentRoute
}
throw error
})
}
}
patchRouterMethod(router, 'push')
patchRouterMethod(router, 'replace')
在初始化vue-router时插入一次。
答案 1 :(得分:14)
当我有一个router-link
指向同一路线时,这发生在我身上。例如/products/1
。
用户可以单击产品,,但是如果已经单击产品(并且已经加载了组件视图),并且用户尝试再次单击它,则会显示错误/警告在控制台中。
您可以了解更多on the github issue.。
Posva是vue-router的主要贡献者之一:
router.push('您的路径').catch(err => {})
但是,如果您不想让一个catch
块什么也不做,为了解决此问题,您可以将路由器导航与当前路径进行比较,并且仅在它们不同时进行导航:
const path = `/products/${id}`
if ($route.path !== path) this.$router.push(path)
注意:$route
是vue-router向每个组件提供的对象
答案 2 :(得分:11)
我认为,如果我们不打算进一步使用Router.push
作为异步调用,则可以在根标签上解决此问题的最佳解决方案。
import Router from 'vue-router';
const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
};
Vue.use(Router);
答案 3 :(得分:8)
我在搜索时遇到了同样的问题。我的解决方案是在搜索页面的timestamp
参数中添加this.$route.query
。
this.$router.push({
path: "/search",
query: {
q: this.searchQuery,
t: new Date().getTime(),
}
});
希望对您有帮助。
答案 4 :(得分:7)
在手册中:
router.push(location, onComplete?, onAbort?)
您可以更简单地使用
router.push("/", () => {});
答案 5 :(得分:6)
如果您在代码中使用router.push,并且不关心导航失败,则应使用catch来捕获它:
router.push('/location').catch(err => {})
答案 6 :(得分:3)
您在这里混合了多个概念,从router-link
到程序化导航,向状态存储查询参数。这使得帮助您和告诉您这里的“正确”解决方案有点困难。
不过,我认为最适合您的方法是:
1)将您的路线定义为
{
path: "/search/:searchString",
component: MySearchComponent,
props: true
}
2)使用响应式<router-link>
而不是您的router.push
<input type="text" v-model="searchString">
<router-link :to="'/search/'+searchString" tag="button">search</router-link>
3)通过searchString
和props: ['searchString']
来访问搜索组件中的this.searchString
props: ['searchString'],
...
computed: {
msg() {
return `Searching for, ${this.searchString}!`;
}
}
完整示例:https://codesandbox.io/s/vue-routing-example-9zc6g
请注意,我只是用可以找到的router
分叉了第一个codeandbox,并进行了相应调整。
答案 7 :(得分:1)
如果您不愿意捕获所有类型的错误,我认为此实现更体贴:
this.$router.push("path").catch(error => {
if (error.name != "NavigationDuplicated") {
throw error;
}
});
答案 8 :(得分:1)
我迟到了,但我想我会添加我的解决方案来解决这个问题,因为它没有列出:我只是放置了一个中间搜索页面作为搜索结果视图的传递。我现在正在使用此页面对搜索词进行一些预处理。
页面模板就是:
<template>
<div>searching ...</div>
</template>
NavigationDuplicated 错误现在消失了,作为一个额外的好处,因为我在这个中间页面中执行提取,错误处理的责任与搜索栏和结果视图隔离。
答案 9 :(得分:0)
我的解决方案是扩展 prototype
和检查 Navigation Duplicated Error
的混合。其他错误和警告应该是可见的。生产一周后 - 没有 NavigationDuplicated
,一切正常。
import { equals } from 'ramda'
export function register(Vue) {
const routerPush = Router.prototype.push
const routerReplace = Router.prototype.push
const isNavigationDuplicated = (currentRoute, nextRoute) => {
const { name: nextName, params: nextParams = {}, query: nextQuery = {} } = nextRoute
const { name, params, query } = currentRoute
return equals(nextQuery, query) && equals(nextParams, params) && equals(nextName, name)
}
Router.prototype.push = function push(location) {
if (!isNavigationDuplicated(this.currentRoute, location)) {
return routerPush.call(this, location)
}
}
Router.prototype.replace = function replace(location) {
if (!isNavigationDuplicated(this.currentRoute, location)) {
return routerReplace.call(this, location)
}
}
Vue.use(Router)
}
答案 10 :(得分:0)
我在这里发布了我找到的解决方案,因为我无法在某处找到它的详细记录,我通过反复试验完成了它。 它可能对某人有用,或者某人可能会纠正我对 vue-router 守卫的误解。
它使用 vue-router V4.x 和全局 beforeEach
保护。
用例是:
https://app.com/
;https://app.com/
已被授权;路线:
const routes = [
/**
* Routes not requiring auth
*/
{
path: '/',
component: () => import('layouts/NotAuthorizedLayout.vue'),
children: [
{
path: 'login',
name: 'LOGIN',
component: () => import('pages/Login.vue')
},
{
path: 'emailsignup',
component: () => import('pages/EmailSignup.vue')
},
{
path: 'forgottenpassword',
component: () => import('pages/ForgottenPassword.vue')
}
]
},
/**
* Routes requiring auth
*/
{
path: '/',
component: () => import('layouts/AuthorizedLayout.vue'),
meta: { requiresAuth: true },
children: [
{
path: 'authors',
name: 'AUTHORS',
component: () => import('pages/Authors.vue')
},
{ path: 'profile', component: () => import('pages/userProfile/index.vue') }
]
}
];
beforeEach global guard:
const redirectToLogin = route => {
const LOGIN = 'LOGIN';
if (route.name != LOGIN) {
return { name: LOGIN, replace: true, query: { redirectFrom: route.fullPath } };
}
};
const redirectToHome = route => {
const DEFAULT = 'AUTHORS';
return { name: DEFAULT, replace: true };
};
Router.beforeEach((to, from) => {
const userIsAuthenticated = store.getters['authentication/userIsAuthenticated'];
const requiresAuth = to.matched.some((route) => route.meta && route.meta.requiresAuth);
if (!userIsAuthenticated && to.fullPath === '/') {
return redirectToLogin(to);
}
if (!userIsAuthenticated && requiresAuth) {
return redirectToLogin(to);
}
if (to.fullPath === '/') {
return redirectToHome(to);
}
return true;
});
答案 11 :(得分:0)
你的问题比较老了。
您的错误是“@click.prevent”。这个语句不起作用,因为你的按钮是一个提交按钮(所以你的事件被调用了两次)。
使用“@submit.prevent”应该可以(或更改按钮的类型)。
答案 12 :(得分:0)
我注意到当我尝试用相同的值替换 url 查询参数时出现错误。
我有选择过滤器和 url 查询字符串参数与它们的值同步。只要您更改为新值,它就可以正常工作。如果值保持不变(例如从历史记录中返回)并因此用相同的值替换查询字符串参数,则会弹出错误。
解决方案是检查值是否更改,然后替换路由器中的查询参数:
let newValue = 'foo'; // new query value for parametar
let qcopy = { ...this.$route.query }; // clone current query
// prevent NavigationDuplicated: Avoided redundant navigation to current location
if (qcopy['your_param'] != newValue){
qcopy['your_param'] = newValue;
this.$router.replace({query: qcopy});
}
答案 13 :(得分:-1)
这是一个简单而有效的解决方案:
if(from.fullPath === to.fullPath){
return
}