Vue导航守卫

850 阅读2分钟

1 概述

  • 别名:路由钩子、路由守卫、路由拦截
  • 作用:对路由的跳转进行拦截
  • 守卫类型
    • 全局导航守卫:对整个项目做控制
    • 路由独享守卫:对单个路由配置做控制
    • 路由内守卫:对组件对应的路由做控制
  • 回调参数
    • to:表示目标路由
    • from:表示当前路由
    • next 表示两者之间的连接
      • next() 默认连通
      • next(true) 允许跳转,和next()相同
      • next (false) 取消跳转
      • next('/xxx') / next({ name: 'home', params: {},query: {} }) 跳转到指定路由
      • next( vm => { } ) // vm指的是目标组件(组件前置守卫无法获取this,用vm代替)

2 全局导航守卫

2.1 全局前置守卫

  • 使用场景

    • 后台管理系统、社区app 做登录拦截
  • 使用方法

    // 进行登录判断,若有token,允许跳转,否则一律跳到登录页
    
    import router from '@/router' 
    import { getCookie } from '@/utils/cookie'
    
    router.beforeEach(( to,from,next ) => { // 前置守卫必须写next
        // next的参数
        // next( false )不允许跳转
        // next() == next( true )运行跳转
    	// next('/login') 拦截并跳转至指定路由
        // 有重定向,先完成重定向跳转
        if ( to.path == '/home/hot' ) {
          next()
        }
    	// 判断token
        const token = getCookie(' _token')
    	
        if ( token || to.path == '/login') {// 二次触发时to.path == '/login'成立,直接跳转
            next()
            return
        } else {
          // 若没有token,且不是去登录页,强制转到登录页
          next('/login') // 路由跳转,触发导航守卫再次执行该文件
        }
    
    })
    

2.2 全局后置守卫

  • 没有拦截功能,常用于跳转后提示信息

    router.afterEach((to) => {
        if ( to.path == '/recommend' ) {
          Notify({ type: 'success', message: '通知内容' });
        }
      })
    

2.3 全局更新守卫

  • 使用与前置守卫相同

  • 区别:是否完整遍历路由表

    • 更新守卫要遍历完整路由表没有配置错误才跳转页面

3 路由独享守卫

  • 只在设置守卫的路由生效

    /* 
      * 路由表
    */
    // 引入cookie.js
    import { getCookie } from '@/utils/cookie'
    import Vue from 'vue'
    import { Toast } from 'vant'
    Vue.use( Toast )
    
    // 路由懒加载
    const ShopCar = () => import(/* webpackChunkName: "group-ljun" */ '@/views/shopcar/index.vue')
    const Error = () => import(/* webpackChunkName: "group-ljun" */ '@/views/error/index.vue')
    
    const routeTable = [
      {
        path: '/shopcar',
        component: ShopCar,
        beforeEnter ( to,from,next ) {
          console.log('to',to)
          const token = getCookie('_token')
          if ( token ) {
            next()
          } else {
            Toast.fail('您还没有登录,无法查看购物车,请先去登录')
            next( false )
          }
        },
        meta: {
          include: 'ShopCar'
        }
      },
      {
        path: '*',// 必须放在配置最下面 - 错误路由配置
        component: Error,
        meta: {
          include: 'Error'
        }
      }
    ]
    export default routeTable 
    

4 组件内守卫

4.1 组件前置守卫

  • 拦截组件的进入

  • 执行: 创建组件实例前执行,这个时候没有组件,没有this

  • 功能

    • 判断是否有token,然后是否能进入当前页面
      <template>
        <div class="mine">
          个人中心
        </div>
      </template>
      
      <script>
      import { getCookie  } from '@/utils/cookie'
      export default {
        beforeRouteEnter (to,from,next) { // 组件内的前置钩子
          const token = getCookie('_token')
          if ( token ) {
            next()
            return ;
          }
          next( false )
        }
      }
      </script>
    
    • 数据预载:进入组件前,提前得到数据,并将这个数据赋值给组件
    <script>
    import request from '@/utils/request.js';
    export default {
      async beforeRouteEnter ( to,from,next ) {
        // 数据预载
        console.log(to,from,next)
        const result = await request({
          url: '/ajax/search',
          params: {
            kw: '万达',
            cityId: 1,
            stype: 2
          }
        })
        // console.log("beforeRouteEnter -> result", result.data.cinemas.list ) 
    
        next( vm => { // vm就是当前组件  -> 解决的就是这个钩子得不到this
          // vm.cinemas = result.data.cinemas.list  这么写可行吗? 不行 
          // 对象的合并  Object.assign() -> Vue.set/this.$set( 属性,属性值 )
          vm.$set( vm.cinemas, JSON.stringify(result.data.cinemas.list))
          next()
        })
      },
      data () {
        return {
          cinemas: {}
        }
      }
    }
    </script>
    

4.2 组件后置守卫

  • 拦截组件离开

  • 执行: 离开组件前,这个时候有组件,有this

  • 功能

    • 已填写部分表单未提交就跳转时进行
    beforeRouteLeave ( to,from,next ) {
        // 将要离开组件了
        if ( this.username || this.password ) {
          if (confirm('您还没有提交,确定要离开吗?')) {
            next()
            return;
          } else {
            next( false )
            return;
          }
        }
        next()
      }
    

基础决定未来,一步一个脚印