Vue路由守卫详解

Vue 路由守卫是 Vue Router 提供的一种功能,用于在路由导航的不同阶段插入控制逻辑,从而实现对路由跳转的精细化管理。以下是 Vue 路由守卫的详细解析:

路由守卫的分类

Vue 路由守卫主要分为三类:全局守卫、路由独享守卫和组件内守卫

1. 全局守卫

全局守卫对整个应用中的所有路由跳转生效,主要包括以下几种:

  • 全局前置守卫 (beforeEach):在路由跳转之前被调用,可以用于身份验证、权限检查等。例如,检查用户是否登录,如果未登录则重定向到登录页面。
router.beforeEach((to, from, next) => {
  const isAuthenticated = localStorage.getItem('token');
  if (to.meta.requiresAuth && !isAuthenticated) {
    next('/login');
  } else {
    next();
  }
});
  • 每个守卫接收两个(或三个)参数:
    to:即将要进入的目标
    from:当前导航正要离开的路由
    next:(可选)一个继续执行的函数

  • 可以返回的值如下:
    false:取消当前的导航
    一个路由地址:通过一个路由地址重定向到一个不同的地址,如同调用router.push(),并且可以传入类似“replace:true” 或 “name:home” 之类的选项

 
  router.beforeEach(async (to,from) => {
  // 检查用户是否已登录
    if ( !isAuthenticated  && to.name !== 'Login') {
      return {name : 'Login',replace : true}
    }
  });
  • 全局解析守卫 (beforeResolve):在路由确认后、组件渲染前被调用,通常用于数据预加载。

    
    router.beforeEach(async (to,from) => {
    // 检查用户是否一登陆
      if ( to.meta.requiresAdmin) {
        try {
          await validateAdminPrivileges();
        } catch (error) {
          return '/no-permission';
        }
      }
    });
    

    router.beforeResolve 是获取数据或执行其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置

  • 全局后置钩子 (afterEach):在路由跳转完成后被调用,通常用于页面访问统计等。和守卫不同的事,这个钩子不会接受 next函数也不会改变导航本身

    router.afterEach((to) => {
      analytics.trackPageView(to.fullPath);
    });
    
2. 路由独享守卫

路由独享守卫只对某个特定的路由生效,通过在路由配置中定义 beforeEnter 属性来实现。它适用于对特定路由进行特殊的权限验证或逻辑处理
值得注意的是beforeEnter 旨在进入路由时触发,不会在 paramsquery hash 改变时触发。
例如:从 /users/2 进入 /users/3 或者从 /users/2#info 进入到 /users/2#projects。 他们只有在 从一个不同的 路由导航时,才会触发

const routes = [
  {
    path: '/premium-content',
    component: PremiumContent,
    beforeEnter: (to, from, next) => {
      if (!userStore.isSubscribed) {
        next('/upgrade');
      } else {
        next();
      }
    }
  }
];
3. 组件内守卫

组件内守卫定义在组件内部,只对该组件的路由跳转生效,主要包括以下几种:

  • beforeRouteEnter:在进入该组件的路由前执行,适合进行数据预加载或权限验证。
    export default {
      beforeRouteEnter(to, from, next) {
        fetchInitialData(to.params.id).then(data => {
          next(vm => vm.setData(data));
        });
      }
    };
    
  • beforeRouteUpdate:在当前路由改变且该组件被复用时调用,适用于路由参数变化时的逻辑处理。
    export default {
      beforeRouteUpdate(to, from) {
        this.productId = to.params.id;
        this.loadProductData();
      }
    };
    
  • beforeRouteLeave:在离开该组件的路由前执行,常用于提示用户保存未保存的数据。
    export default {
      beforeRouteLeave(to, from, next) {
        if (this.unsavedChanges) {
          const confirm = window.confirm('有未保存的修改,确定离开吗?');
          next(confirm);
        } else {
          next();
        }
      }
    };
    

完整的导航解析流程

  1. 导航被触发
  2. 在失活的组件里调用 (beforeRouteLeave)守卫。
  3. 调用全局的 (beforeEach) 守卫。
  4. 在重用的组件里调用(beforeRouteUpdate) 守卫。
  5. 在路由配置里调用 (beforeEnter)。
  6. 解析异步路由组件
  7. 在被激活的组件里调用 (beforeRouteEnter)。
  8. 调用全局的 (beforeResolve)。
  9. 完成导航。
  10. 调用全局后置钩子 (afterEach)。
  11. 触发dom 更新
  12. 调用 (beforeRouteEnter)守卫传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入

最佳实践建议

  • 权限校验链:建议使用全局守卫进行基础校验,路由独享守卫进行特定校验,组件守卫进行最终校验。
  • 异步处理:在守卫中使用 async/await 处理异步操作时,要确保正确调用 next()
  • 性能优化:避免在全局守卫中执行耗时操作,必要时可结合路由懒加载。
  • 调试技巧:使用 router.onError() 捕获导航过程中的异常。

你可能感兴趣的:(vue.js,前端,javascript)