在Vue.js中不修改URL的情况下重定向到404页面

4

在我的Vue.js项目中,如果路由参数无效,我想要显示我的404页面。目前,我正在使用以下代码:

this.$router.replace({ path: '/404' });

有没有一种方法可以不修改URL就实现这个功能?我希望用户仍然能够复制浏览器的原始URL。有没有某种“silent:true”参数?

可能会有帮助:https://github.com/vuejs/vue-router/issues/977 - Farkhat Mikhalko
很抱歉,不行。我已经找到了那个讨论。在我的情况下,重定向应该是从视图本身开始的。 - André Reichelt
4个回答

7

vue-router中,URL是真实的来源。如果URL发生改变,渲染也会发生相应的变化。你不能“暂停”路由(这是一个困扰我已久的vue-router缺陷,但我就不展开了)。

你只需要在不修改路由的情况下显示404页面。在你的根组件中添加一个display404数据属性,并在模板中手动设置它来显示404页面,而不使用<router-view>,例如:

<div>
  <my-404-page v-if="display404"/>
  <router-view v-else/>
</div>

要从任何组件显示404页面:
this.$root.display404 = true

当然,这只是一个基本示例,用于演示我的意思。您可以使用Vuex共享状态,或使用事件总线,或以其他适合您的方式显示404页面等等。


嗯,看起来很不专业,但至少这是一个解决方案。我在想,这是否真的是一个非常特殊的需求,以至于没有被广泛应用的标准功能来满足它。 - André Reichelt
没有(官方的)方法可以让 vue-router 在不改变 URL 的情况下显示特定路由。vue-router 无法进入视图与 URL 不一致的状态。 - Decade Moon
这将导致404页面显示在您的子页面内,这是您想要的吗? - Decade Moon
那样完全没问题。我已经尝试过这种方法:<template><div v-if="clientSettings">...</div><div v-else>我怎么在这里获取错误页面?</div></template> - André Reichelt
你什么时候设置 this.$root.display404 = false - Rtbo
显示剩余3条评论

5

这个问题在Vue Router 4中得到了解决,您可以在文档的第二个例子中看到

按照以下方式构建您的NotFound路由:

{ 
  path: '/:pathMatch(.*)*', 
  name: 'NotFound', 
  component: NotFound 
},

接着,您可以在动态 Vue 上使用一个名为 beforeEnter 的导航守卫,用法如下:

// In your router/index.js file...
{
  path: 'users/:id',
  name: 'User Detail',
  component: UserDetail,
  beforeEnter(to, from) {
    // See if that query exists in your data...
    const exists = data.users.find(
      user => user.id === parseInt(to.params.id)
    )
    if (!exists) {
      // THE IMPORTANT PART
      // Return your not found view...
      return {
        name: 'NotFound',
        // Match the path of your current page and keep the same url...
        params: { pathMatch: to.path.split('/').slice(1) },
        // ...and the same query and hash.
        query: to.query,
        hash: to.hash,
      }
    }
  }
}

尚未在组件中测试过这个内容,但我认为在beforeRouteEnter 导航守卫中的逻辑应该是相同的。

这不会给你返回404状态码,对吧? - undefined
我试图做一些类似于你的代码的事情,但由于斜杠字符,我得到的URL带有%F2。现在有了你的一些代码,我可以为404页面保留一个动态URL。next({ name: 'NotFound', params: { pathMatch: to.path.split('/').slice(1) }, query: to.query, hash: to.hash }) - undefined

0

不太确定您的问题是什么,但以下两个方案是否有所帮助?

一种是使用通配符路由: 来自Vue.js文档的“通配符路由”

另一种是如果您正在处理调用的响应表单(方法/获取等):请使用try/catch的组合和“loading”数据值来更改显示或加载哪个组件。


我已经实现了这个。但是有时候,如果我的视图中的某个ajax调用出错,我还想重定向到那里定义的404页面。类似于 axios.get('someData').then(d => doSomething()).catch(err => display404Page()); - André Reichelt
转到 https://www.amazon.com/asdf 并注意它显示404页面而不更改根目录。这就是我们要找的。 - Zack Plauché
你能否将路由器传递到显示404页面函数中?display404Page(this.$router)或者让错误“冒泡”到axios.get函数被调用的位置?例如存储操作或组件方法。然后处理它,这是我所做的,并保持axios脚本的整洁。它还可以让你分离关注点。 - user3067684

0

根据 Decade Moon 的解决方案,我做了以下操作:

main.js

import Error404 from './views/error/404.vue'

Vue.component('error-404', Error404)

404.vue

<template>
    <div>
        <h1>Page not found</h1>
        <p>Whatever...</p>
    </div>
</template>

<script>
    export default {
        name: 'Page not found'
    }
</script>

路由器 --> index.js

const PageNotFound = () => import('@/views/error/404')

function configRoutes() {
    return [
        {
            path: '/',
            name: 'Home',
            component: TheContainer,
            children: [
                // ...
                {
                    path: '404',
                    name: 'Page not found',
                    component: PageNotFound,
                    alias: '*'
                }
            ]
        }
    ]
}

我的页面应该显示404错误

<template>
    <div class="animated fadeIn" v-if="clientSettings">
        ...
    </div>
    <error-404 v-else></error-404>
</template>

<script>
    export default {
        name: 'Test',
        data() {
            return {
                clientSettings: null
            };
        },
        async created() {
            this.setClientConfig();
        },
        watch: {
            '$route.params.id': function (id) { this.setClientConfig(id);}
        },
        methods: {
            setClientConfig(id) {
                if (!id) {
                    id = this.$route.params.id;

                    // Redirect to the first valid list, if no parameter is proviced
                    if (!id) {
                        this.$router.push({ name: 'Test', params: { id: this.$root.clientConfiguration[0].name } });
                        return;
                    }
                }

                // Set client settings
                this.clientSettings = this.$root.clientConfiguration.find(cc => cc.name === id);
                // This will return null, if no entry was found, therefore the template will jump into the v-else
            }
        }
    }
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接