• Vue学习第33天——路由守卫(导航守卫)超详解讲解及使用场景、案例练习


    一、路由守卫相关知识

    1、概念

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

    2、作用

    对路由进行权限控制

    3、分类

    全局守卫、独享守卫、组件内守卫

    二、全局守卫详解

    全局守卫又分为全局前置守卫和全局后置守卫

    1、全局前置守卫

    当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
    ① 执行时间
    初始化时执行,每次路由切换前执行
    ② 使用场景
    全局前置守卫通常用来进行路由跳转的一些信息判断,判断是否登录,是否拿到对应的路由权限等等。
    ③ 使用方法
    可以使用 router.beforeEach 注册一个全局前置守卫

    const router = new VueRouter({ ... })
    
    router.beforeEach((to, from,next) => {
      //to: 即将要进入的目标路由
      //from:当前导航正要离开的路由
      // next():进行下一个路由
      
    })
    

    2、全局后置守卫

    ① 执行时间
    初始化时执行,每次路由切换后执行
    ② 使用场景
    对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
    ③ 注意项
    不会接受 next函数,也不会改变导航本身
    ④ 使用方法
    可以使用 router.afterEach 注册一个全局后置守卫

    const router = new VueRouter({ ... })
    
    router.afterEach((to, from) => {
      document.title = to.meta.title //修改网页的title
    })
    

    三、路由独享守卫详解

    ① 执行时间
    独享守卫 只在进入路由时触发,不会在 params、query 或 hash 改变时触发。它们只有在 从一个不同的 路由导航时,才会被触发。
    ② 注意项
    独享守卫没有后置,可以全局后置路由守卫搭配使用
    ③ 使用方法
    直接在路由配置上使用 beforeEnter定义独享守卫

    const routes = [
      {
        path: '/cats',
        component: Cats,
        beforeEnter: (to, from,next) => {
          if(to.meta.isAuth) {
          	next()
          }else {
          	alert('暂无权限')
          }
        },
      },
    ]
    

    四、组件内守卫详解

    组件内直接定义路由导航守卫
    组件内守卫又分为进入守卫和离开守卫

    1、进入守卫

    ① 执行时间
    通过路由规则进入该组件时被调用

    ② 注意点
    进入守卫不能访问this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

    ③ 使用方法
    可以使用 beforeRouteEnter 注册一个进入守卫

      beforeRouteEnter(to, from, next) {
        // 在渲染该组件的对应路由被验证前调用
        // 不能获取组件实例 `this` !因为当守卫执行时,组件实例还没被创建!
      },
    

    ④ 可以传一个回调给next来访问组件实例
    可以通过传一个回调给 next 来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数

    beforeRouteEnter (to, from, next) {
      next(vm => {
        // 通过 `vm` 访问组件实例
      })
    }
    

    2、离开守卫

    ① 执行时间
    通过路由规则离开该组件时被调用
    ② 使用场景
    离开守卫通常用来预防用户在还未保存修改前突然离开。该导航可以通过返回 false 来取消
    ③ 使用方法
    可以使用 beforeRouteLeave 注册一个离开守卫

    beforeRouteLeave (to, from, next) {
      const answer = alert('还未保存,确定要离开吗')
      if (answer) {
      	next() //放行
      }else {
      	return false //取消
      }
    }
    

    五、案例练习

    知识补充
    meta:路由元信息,即程序员自定义信息,在路由规则中配置

    {
    	name:"miaomiao",
    	path:'/cats',
    	component:Cats,
    	//路由元信息,是否需要权限
    	meta:{isAuth:true}
    }
    

    案例需求:dogs.vue、catsAbout.vue、OwnerAbout.vue三个路由组件需要权限展示
    采用bootstrap样式,可以在public/index.html中引入bootstrap样式

    router/index.js代码

    import Vue from "vue";
    import VueRouter  from "vue-router";
    
    Vue.use(VueRouter);
    
    import Cats from "../pages/Cats";
    import Dogs from "../pages/Dogs";
    import CatsAbout from "../pages/CatsAbout";
    import OwnerAbout from "../pages/OwnerAbout"
    
    const router = new VueRouter({
        routes:[
            {
                name:"miaomiao",
                path:'/cats',
                component:Cats,
                children:[
                    {
                        name:"miaoAbout",
                        path:'catsAbout',
                        component:CatsAbout,
                        meta:{isCat:true}
                    },
                    {
                        name:"zhurenAbout",
                        path:'/ownerAbout',
                        component:OwnerAbout,
                        //路由元信息,是否需要权限
                        meta:{
                            isAuth:true,
                            title:'铲屎官相关信息'
                        }
                    }
                ]
            },
            {
                name:"wangwang",
                path:'/dogs',
                component:Dogs,
                meta:{isDog:true},
                //独享守卫:逻辑与全局前置守卫一样
                beforeEnter(to,from,next){
                    if(to.meta.isDog){
                        if(localStorage.getItem('dogName') == 'dog') {
                            next()
                        } else {
                            alert('暂无权限查看狗狗相关信息')
                        }
                    }
                }
            },
    
        ]
    })
    
    //全局前置路由守卫 :验证登录信息
    router.beforeEach((to,from,next)=>{
        if(to.meta.isAuth) {
            //铲屎官相关路由组件需要验证name是否为liqi6limi
            if(localStorage.getItem('name') == 'liqi6limi') {
                next()
            } else {
                alert('暂无权限查看铲屎官相关信息')
            }
        }else {
            next()
        }
    })
    
    //全局后置路由守卫:修改网页title
    router.afterEach((to,from)=>{
        //修改网页标题
        if(to.meta.title) {
            document.title = to.meta.title
        }else {
            document.title = '动物学院网站';
            console.log(from);
        }
    })
    
    export default router;
    

    App.vue代码

    <template>
      <div id="app">
        <h3>动物学院h3>
          <button @click="catSchool" class="btn btn-info active" >喵喵院系button>
          <button @click="dogSchool" class="btn btn-info active" >汪汪院系button>
          <router-view>router-view>
      div>
    template>
    
    <script>
    
    export default {
      name: 'App',
      methods: {
        catSchool(){
          this.$router.push({
            name:"miaomiao"
          },() => {})
        },
        dogSchool() {
            this.$router.push({
            name:"wangwang"
          },() => {})
        }
      }
    }
    script>
    <style >
      button {
        margin: 5px;
      }
     #app {
      width: 100%;
      text-align: center;
     }
       li {
        line-height: 40px;
        height: 40px;
      }
      span {
        margin-right: 5px;
      }
    style>
    

    Dogs.vue代码

    <template>
      <div>
        <h3>汪汪学院相关人员h3>
        <p>目前还没有养狗,等我有钱了再养一只修狗p>
        <router-view>router-view>
      div>
    template>
    
    <script>
    export default {
      name:"Dogs",
    }
    script>
    

    Cats.vue代码

    <template>
      <div>
        <h3>喵喵学院相关人员h3>
        <button class="btn btn-success" @click="catAbout">喵喵相关button>
        <button class="btn btn-success" @click="ownerAbout">铲屎官相关button>
        <router-view>router-view>
      div>
    template>
    
    <script>
    export default {
      name:"Cats",
      methods:{
        catAbout(){
          this.$router.push({
            path:"/cats/catsAbout",
          },()=>{})
        },
        ownerAbout(){
           this.$router.push({
            name:"zhurenAbout",
          },()=>{})
        }
      }
    }
    script>
    

    CatsAbout.vue代码

    <template>
      <div>
            <ul class="list-unstyled">
          <li v-for="(cat,index) in cats" :key="index">
            <span>喵喵名:{{cat.name}}span>
            <span>性别:{{cat.sex}}span>
            <span>年龄:{{cat.age}}span>
            <span>其他:已绝育,疫苗已打span>
          li>
        ul>
      div>
    template>
    
    <script>
    export default {
      name:"CatsAbout",
      data(){
        return {
          cats:[{
            name:"憨瓜",
            age:"4岁整",
            sex:"公"
          },{
            name:"波妞",
            age:"3岁3个月",
            sex:"母",
          }]
        }
      },
      //进入守卫:通过路由规则进入组件时被调用
      beforeRouteEnter(to,from,next){
        if(to.meta.isCat){
            if(localStorage.getItem('catName') == 'cat') {
                next()
            } else {
                alert('暂无权限查看猫猫相关信息')
            }
        }
      },
      //离开守卫:通过路由规则离开时被调用
      beforeRouteLeave(to,from,next){
        console.log(to,from);
        next()
      },
    }
    script>
    

    OwnerAbout.vue代码

    <template>
        <div>
            <h4>本人养有2只猫:憨瓜和波妞,等我有钱了再养一只狗h4>
        div>
    template>
    <script>
        export default ({
           name:"OwnerAbout",
        })
    script>
    

    运行结果
    在这里插入图片描述

    六、总结

    1、独享守卫beforeEnter 只有前置没有后置,可以搭配全局后置守卫afterEach使用

    2、进入守卫beforeRouteEnter 是支持给 next 传递回调的唯一守卫

    3、组件内守卫与全局守卫的区别
    全局守卫是进入前和进入后,组件内守卫是进入前和出来后,组件守卫也可以搭配全局后置守卫afterEach使用

    4、路由守卫使用场景
    ① 全局前置守卫beforeEach通常用来进行路由跳转的一些信息判断,判断是否登录,是否拿到对应的路由权限等等
    ② 全局后置守卫afterEach对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
    ③ 离开守卫beforeRouteLeave通常用来预防用户在还未保存修改前突然离开。该导航可以通过返回 false 来取消

    5、每个守卫方法接收3个参数
    to::route, 即将要进入的目标路由;
    from: route,当前导航正要离开的路由;
    next:function, 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

    next 可以返回的值如下:
    next(): 进行下一个路由。如果全部路由执行完了,则导航的状态就是 confirmed (确认的)

    next(false):取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址

    next('/') next({ path: '/' }):通过一个路由地址跳转到一个不同的地址,就像调用 router.push() 一样,当前的导航被中断,然后进行一个新的导航,就和 from 一样

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

    七、路由守卫解析流程

    1、导航被触发
    2、在失活的组件里调用 离开守卫 beforeRouteLeave
    3、调用 全局前置守卫 beforeEach
    4、在重用的组件里调用 更新守卫beforeRouteUpdate (2.2+)(举例来说,对于一个带有动态参数的路径 /user/:id,在 /users/1/users/2 之间跳转的时候,由于会渲染同样的 UserDetail 组件,因此组件实例会被复用。而这个守卫就会在这个情况下被调用)
    5、在路由配置规则里调用 独享守卫 beforeEnter
    6、解析异步路由组件
    7、在被激活的组件里调用 进入守卫 beforeRouteEnter
    8、调用全局解析守卫 beforeResolve (2.5+)(和 全局前置守卫router.beforeEach 类似,因为它在每次导航时都会触发,但是确保在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用)
    9、导航被确认
    10、调用全局后置守卫 afterEach
    11、触发 DOM 更新
    12、调用 进入守卫 beforeRouteEnter中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入
    在这里插入图片描述

  • 相关阅读:
    DC-4 靶机
    Python办公自动化之Word
    Day4:写前端项目(html+css+js)
    7.联合索引(最左前缀原则)
    Twain的学习记录和基于Qt的相关开源项目详解
    Python PDF转化wolrd代码怎么写
    树的直径(dp和bfs求法)
    93 # 实现 express 错误处理中间件
    初探微前端
    Python-图像拼接神器-stitching
  • 原文地址:https://blog.csdn.net/Vest_er/article/details/127079620