• Vue Router 路由守卫(导航守卫)


    一、什么是导航守卫

    1、官方的定义

    提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

    2、自己的理解

    导航守卫就是路由跳转过程中的一些钩子函数,再直白点路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事儿的时机,比如跳转前是否验证登录等,这就是导航守卫。

    二、使用导航守卫

    1、安装包

    npm导入
    npm install vue-router --save
    
    cnpm淘宝镜像导入
    cnpm install vue-router --save
    如果没有安装淘宝镜像需要先安装
    npm install -g cnpm --registry=https://registry.npm.taobao.org
    

    2、全局守卫

    是指路由实例上直接操作的钩子函数,他的特点是所有路由配置的组件都会触发,直白点就是触发路由就会触发这些钩子函数。钩子函数按执行顺序包括beforeEach、beforeResolve(2.5+)、afterEach三个

    beforeEach:

    在路由跳转前触发,参数包括to,from,next(参数会单独介绍)三个,这个钩子作用主要是用于登录验证,也就是路由还没跳转提前告知,以免跳转了再通知就为时已晚。

    beforeResolve(2.5+)

    这个钩子和beforeEach类似,也是路由跳转前触发,参数也是to,from,next三个,和beforeEach区别官方解释为:

    区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
    即在 beforeEach 和 组件内beforeRouteEnter 之后,afterEach之前调用。

    afterEach:

    和beforeEach相反,他是在路由跳转完成后触发,参数包括to,from没有了next(参数会单独介绍),他发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫,后讲)之前。

    他们的使用如下:

    router.beforeEach((to, from, next) => {
      //to 将要访问的路径
      //from 代表从哪个路径跳转而来
      //next 是一个函数,表示放行
      // next() 放行  next('/login') 强制跳转
    })
    

    小案例:

    比如我们的后台管理系统,基本上都是需要登录后才能操作的,所以路由跳转前先判断是否登录,如果未登录状态就强制跳转到登录页,代码如下
    router 模块

    import Vue from "vue";
    import VueRouter from "vue-router";
    import Login from "../components/Login";
    import Home from "../components/Home";
    import Welcome from "../components/Welcome";
    import User from "../components/User/User";
    
    
    Vue.use(VueRouter);
    const router = new VueRouter({
      routes: [
        { path: "/", redirect: "/login" },
        { path: "/login", component: Login },
        {
          path: "/home", component: Home,
          redirect: 'welcome',
          children: [
            { path: '/welcome', component: Welcome },
            { path: '/users', component: User },
          ]
        }
      ]
    });
    //挂载路由导航守卫,控制页面访问权限
    
    router.beforeEach((to, from, next) => {
      if (to.path === '/login') return next();
      //获取token
      const tokenStr = window.sessionStorage.getItem('token')
      if (!tokenStr) return next('/login')
      next()
    })
    
    export default router;
    

    3、单个路由独享

    是指在单个路由配置的时候也可以设置的钩子函数,其位置就是下面示例中的位置,也就是像Foo这样的组件都存在这样的钩子函数。目前他只有一个钩子函数beforeEnter。

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => {
            // ...
          }
        }
      ]
    })
    

    beforeEnterbeforeEach 完全相同,如果都设置则在beforeEach之后紧随执行,参数to、from、next

    小案例

    当只有进入某个路由时,才需要验证,使用路由元信息
    在路由配置中加入 meta

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          children: [
            {
              path: 'bar',
              component: Bar,
              // a meta field
              meta: { requiresAuth: true }
            }
          ]
        }
      ]
    })
    
    router.beforeEach((to, from, next) => {
      if (to.matched.some(record => record.meta.requiresAuth)) {
        // this route requires auth, check if logged in
        // if not, redirect to login page.
        if (!auth.loggedIn()) {
          next({
            path: '/login',
            query: { redirect: to.fullPath }
          })
        } else {
          next()
        }
      } else {
        next() // 确保一定要调用 next()
      }
    })
    

    4、组件级

    是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数。钩子函数按执行顺序包括beforeRouteEnter、beforeRouteUpdate (2.2+)、beforeRouteLeave三个,执行位置如下:

    <template>
      ...
    </template>
    export default{
      data(){
        //...
      },
      beforeRouteEnter (to, from, next) {
        // 在渲染该组件的对应路由被 confirm 前调用
        // 不!能!获取组件实例 `this`
        // 因为当守卫执行前,组件实例还没被创建
      },
      beforeRouteUpdate (to, from, next) {
        // 在当前路由改变,但是该组件被复用时调用
        // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
        // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
        // 可以访问组件实例 `this`
      },
      beforeRouteLeave (to, from, next) {
        // 导航离开该组件的对应路由时调用
        // 可以访问组件实例 `this`
      }
    }
    <style>
      ...
    </style>
    

    beforeRouteEnter

    路由进入之前调用,参数包括to,from,next。该钩子在全局守卫beforeEach和独享守卫beforeEnter之后,全局beforeResolve和全局afterEach之前调用,要注意的是该守卫内访问不到组件的实例,也就是this为undefined,也就是他在beforeCreate生命周期前触发。在这个钩子函数中,可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数,可以在这个守卫中请求服务端获取数据,当成功获取并能进入路由时,调用next并在回调中通过 vm访问组件实例进行赋值等操作,(next中函数的调用在mounted之后:为了确保能对组件实例的完整访问)。

    beforeRouteEnter (to, from, next) {
      // 这里还无法访问到组件实例,this === undefined
      next( vm => {
        // 通过 `vm` 访问组件实例
      })
    }
    

    beforeRouteUpdate (v 2.2+)

    在当前路由改变时,并且该组件被复用时调用,可以通过this访问实例。参数包括to,from,next。可能有的同学会疑问,what is 路由改变 or what is 组件被复用?

    对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,组件实例会被复用,该守卫会被调用
    当前路由query变更时,该守卫会被调用

    beforeRouteLeave

    导航离开该组件的对应路由时调用,可以访问组件实例this,参数包括to,from,next。

    三、总结

    全局路由钩子:

    beforeEach(to,from, next)、beforeResolve(to,from, next)、afterEach(to,from);

    独享路由钩子:

    beforeEnter(to,from, next);

    组件内路由钩子:

    beforeRouteEnter(to,from, next)、beforeRouteUpdate(to,from, next)、beforeRouteLeave(to,from, next)

    导航守卫回调参数

    to:目标路由对象;

    from:即将要离开的路由对象;

    next:他是最重要的一个参数,他相当于佛珠的线,把一个一个珠子逐个串起来。以下注意点务必牢记:

    1.但凡涉及到有next参数的钩子,必须调用next() 才能继续往下执行下一个钩子,否则路由跳转等会停止。

    2.如果要中断当前的导航要调用next(false)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from路由对应的地址。(主要用于登录验证不通过的处理)

    3.当然next可以这样使用,next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。意思是当前的导航被中断,然后进行一个新的导航。可传递的参数与router.push中选项一致。

    4.在beforeRouteEnter钩子中next((vm)=>{})内接收的回调函数参数为当前组件的实例vm,这个回调函数在生命周期mounted之后调用,也就是,他是所有导航守卫和生命周期函数最后执行的那个钩子。

    5.next(error): (v2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

    当点击切换路由时:

    beforeRouterLeave-->beforeEach-->beforeEnter-->beforeRouteEnter-->beforeResolve-->afterEach-->beforeCreate-->created-->beforeMount-->mounted-->beforeRouteEnter的next的回调

    当路由更新时:

    beforeRouteUpdate
    官方文档

  • 相关阅读:
    关于oracle分页出现数据重复的问题
    VSCode如何配置中文环境
    POI导出excel执行自动求和
    IE浏览器不支持document.getElementsByClassName的解决办法
    原生JavaScript实现切换tab显示不同的样式
    easyUI日期控件只选择月份和日期
    POI导出Excel的两种方法
    python Django 学习笔记(四)—— 使用MySQL数据库
    python Django 学习笔记(三)—— 模版的使用
    python Django 学习笔记(二)—— 一个简单的网页
  • 原文地址:https://www.cnblogs.com/qingheshiguang/p/14679561.html
Copyright © 2020-2023  润新知