• Vue导航守卫的定义和用法
  • 发布于 2个月前
  • 345 热度
    0 评论
  • 奥特蛋
  • 1 粉丝 48 篇博客
  •   
一、什么是导航守卫

当涉及到Vue路由时,导航守卫是一项非常有用的功能。导航守卫允许你在路由导航过程中执行一些操作,例如验证用户权限、重定向或取消导航等,导航守卫主要分为三种:全局导航守卫、独享导航守卫、组件内导航守卫。


二、全局导航守卫
全局导航守卫有三种:beforeEach(全局前置守卫)、beforeResolve(全局解析守卫)、afterEach(全局后置守卫)。
1.全局前置守卫
我们可以使用router.beforeEach注册一个全局前置守卫,beforeEach在路由切换之前调用,可以用来进行权限验证、登录状态检查等操作。
用户如果没有登录,只能访问登录界面,不能访问其他页面。用户如果登录了,就可以访问其他页面,不能访问登录页面。
router.beforeEach((to, from, next) => {
  let token = userStore.token;
  // 如果用户已登录
  if(token) {
    // 访问登录页则跳回首页
    if(to.path == "/login"){
      next({path: "/"});
    } else {
      // 如果访问其他页面则放行
      next();
    }
  } else { // 如果用户未登录
    if(to.path == "/login"){
      next();
    } else {
      // 如果访问其他页面则返回登录界面
      next({path: "/login"});
    }
  }
})
三个参数的含义:
to: 表示即将要进入的目标路由。它是一个包含路由信息的对象,包括path、params、query等参数信息。我们可以通过to.path获取目标路由的路径,通过to.params获取目标路由的参数,通过to.query获取目标路由的查询参数等。
from: 表示当前导航正要离开的路由。它也是一个包含路由信息的对象,我们可以通过from.path获取当前路由的路径,通过from.params获取当前路由的参数,通过from.query获取当前路由的查询参数等。
next: 可选的第三个参数,是一个函数(放行函数),用于控制导航的行为。

这里列举一些next的具体用法:
next():调用next()表示继续导航,即允许用户访问目标路由。
next(false):调用next(false)表示终止导航,即不允许用户访问目标路由。这通常用于进行权限验证或者登录状态检查,如果条件不满足,则终止导航。
next('/path'):调用next('/path')表示重定向导航到指定的路径。这可以用于在导航守卫中进行重定向,例如在未登录时将用户重定向到登录页面。
next({ path: '/path' }):调用next({ path: '/path' })表示重定向导航到指定的路径。与上一个用法相似,但使用了一个包含路径的对象作为参数。
next(error):调用next(error)表示终止导航并传递一个错误对象。这可以用于在导航守卫中处理错误情况,例如在网络请求失败时中止导航并显示错误信息。
next(callback):调用next(callback)表示异步导航,其中callback是一个回调函数。这可以用于在导航守卫中执行异步操作,例如在获取数据后再继续导航。

请注意,next方法只能在导航守卫函数中调用,并且每个导航守卫函数只能调用一次next方法,只能调用一次。
2.全局解析守卫
我们可以用router.beforeResolve注册一个全局守卫。beforeResolve在路由切换之前调用,但在beforeEach守卫之后调用。在该守卫中,可以在导航被确认之前执行异步操作或者获取组件数据,可以在所有组件内守卫和异步路由组件被解析之后调用。
router.beforeResolve((to, from, next) => {
  // 在这里执行一些操作,例如加载数据
  fetchData().then(() => {
    next();
  });
});
Vue-router的官网写道:router.beforeResolve是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
3.全局后置守卫
我们可以使用router.afterEach方法注册一个全局后置钩子,afterEach在路由切换之后调用,可以用来进行页面统计、错误处理等操作,通常用于页面渲染完成后的操作。该守卫没有next参数,因此不能中止导航。
router.afterEach((to, from) => {
  // 堆代码 duidaima.com
  // 在这里执行一些操作,例如记录页面浏览历史
  trackPageView(to.path);
});
比如说我们就可以利用前置守卫和后置守卫制作一个进度条,当然我们还需要引入第三方库及其样式,这样项目上方会出现进度条。
import nprogress from "nprogress";
import "nprogress/nprogress.css";
import router from "./router";

router.beforeEach((to, from, next) => {
  nprogress.start();
  next();
})
router.afterEach((to, from) => {
  nprogress.done();
})
三、独享导航守卫
除了全局导航守卫外,我们还可以在路由配置中为特定的路由定义独享的守卫。路由独享守卫仅对特定的路由生效,可以用于处理特定路由的逻辑。beforeEnter守卫只在进入路由时触发,不会在params、query或hash改变时触发。
例如,从/users/2进入到/users/3或者从/users/2#info进入到/users/2#projects时,守卫不会触发,只有在从一个不同的路由导航时,才会被触发。
const routes = [
  {
    path: '/home',
    component: Home,
    beforeEnter: (to, from, next) => {
      // 在进入路由之前执行一些操作
      if (isLoggedIn()) {
        // 用户已登录,允许访问路由
        next();
      } else {
        // 用户未登录,重定向到登录页面
        next('/login');
      }
    }
  },
  // 其他路由配置...
]
通过使用独享导航守卫,我们可以在路由级别上对访问权限进行一定的控制。
四、组件内导航守卫
除了全局导航守卫和路由独享守卫外,我们还可以在路由组件内直接定义路由导航守卫。这些守卫将在组件的生命周期钩子中被调用,用于在组件内部控制路由导航行为。
beforeRouteEnter:用于在路由进入组件之前执行操作,无法通过this访问组件实例,因为当守卫执行时,组件实例还没被创建。
beforeRouteUpdate:用于在组件复用时,路由参数发生变化时执行操作,可以通过this访问组件实例,因为组件已经挂载好了。
beforeRouteLeave:用于在路由离开组件之前执行操作,可以通过this访问组件实例。
const UserDetails = {
  template: `...`,
  beforeRouteEnter(to, from) {
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` ! 
    // 因为当守卫执行时,组件实例还没被创建!
  },
  beforeRouteUpdate(to, from) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
    // 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from) {
    // 在导航离开渲染该组件的对应路由时调用
    // 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },
}
在beforeRouteEnter守卫中,可以通过传递一个回调函数给next方法来访问组件实例。这个回调函数会在路由确认之后被调用,此时组件实例已经被创建。回调函数的参数就是组件实例,因此可以通过这个参数访问组件实例的方法和属性。
export default {
  beforeRouteEnter(to, from, next) {
    next(vm => {
      // 在进入组件之后执行一些操作
      // 可以访问组件实例的this上下文
      vm.doSomething();
    });
  },
  beforeRouteUpdate(to, from, next) {
    // 在这里执行一些操作,例如重新加载数据
    fetchData().then(() => {
      next();
    });
  },
  beforeRouteLeave(to, from, next) {
    // 堆代码 duidaima.com
    // 在这里执行一些操作,例如提示用户保存未保存的数据
    if (hasUnsavedChanges) {
      if (confirm('你有未保存的数据,确定要离开吗?')) {
        next();
      } else {
        next(false);
      }
    } else {
      next();
    }
  },
};

五、最后的话

Vue导航守卫是Vue Router提供的一种机制,用于在路由导航过程中执行一些操作。全局守卫可以在整个应用程序的路由导航过程中被调用,而路由独享守卫只对特定的路由生效。通过使用导航守卫,我们可以实现权限验证、数据预加载等功能,提升用户体验和应用程序的安全性。


能力一般,水平有限,本文可能存在纰漏或错误,如有问题欢迎指正,感谢你阅读这篇文章,如果你觉得写得还行的话,不要忘记点赞、评论、收藏哦!祝生活愉快!

用户评论