vue router的导航守卫是什么,它的机制和如何使用

314 阅读2分钟

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};

导航守卫的机制

导航守卫的工作机制如下:

  1. 触发导航:用户点击链接或编程式导航(如 router.push)触发导航。
  2. 调用全局前置守卫:依次调用 beforeEach 守卫。
  3. 调用路由独享守卫:如果目标路由有 beforeEnter 守卫,则调用它。
  4. 调用组件内的 beforeRouteEnter 守卫:对于即将进入的组件,调用其 beforeRouteEnter 守卫。
  5. 解析异步路由组件:如果有异步路由组件,等待其解析完成。
  6. 调用全局解析守卫:调用 beforeResolve 守卫。
  7. 导航确认:如果所有守卫都返回 next() 或没有守卫阻止导航,则导航确认。
  8. 调用全局后置钩子:调用 afterEach 钩子。
  9. DOM 更新:更新视图,显示新的路由内容。
  10. 调用组件内的 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 中设置各种导航守卫,实现权限验证、数据预取等功能。