当前位置:  首页>> 技术小册>> TypeScript和Vue从入门到精通(五)

15.6 路由导航守卫

在Vue.js应用中,尤其是在使用Vue Router进行单页面应用(SPA)开发时,路由导航守卫(Navigation Guards)是一项至关重要的功能。它们允许我们在路由发生变化的过程中执行代码,比如验证用户权限、设置页面标题、加载数据等。TypeScript与Vue的结合,为这些守卫的编写提供了更强的类型支持和更清晰的代码结构。本章节将深入介绍Vue Router中的路由导航守卫,并展示如何在TypeScript环境中使用它们。

15.6.1 理解路由导航守卫

Vue Router提供了多种导航守卫,这些守卫可以在路由的不同阶段被调用,从而允许我们控制路由的跳转过程。常见的路由导航守卫包括全局守卫、路由独享的守卫以及组件内的守卫。

  • 全局守卫:作用于整个应用,如beforeEachafterEach,无论路由如何变化,这些守卫都会被调用。
  • 路由独享的守卫:仅对某个特定的路由有效,如beforeEnter
  • 组件内的守卫:在组件内部定义,包括beforeRouteEnterbeforeRouteUpdate(Vue 2.2+)、beforeRouteLeave

15.6.2 全局守卫

全局守卫通常在路由配置文件中定义,用于对整个应用的路由跳转进行全局性的控制。

1. beforeEach

beforeEach是最常用的全局守卫之一,它在路由即将变化之前被调用。你可以在这里进行用户登录验证、重定向到登录页面、设置页面标题等操作。

  1. import Vue from 'vue';
  2. import Router from 'vue-router';
  3. import Home from './views/Home.vue';
  4. import Login from './views/Login.vue';
  5. Vue.use(Router);
  6. const router = new Router({
  7. routes: [
  8. {
  9. path: '/',
  10. name: 'home',
  11. component: Home
  12. },
  13. {
  14. path: '/login',
  15. name: 'login',
  16. component: Login
  17. }
  18. // 更多路由...
  19. ]
  20. });
  21. router.beforeEach((to: Route, from: Route, next: Function) => {
  22. // 假设我们有一个方法来检查用户是否登录
  23. if (to.matched.some(record => record.meta.requiresAuth)) {
  24. // 这里只是模拟,实际情况应检查用户是否登录
  25. if (!isAuthenticated()) {
  26. next({
  27. path: '/login',
  28. query: { redirect: to.fullPath } // 将尝试访问的路由地址作为参数,登录后重定向回去
  29. });
  30. } else {
  31. next(); // 确保一定要调用 next()
  32. }
  33. } else {
  34. next(); // 确保一定要调用 next()
  35. }
  36. });
  37. function isAuthenticated(): boolean {
  38. // 这里应实现具体的登录验证逻辑
  39. return false; // 假设用户未登录
  40. }
  41. export default router;

在上面的例子中,我们通过检查路由的meta字段来判断是否需要验证用户身份。如果需要,则调用isAuthenticated函数来验证,并根据验证结果决定是跳转到登录页面还是继续当前路由的跳转。

2. afterEach

beforeEach相对,afterEach守卫在路由跳转完成后被调用,不接受next函数,因此不能改变导航本身。它主要用于一些收尾工作,如分析页面停留时间、设置页面标题等。

  1. router.afterEach((to: Route, from: Route) => {
  2. // 设置页面标题
  3. document.title = to.meta.title || '默认标题';
  4. });

15.6.3 路由独享的守卫

路由独享的守卫只针对某个具体的路由生效,主要通过beforeEnter来定义。这在某些特定的路由上执行逻辑时非常有用,而无需全局性地影响其他路由。

  1. const router = new Router({
  2. routes: [
  3. {
  4. path: '/profile',
  5. component: Profile,
  6. beforeEnter: (to: Route, from: Route, next: Function) => {
  7. // 在这里可以执行针对/profile路由的特定逻辑
  8. // 比如检查用户是否已登录
  9. if (!isAuthenticated()) {
  10. next({
  11. path: '/login',
  12. query: { redirect: to.fullPath }
  13. });
  14. } else {
  15. next();
  16. }
  17. }
  18. }
  19. // 其他路由...
  20. ]
  21. });

15.6.4 组件内的守卫

组件内的守卫允许我们在组件内部对路由的进入、更新和离开进行控制。

1. beforeRouteEnter

在渲染该组件的对应路由被 confirm 前调用,不!能!获取组件实例 this。因为当守卫执行前,组件实例还没被创建。

  1. export default Vue.extend({
  2. beforeRouteEnter(to: Route, from: Route, next: Function) {
  3. // 在渲染该组件的对应路由被 confirm 前调用
  4. // 不!能!获取组件实例 `this`
  5. // 当守卫执行前,组件实例还没被创建
  6. next(vm => {
  7. // 通过 `vm` 访问组件实例
  8. });
  9. }
  10. // 其他选项...
  11. });
2. beforeRouteUpdate (Vue 2.2+)

在当前路由改变,但是该组件被复用时调用。例如,对于一个带有动态参数的路径 /foo/:id,在 /foo/1/foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。

  1. export default Vue.extend({
  2. beforeRouteUpdate(to: Route, from: Route, next: Function) {
  3. // 路由更新前调用
  4. // 例如,当一个带有动态参数的路由在变化时,该组件被复用,而你想在每次变化时都执行一些操作
  5. next();
  6. }
  7. // 其他选项...
  8. });
3. beforeRouteLeave

导航离开该组件的对应路由时调用,可以访问组件实例 this。这个守卫通常用于提示用户保存更改,或者阻止用户在表单尚未保存的情况下离开页面。

  1. export default Vue.extend({
  2. data() {
  3. return {
  4. isFormChanged: false
  5. };
  6. },
  7. beforeRouteLeave(to: Route, from: Route, next: Function) {
  8. if (this.isFormChanged) {
  9. const answer = window.confirm('您有未保存的更改,确定离开吗?');
  10. if (answer) {
  11. next();
  12. } else {
  13. next(false); // 取消路由跳转
  14. }
  15. } else {
  16. next();
  17. }
  18. }
  19. // 其他选项...
  20. });

15.6.5 总结

路由导航守卫是Vue Router中一个非常强大的功能,它允许我们在路由跳转的不同阶段执行代码,从而控制用户的访问流程、设置页面标题、加载数据等。在TypeScript环境中,利用TypeScript的强类型特性,我们可以编写出更加健壮、易于维护的路由守卫代码。通过合理使用全局守卫、路由独享守卫和组件内守卫,我们可以灵活地控制整个应用的路由逻辑,提升用户体验。


该分类下的相关小册推荐: