巧用Vue-Router路由守卫实现路由权限控制和加载进度

在系统路由跳转前做权限校验,是经常遇到的需求。本文将使用Vue-Router中的路由守卫功能实现权限控制和加载进度。

路由守卫

Vue-Router提供了两个钩子函数,分别是前置守卫beforeEach和后置守卫afterEach,其中前置守卫在路由跳转前触发,后置守卫在路由跳转后触发。

可以使用下面的方式注册全局路由守卫,当路由跳转触发时,路由守卫按照创建顺序异步解析执行,只有所有守卫resolved才会进入resolved状态,否则一直处于pending状态中。

const router = new VueRouter({ ... })

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

// 全局注册后置守卫
router.afterEach((to, from, next) => {
  // ...
})

守卫的回调函数接收三个参数:

  • to: 即将要进入的路由,一个Route对象
  • from: 正要离开的路由,一个Route对象
  • next: 一个Function,回调函数内部必须执行该方法,令守卫进入resolved状态。根据调用参数不同,其效果也不同
    • next(): 进行守卫管道中的下一个钩子。如果全部钩子执行完了,则路由跳转的状态就是confirmed
    • next(false): 中断当前的路由跳转。如果浏览器的 URL 改变了,那么 URL 地址会重置到 from 路由对应的地址。
    • next('/') 或者 next({ path: '/' }): 中止当前路由跳转,并跳转到参数指定的路由,这个参数支持的格式和router.push()的参数相同。
    • next(Error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则中止路由跳转,并且该错误会被传递给 router.onError() 注册过的回调。

守卫回调函数中必须调用 next 方法,否则钩子就不会被 resolved

具体内容文档可以查看Vue-Router官方文档。

权限校验

下面示例就是在前置守卫中对登录状态以及跳转路由的权限进行判断,如果没有登录就跳转至登录页,如果没有权限就跳转至403页面。

import router from './router'
import store from './store'
import { getToken } from '@/utils/token'

const whiteList = ['/login'] // 白名单,不鉴权跳转

router.beforeEach((to, from, next) => {
  // 此处进行鉴权操作
  const token = getToken()

  if (token) {
    if (to.path === '/login') {
      next('/') // 系统根路由
    } else {
      // 其他鉴权操作,比如资源是否可访问
      let menus = store.getters['user/menus']
      if (menus.includes(to.path)) {
        next()
      } else {
        next({
          path: '/403',
          replace: true // 替换当前路由,避免用户后退等操作导致重复跳转
        })
      }
    }
  } else {
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
    }
  }
})

加载进度

在单页应用中跟路由匹配加载不同组件,如果网速较差时,资源加载慢会导致白屏时间增长,而用户得不到反馈的信息情况下,大概率会关闭页面,此时就可以使用前置守卫和后置守卫在页面上进行一些操作,比如当前页面加载进度条。

这里可以使用NProgress,直接npm安装即可,非常轻量。具体使用教程可以查询NProgress文档

npm install -S nprogress

import router from './router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

NProgress.configure({ showSpinner: false }) // 配置NProgress

router.beforeEach((to, from, next) => {
  NProgress.start()
  next()
})

router.afterEach(() => {
  NProgress.done()
})

可以看到,使用起来非常方便。当然也可以修改样式展示不同的效果。

#nprogress .bar {
  padding: 0 !important;
  color: rgb(15, 75, 96) !important;
}

功能整合

上述两个功能算是常见需求,可以整合在一起,代码如下。

import router from './router'
import store from './store'
import { getToken } from '@/utils/token'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

NProgress.configure({ showSpinner: false })

const whiteList = ['/login'] // 白名单,不鉴权跳转

router.beforeEach((to, from, next) => {
  NProgress.start()
  // 此处进行鉴权操作
  const token = getToken()

  if (token) {
    if (to.path === '/login') {
      next('/') // 系统根路由
    } else {
      // 其他鉴权操作,比如资源是否可访问
      let menus = store.getters['user/menus']
      if (menus.includes(to.path)) {
        next()
      } else {
        next({
          path: '/403',
          replace: true // 替换当前路由,避免用户后退等操作导致重复跳转
        })
      }
    }
  } else {
    if (whiteList.includes(to.path)) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

总结

Vue-Router的路由守卫是一个非常强大的功能,合理利用可以让系统更加完善,用户体验更加良好。

你可能感兴趣的:(随笔,Vue)