路由器钩子
路由导航的总体流程如下图所示:

一旦在某个路由上触发了导航,Vue 路由器就会为开发人员提供几个主要的导航保护或钩子,以保护或拦截导航过程。根据类型的不同,这些保护可以在全局或组件中挂钩。下面是一些示例:
-
全局:beforeEach、beforeResolve 和 afterEach
-
每个组件:beforeEnter
-
组件内:beforeRouteUpdate、beforeRouteEnter 和 beforeRouterLeave
如图 6.23 所示,只有在所有 Hook 或防护(包括任何异步防护)都已解析(resolved)后,导航才被视为完成。 现在,让我们看看如何设置 beforeEach Hooks。
设置 beforeEach 钩子
beforeEach 是一个全局 Hook,在导航开始时调用,在触发其它全局和组件内 Hook 之前(前一个视图组件的 beforeRouteLeave 除外)。它应该在初始化期间在 index.js 文件中定义为路由器实例的全局方法,并采用以下语法:
const router = new VueRouter({
//...
})
router.beforeEach(beforeEachCallback)
在前面的代码片段中,beforeEachCallback 是一个接收三个参数的钩子函数:
const beforeEachCallback = (
to, // The destination route
from, //The source route
next //The function to trigger to resolve the hook
) => { … })
或者我们可以直接这样写:
router.beforeEach((to, from, next) => { … })
例如,如果我们想要在用户导航到 About 而没有用户参数值时显示通用消息(有参数时,会根据参数显示不同的页面),我们可以如下挂钩 beforeEach :
router.beforeEach((
to, // The destination route
from, //The source route
next //The function to trigger to resolve the hook
) => {
if (to.name === 'about' && (!to.params || !to.params.user)) {
next({ name: 'error' })
} else {
next();
}
})
在这里,我们检查目标路由是否是 about,如果它没有传递任何附加参数,也没有传递任何用户参数值,我们将导航到错误(error)路由。否则,只需正常执行 next()
即可。
|
我们仍然需要使用 Error.vue 视图组件创建一个错误(error)页面,显示一条简单的消息:
<template>
<div>
<h2>No param passed.</h2>
</div>
</template>
另外,请确保相应地注册路径:
{
path: '/error',
name: 'error',
component: () => import(/* webpackChunkName: "error" */'../views/Error.vue'),
}
现在,在主页(Home)视图中,单击 About 链接后,应用程序将渲染 Error 页面,而不是 About 页面,如以下屏幕截图所示:

现在,让我们转到 App.vue 文件并指定 to 属性来绑定到 { name: 'about', params: { user: 'Adam' }}
对象:
<router-link :to="{ name: 'about', params: { user: 'Adam'}}">About</router-link>
让我们导航回到应用程序的主页(Home)并单击 About 链接。由于我们传递了正确的参数,因此输出将如下所示:

此外,从现在开始,每次刷新 About 页面时,我们都会被重定向到 Error 页面,因为刷新时没有传递用户(user)参数。
现在我们将看看 beforeEach 和 beforeResolve Hook 之间的几个关键区别点。
区分 beforeEach 和 beforeResolve 钩子
我们还可以使用相同的语法向 beforeResolve 注册全局 Hook。 然而,与在导航创建阶段触发的 beforeEach 不同,beforeResolve 将在所有 Hooks(全局的和组件内的)解析之后,在导航执行并确认之前触发:
router.beforeResolve((
to, // The destination route
from, //The source route
next //The function to trigger to resolve the hook
) => {
if (to.name === 'about' && (!to.params || !to.params.user))
{
next({ name: 'error' })
} else {
next();
}
})
输出结果将保持与图 6.25 相同:

现在让我们详细看看 afterEach Hook。
afterEach 钩子
afterEach() Hook 是确认导航后(即 beforeResolve() 之后)触发的最后一个全局导航守卫。 与其它全局防护不同,传递给 afterEach() 的 Hook 函数不会接收 next 函数,因此它不会影响导航。
此外,to 和 from 参数是只读 Route 对象。因此,afterEach 的最佳用例是保存数据,例如后退按钮的上次访问的 Route 对象、传递的路由目的地参数或页面视图跟踪。例如,我们可以有一个默认值 user,分配它,并在需要时保存它:
let user = 'Adam';
router.beforeEach((to, from, next) => {
if (to.name === 'about' && (!to.params || !to.params.user)) {
next({ name: 'about', params: { user }})
} else {
user = to.params.user;
next()
}
});
router.afterEach((to, from) => {
if (to.name === 'about' && to.params && to.params.user) {
user = to.params.user;
}
})
现在,在 App.js 文件中,而不是 Adam,添加以下内容:
<router-link
:to="{ name: 'about', params: { user: 'Adam' }}"
>
About
</router-link>
让我们将其更改为 Alex:
<router-link
:to="{ name: 'about', params: { user: 'Alex' }}"
>
About
</router-link>
现在单击 About 链接时的输出如下:

但在重新加载时,About 页面会使用默认用户 Adam 渲染,因为有一个用户传递给了参数,如下所示:

在本节中,我们研究了 afterEach Hook。我们使用 afterEach Hook 将数据传递到 about 页面,而不必将该数据包含在 URL 中。同样的技术可用于更新其它行为,例如按下后退按钮时所需的目标页面。
个性化每个路由的钩子
我们可以直接在目标路由的配置对象中定义一个 beforeEnter 防护,而不是定义一个全局 Hook(这可能会导致看不见的错误并需要进行路由检查),例如我们的 About 路由:
beforeEnter: (to, from, next) => {
if (!to.params || !to.params.user) {
to.params.user = 'Adam'
}
next()
}
通过这种方法,无论是重新加载还是单击链接导航到 About 页面,输出现在都是一致的,如以下屏幕截图所示:

使用 beforeEnter(),to 是可写的,您将可以访问它(它指向特定的路由 - About)。 仅当用户触发导航到 About 页面时才会触发它。 |
在本节中,我们研究了 Vue 中可用的不同路由器 Hook,包括 beforeEach、beforeResolve 和 afterEach。 我们看到了如何在路由过程的不同点调用每个 Hook。 作为一个实际示例,我们研究了一条路由,如果未提供参数,该路由会将用户引导至错误页面。这些 Hook 非常有用,尤其是在设置经过身份验证的路由时。在下一节中,我们将了解如何设置组件内 Hook。