Vue Router 提供了导航守卫(Navigation Guards)来控制路由的导航行为。这些守卫可以在路由跳转的不同阶段执行一些逻辑,例如权限验证、页面加载前的数据预取等。Vue Router 的导航守卫主要有三种类型:全局守卫、路由独享守卫和组件内守卫。
导航守卫的类型
1. 全局守卫
全局守卫应用于整个应用的所有路由。主要有以下几种:
beforeEach:在每次路由跳转前调用。beforeResolve:在所有beforeEach和beforeRouteEnter守卫都解析后调用。afterEach:在每次路由跳转完成后调用。
1import Vue from 'vue';
2import Router from 'vue-router';
3
4Vue.use(Router);
5
6const router = new Router({
7 routes: [
8 // 路由配置
9 ]
10});
11
12router.beforeEach((to, from, next) => {
13 // to: 即将要进入的目标路由对象
14 // from: 当前导航正要离开的路由对象
15 // next: 必须调用 next() 来 resolve 这个钩子
16 console.log('Global beforeEach guard');
17 next();
18});
19
20router.beforeResolve((to, from, next) => {
21 console.log('Global beforeResolve guard');
22 next();
23});
24
25router.afterEach((to, from) => {
26 console.log('Global afterEach hook');
27});
2. 路由独享守卫
路由独享守卫只应用于特定的路由配置中。主要有以下几种:
beforeEnter:在进入该路由之前调用。
1const routes = [
2 {
3 path: '/user/:id',
4 component: User,
5 beforeEnter: (to, from, next) => {
6 console.log('Route-specific beforeEnter guard');
7 next();
8 }
9 }
10];
3. 组件内守卫
组件内守卫是在组件内部定义的守卫。主要有以下几种:
beforeRouteEnter:在进入组件之前调用。beforeRouteUpdate:在当前路由改变,但是该组件被复用时调用。beforeRouteLeave:在离开组件时调用。
1export default {
2 name: 'User',
3 data() {
4 return {
5 user: null
6 };
7 },
8 beforeRouteEnter(to, from, next) {
9 // 在渲染该组件的对应路由被 confirm 前调用
10 // 不能访问 this
11 console.log('Component beforeRouteEnter guard');
12 next(vm => {
13 // 通过 vm 访问组件实例
14 vm.loadUser(to.params.id);
15 });
16 },
17 beforeRouteUpdate(to, from, next) {
18 // 在当前路由改变,但是该组件被复用时调用
19 // 可以访问 this
20 console.log('Component beforeRouteUpdate guard');
21 this.loadUser(to.params.id);
22 next();
23 },
24 beforeRouteLeave(to, from, next) {
25 // 导航离开该组件的对应路由时调用
26 // 可以访问 this
27 console.log('Component beforeRouteLeave guard');
28 const answer = window.confirm('Do you really want to leave?');
29 if (answer) {
30 next();
31 } else {
32 next(false);
33 }
34 },
35 methods: {
36 loadUser(id) {
37 // 模拟异步请求
38 setTimeout(() => {
39 this.user = { id, name: `User ${id}` };
40 }, 1000);
41 }
42 }
43};
导航守卫的机制
导航守卫的工作机制如下:
- 触发导航:用户点击链接或编程式导航(如
router.push)触发导航。 - 调用全局前置守卫:依次调用
beforeEach守卫。 - 调用路由独享守卫:如果目标路由有
beforeEnter守卫,则调用它。 - 调用组件内的
beforeRouteEnter守卫:对于即将进入的组件,调用其beforeRouteEnter守卫。 - 解析异步路由组件:如果有异步路由组件,等待其解析完成。
- 调用全局解析守卫:调用
beforeResolve守卫。 - 导航确认:如果所有守卫都返回
next()或没有守卫阻止导航,则导航确认。 - 调用全局后置钩子:调用
afterEach钩子。 - DOM 更新:更新视图,显示新的路由内容。
- 调用组件内的
beforeRouteUpdate守卫:如果当前路由改变但组件被复用,则调用beforeRouteUpdate守卫。
如何使用导航守卫
下面是一个完整的示例,展示了如何在 Vue Router 中使用导航守卫进行权限验证和数据预取。
1. 安装 Vue Router
1npm install vue-router
2. 配置路由
1// router/index.js
2import Vue from 'vue';
3import Router from 'vue-router';
4import Home from '@/components/Home.vue';
5import User from '@/components/User.vue';
6
7Vue.use(Router);
8
9const routes = [
10 {
11 path: '/',
12 name: 'Home',
13 component: Home
14 },
15 {
16 path: '/user/:id',
17 name: 'User',
18 component: User,
19 beforeEnter: (to, from, next) => {
20 console.log('Route-specific beforeEnter guard');
21 next();
22 }
23 }
24];
25
26const router = new Router({
27 mode: 'history',
28 base: process.env.BASE_URL,
29 routes
30});
31
32router.beforeEach((to, from, next) => {
33 console.log('Global beforeEach guard');
34 if (to.matched.some(record => record.meta.requiresAuth)) {
35 if (!isAuthenticated()) {
36 next({
37 path: '/login',
38 query: { redirect: to.fullPath }
39 });
40 } else {
41 next();
42 }
43 } else {
44 next();
45 }
46});
47
48router.beforeResolve((to, from, next) => {
49 console.log('Global beforeResolve guard');
50 next();
51});
52
53router.afterEach((to, from) => {
54 console.log('Global afterEach hook');
55});
56
57function isAuthenticated() {
58 // 模拟身份验证
59 return true;
60}
61
62export default router;
3. 创建组件
1<!-- components/Home.vue -->
2<template>
3 <div>
4 <h1>Home</h1>
5 <router-link to="/user/1">User 1</router-link>
6 </div>
7</template>
8
9<script>
10export default {
11 name: 'Home'
12};
13</script>
1<!-- components/User.vue -->
2<template>
3 <div>
4 <h1>User {{ user.name }}</h1>
5 </div>
6</template>
7
8<script>
9export default {
10 name: 'User',
11 data() {
12 return {
13 user: null
14 };
15 },
16 beforeRouteEnter(to, from, next) {
17 console.log('Component beforeRouteEnter guard');
18 next(vm => {
19 vm.loadUser(to.params.id);
20 });
21 },
22 beforeRouteUpdate(to, from, next) {
23 console.log('Component beforeRouteUpdate guard');
24 this.loadUser(to.params.id);
25 next();
26 },
27 beforeRouteLeave(to, from, next) {
28 console.log('Component beforeRouteLeave guard');
29 const answer = window.confirm('Do you really want to leave?');
30 if (answer) {
31 next();
32 } else {
33 next(false);
34 }
35 },
36 methods: {
37 loadUser(id) {
38 // 模拟异步请求
39 setTimeout(() => {
40 this.user = { id, name: `User ${id}` };
41 }, 1000);
42 }
43 }
44};
45</script>
通过以上步骤,你可以在 Vue Router 中设置各种导航守卫,实现权限验证、数据预取等功能。