Vue路由守卫详解

什么是路由守卫

路由守卫是Vue Router提供的一种机制,用于在导航过程中对路由进行控制和管理。通过使用路由守卫,你可以在路由切换前、切换后以及错误处理时执行相应的逻辑。

Vue Router提供了三种类型的路由守卫:
1、全局前置守卫
2、路由独享的守卫
3、组件内的守卫

全局前置守卫

全局前置守卫( router.beforeEach):这些守卫会在路由切换之前被调用,可以用来进行权限验证、登录状态检查等操作。常见的全局前置守卫有beforeEach。

语法

router.beforeEach((to, from, next) => {
  // 在每次路由导航触发前执行的逻辑  
});

在router/index.js中的具体配置

// index.js

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const router = new VueRouter({
  // 路由配置
  routes: [
    // ...定义路由...
  ]
});

router.beforeEach((to, from, next) => {
  // 全局前置守卫逻辑
});

export default router;

在上述示例中,我们通过 router.beforeEach 方法注册了一个全局前置守卫。在每次路由导航之前,该守卫会被调用。守卫的回调函数接收三个参数:

  • to:即将跳转的目标路由对象
  • from:当前导航正要离开的路由对象
  • next:用于控制导航行为的回调函数

在守卫的回调函数中,你可以根据业务需求执行相应的操作,如验证用户权限、检查登录状态、取消导航或重定向到其他路由。next 函数用于控制导航的继续或中断。

  • 若要中断当前导航并取消跳转,可以调用 next(false)
  • 若要重定向到其他路由,并且希望中断当前导航,可以调用 next('/other-route')
  • 若无需中断导航,则调用 next() 允许导航继续。

全局前置守卫(Global before Guards)可以在以下场景中发挥作用:

  1. 登录验证:你可以使用全局前置守卫来验证用户是否已登录。通过检查用户的登录状态或者验证用户的身份信息,可以防止未经授权的用户访问需要登录权限的页面。

  2. 权限控制:全局前置守卫可以用于实现基于角色或权限的访问控制。通过在守卫中检查用户的角色或权限,可以限制用户只能访问其具备权限的页面,并在没有权限时进行相应的处理,如跳转到错误页面或提示无权限信息。

  3. 路由拦截:在进行路由导航之前,你可以使用全局前置守卫来拦截、修改或重定向导航。根据特定的条件或业务需求,你可以在守卫中对导航进行处理,如取消导航、修改目标路由或跳转到其他页面。

  4. 数据预处理:有时,在进入某个路由之前,你可能需要对相关数据进行加载、初始化或验证等操作。全局前置守卫可以帮助你在导航发生前执行这些预处理任务,确保数据的准备工作完成后再进入目标路由。

路由独享的守卫

路由独享的守卫(beforeEnter):这些守卫可以直接在路由配置中定义,只对特定的路由生效。可以在进入该路由前、离开该路由前或两者之间执行相应逻辑。常见的路由独享守卫有beforeEnter。

语法

const router = new VueRouter({
  routes: [
    {
      path: '/example',//具体跳转路径
      component: ExampleComponent,//具体跳转页面
      beforeEnter: (to, from, next) => {
        // 在单个路由的独享守卫逻辑
      }
    },
    // ...
  ]
});

在router/index.js中的具体配置

// index.js

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const routes = [
  {
    path: '/example',
    component: ExampleComponent,
    beforeEnter: (to, from, next) => {
      // 在单个路由的独享守卫逻辑
    }
  },
  // ...其他路由配置...
];

const router = new VueRouter({
  routes
});

export default router;

路由独享的守卫在以下场景中非常有用:

  1. 鉴权和权限控制:你可以使用路由独享的守卫来验证用户的身份和权限。例如,对于需要登录才能访问的特定路由,可以在其独享守卫中检查用户是否已经登录,如果未登录则阻止导航到该路由。

  2. 数据加载和处理:有时候,在进入某个路由之前需要先加载一些数据或执行一些异步操作。在路由独享的守卫中,你可以调用 API 请求数据,确保数据加载完毕后再继续导航到目标路由。

  3. 导航控制:某些情况下,你可能希望根据一定条件来控制导航行为,如取消导航、重定向到其他路由等。通过在路由独享的守卫中进行条件判断,并调用适当的导航方法,可以实现对导航行为的精确控制。

  4. 日志记录或埋点:如果你需要在特定的路由上进行日志记录或进行统计分析,可以使用路由独享的守卫来触发相应的操作。例如,在进入某个路由时记录访问日志或发送统计数据。

