组件内导航防护回调不起作用:Nuxt JS 和 `beforeRouteEnter`

Mon*_*ist 5 javascript vue.js vue-router vuejs2 nuxt.js

我有一个使用 Nuxt JS 构建的搜索表单和一个结果页面。如果表单返回错误,我正在尝试将结果页面重定向pages/results/index.vue回搜索页面pages/search/index.vue

我正在尝试根据 Vue 文档使用组件内保护

根据文档:

但是,您可以通过将回调传递给 next 来访问该实例。确认导航时将调用回调,并将组件实例作为参数传递给回调:

beforeRouteEnter (to, from, next) {
  next(vm => {
    // access to component instance via `vm`
  })
}
Run Code Online (Sandbox Code Playgroud)
beforeRouteEnter (to, from, next) {
  next(vm => {
    // access to component instance via `vm`
  })
}
Run Code Online (Sandbox Code Playgroud)

我的主要问题是next()导航守卫中函数中的回调似乎无法重新路由页面。

(页)

// version info

??? nuxt@2.10.1
? ??? @nuxt/builder@2.10.1
? ? ??? @nuxt/vue-app@2.10.1
? ?   ??? vue@2.6.10  deduped
? ??? @nuxt/core@2.10.1
?   ??? @nuxt/vue-renderer@2.10.1
?     ??? vue@2.6.10  deduped
??? vue-glide-js@1.3.12
  ??? vue@2.6.10
Run Code Online (Sandbox Code Playgroud)

以上工作正常,其中doSearch验证表单并将结果(以及任何错误)添加到商店。

但是接下来...

(页)

// page/search/index.vue

<template>
  ...
  <nuxt-link to="/results" @click.native="doSearch">
    Show Results
  </nuxt-link>
  ...
</template>

<script>
export default {
  ...
  methods: {
    doSearch () {
      ... // validates search fields and adds content to store
    }
  },
  ...
}
</script>
Run Code Online (Sandbox Code Playgroud)

回调 inbeforeRouteEnter似乎没有被评估,也不会导致路由改变。请注意,日志显示回调正在触发并返回正确的值。

如果我明确定义路由,而不使用回调函数,它会起作用:

// pages/results/index.vue

<script>
export default {
  ...
  beforeRouteEnter (to, from, next) {
    next((vm) => {
      console.log(vm.validateRoute()) // works: '/search'
      vm.validateRoute()              // does not work: does nothing
    })
  },
  ...
  computed: {
    errors () {
      return this.$store.state.errors
    }
  },
  ...
  async fetch ({ store, params }) {
    await store.dispatch('searchresults/GET_RESULTS')
  },
  ...
  methods: {
    validateRoute () {
      let route = true
      if (this.errors.length > 0) {
        route = '/search'
      }
      console.log(this.erros.length)  // works: 7
      console.log(route)              // works: '/search'
      return route
    }
  },
  ...
}
</script>
Run Code Online (Sandbox Code Playgroud)

我尝试了几次迭代,但next(callback)效果有限……

// pages/results/index.vue

<script>
export default {
  ...
  beforeRouteEnter (to, from, next) {
    next('/search')                   // works: re-routes to '/search' every time
  },
  ...
}
</script>
Run Code Online (Sandbox Code Playgroud)
next(() => { return false })          // does not work
Run Code Online (Sandbox Code Playgroud)

但只有显式声明才有效......

next(function () { return false })    // does not work
Run Code Online (Sandbox Code Playgroud)
next({ path: false })                 // works: prevents route change
Run Code Online (Sandbox Code Playgroud)

我不知所措;这是一个错误,还是我错过了什么?

附录

我之前尝试使用这里Nuxt 文档中提到的中间件。然而,这会导致无限循环,如本博客文章中所述

next({ path: '/search' })             // works: changes route to '/search'
Run Code Online (Sandbox Code Playgroud)

固定的

正如@ifaruki所指出的,将中间件调用放置在页面组件内可以解决无限循环问题:

下一步是将中间件添加到页面 pages/results/index.vue 中,如下所示:

export default {
   middleware: 'validate'
} 
Run Code Online (Sandbox Code Playgroud)

在文档的最后发现了这个,它似乎是Vue JS In-component Guards的 Nuxt 方法:

您也可以将中间件添加到特定布局或页面:

pages/index.vue 或者 layouts/default.vue

:脸掌:

Ifa*_*uki 2

对于这种情况,nuxt.js 有一个名为 的属性middleware

你可以用middleware来代替守卫。在您的中间件文件夹中,您首先创建一个名为validate.js.

在您的validate.js文件中,您创建一个函数并将验证逻辑放入其中:

export default function ({ store, redirect }) {
  if (store.state.errors.length > 0) {
    return redirect('/search')
  }
}
Run Code Online (Sandbox Code Playgroud)

现在您已经设置了中间件。下一步是将中间件添加到页面,pages/results/index.vue如下所示:

export default {
   middleware: 'validate'
} 
Run Code Online (Sandbox Code Playgroud)

中间件总是在创建 vue 实例之前调用。每当store.state.errors大于 0 时,您将被重定向回,/search否则该中间件将被忽略。

始终首先阅读 nuxt 文档,因为 nuxt 并不总是具有与 vue.js 或 vue.js 路由器相同的行为 官方文档:https ://nuxtjs.org/api/pages-middleware