组件内的守卫

组件内的守卫:这些守卫是直接写在组件内部的方法,用于对组件内部的路由变化做出反应。常见的组件内守卫有beforeRouteEnter、beforeRouteUpdate和beforeRouteLeave。

组件内的守卫允许你在组件内部针对组件生命周期的不同阶段执行相应的逻辑。

以下是Vue.js提供的组件内的守卫:

  1. beforeRouteEnter:在进入路由前被调用,但在组件实例被创建之前被调用,因此无法访问组件实例。可以通过传入一个回调来获取组件实例或使用Promise来延迟进入。
  2. beforeRouteLeave:在离开当前路由时被调用。可以用于确认是否离开页面、保存临时数据等操作。
  3. beforeRouteUpdate:在当前路由被复用时被调用,即参数发生变化但是组件实例仍然被复用。可以在该守卫中对参数的变化作出响应。

这些守卫可以直接定义在组件的选项中
语法

export default {
  // ...

  beforeRouteEnter(to, from, next) {
    // 在组件实例创建之前调用
    // 可以使用回调函数或返回一个Promise延迟进入
  },

  beforeRouteLeave(to, from, next) {
    // 在离开当前路由时调用
    // 可以进行确认、保存数据等操作
  },

  beforeRouteUpdate(to, from, next) {
    // 在当前路由被复用时调用
    // 可以对参数的变化作出响应
  }

  // ...
}

组件内的守卫在以下场景中非常有用:

  1. 验证用户身份:在进入某个路由前,可以通过 beforeRouteEnter 守卫验证用户的登录状态或权限。如果用户未登录或没有足够的权限访问该路由,可以取消导航或重定向到其他页面。

  2. 加载异步数据:在进入某个路由前,可以使用 beforeRouteEnter 守卫获取异步数据,并在数据加载完成后再渲染组件。这样可以确保组件在数据加载完成后才会显示,避免因数据未加载完成而出现显示问题。

  3. 取消导航:在离开当前路由前,可以使用 beforeRouteLeave 守卫进行一些判断和操作,例如检查表单是否被修改过,询问用户是否需要保存未提交的数据。根据用户的选择,可以取消导航或继续进行下一个路由。

  4. 条件渲染和动态路由:在 beforeRouteUpdate 守卫中,可以根据当前路由参数的变化,更新组件的数据或重新请求数据。这样可以实现根据不同的路由参数动态展示内容或刷新组件的状态。

举例说明

在 Vue 开发中,你可以通过路由导航守卫来实现在未登录状态下先展示登录页面而不展示首页。

路由导航守卫提供了一些钩子函数,可以在路由导航过程中进行拦截和控制。其中,beforeEach 导航守卫可以在每次路由切换前被触发。

使用路由导航守卫来实现在未登录状态下先展示登录页面:

// main.js

import Vue from 'vue';
import App from './App.vue';
import router from './router';

// 全局的路由导航守卫
router.beforeEach((to, from, next) => {
  const isLoggedIn = checkUserLoggedIn(); // 根据实际情况判断用户是否已登录
  if (to.path !== '/login' && !isLoggedIn) {
    // 如果用户未登录且访问的不是登录页,则重定向到登录页
    next('/login');
  } else {
    // 已登录或者访问的是登录页,则正常跳转
    next();
  }
});

new Vue({
  router,
  render: (h) => h(App)
}).$mount('#app');

上述代码中,我们在 beforeEach 导航守卫中进行判断,如果用户未登录且访问的不是登录页(即非 /login 路径),则使用 next('/login') 将用户重定向到登录页;否则,如果用户已登录或者访问的是登录页,则继续正常跳转。

这样,在每次路由切换之前都会进行登录状态的检查,并根据检查结果来决定是否重定向到登录页。这样就可以先展示登录页而不先展示首页。

当用户访问其他需要登录才能查看的页面时,会被拦截并跳转到登录页面。用户在登录成功之后,再跳转到原本要访问的页面。

请注意,checkUserLoggedIn() 是一个自定义函数,用于实际判断用户是否已登录,请根据你的实际需求和认证逻辑来编写该函数。