• Vue守卫详解



    导航守卫就是路由跳转过程中的一些钩子函数,这个过程中触发的这些函数能让你有操作一些其他的事儿的时机,这就是导航守卫。

    守卫适用于切面编程,即把一件事切成好几块,然后分给不同的人去完成,提高工作效率,也可以让代码变得更加优雅。

    1. 全局导航守卫

    语法:

    # 守卫参数
    	+ to: Route: 即将要进入的目标 路由对象
    	+ from: Route: 当前导航正要离开的路由
    	+ next: Function: 一定要调用该next方法,否则路由不向下执行,页面空白。
    
    # 全局前置守卫,当一个导航触发时,立刻触发前置守卫,
    router.beforeEach((to, from, next) => {
      // ...
      next()
    })
    
    //全局解析守卫,等到路由独享守卫和组件内守卫都解析完毕后执行
    router.beforeResolve((to, from, next) => {
      // ...
      next()
    })
    
    # 全局后置钩子,全部守卫执行完毕后执行
    // 此钩子不会接受 next 函数也不会改变导航本身
    router.afterEach((to, from) => {
      // ...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    全局导航守卫执行顺序:

    news.js(这个文件是从 index.js 文件中抽取拆分出来的,最终要被引入到 insex.js 文件中):

    import News from '@/views/News'
    import Detail from '@/views/Detail'
    import Login from '@/views/Login'
    
    const routes = [
        {
            path: '/news',
            component: News,
        },
        {
            path: '/news/:id',
            name: 'xw',
            component: Detail,
        },
        {
            // 这是登录页
            path: '/login',
            component: Login,
        }
    ]
    
    export default routes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    index.js:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    import news from './routes/news'
    
    // 以插件的方式添加
    Vue.use(VueRouter)
    
    // 实例化路由对象及配置路由表
    
    const routes = [...news]
    
    const router = new VueRouter({
      // 路由模式
      mode: 'history',
      // 路由规则表
      routes
    })
    
    // 全局守卫 每次切换页面都会执行到
    // 前置
    router.beforeEach((to, from, next) => {
      console.log('全局 --- beforeEach')
      next()
    })
    
    // 解析
    router.beforeResolve((to, from, next) => {
      console.log('全局 --- beforeResolve')
      next()
    })
    
    // 后置
    router.afterEach((to, from) => {
      console.log('全局 --- afterEach')
    })
    
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    登录页(index.vue):

    <template>
      <div>
        <button>登录用户button>
      div>
    template>
    
    <script>
    export default {
    
    }
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    现在我们有这样一个需求,用户只有在登录成功之后,才能访问新闻页面,该怎么做呢?

    index.js:

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    import news from './routes/news'
    
    // 以插件的方式添加
    Vue.use(VueRouter)
    
    // 实例化路由对象及配置路由表
    const routes = [...news]
    
    const router = new VueRouter({
      // 路由模式
      mode: 'history',
      // 路由规则表
      routes
    })
    
    // 用全局前置守卫判断用户是否登录
    router.beforeEach((to, from, next) => {
      // 在使用导航守卫来验证用户是否登录,一定要把登录页面路由排除掉,防止死循环
      // 如果没有在本地存储中获取到token值,并且即将跳转的页面不是登录页
      if (!sessionStorage.getItem('token') && to.path != '/login') {
        // 到登录页面
        // next('/login')
        // replace: true表示跳转到登录页面后,不允许回退
        next({ path: '/login', replace: true })
      } else {
        next()
      }
    })
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    2. 路由独享守卫

    语法:

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => {
            // ...
    		next()
          }
        }
      ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用:

    news.js(这个文件是从 index.js 文件中抽取拆分出来的,最终要被引入到 insex.js 文件中):

    import News from '@/views/News'
    import Detail from '@/views/Detail'
    import Login from '@/views/Login'
    
    const routes = [
      {
        path: '/news',
        component: News,
      },
      {
        path: '/news/:id',
        name: 'xw',
        component: Detail,
      },
        {
          // 这是登录页
          path: '/login',
          component: Login,
          // 路由独享守卫 
          // 只有当前的路由规则才生效,比如登录页面的路由独享守卫在进入新闻页面时就不会生效
          // 路由独享守卫在每次进入到当前路由页面时都会执行
          beforeEnter: (to, from, next) => {
            console.log('路由独享守卫 ==login -- --- beforeEnter')
            next()
          }
        }
    ]
    
    export default routes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    3. 组件内守卫

    语法:

    你可以在路由组件内直接定义以下路由导航守卫:

    const Foo = {
      template: `...`,
      //执行完全局前置守卫和路由独享守卫,就会执行当前函数
      beforeRouteEnter (to, from, next) {
        // 在渲染该组件的对应路由被 confirm 前调用
        // 不!能!获取组件实例 `this`
        // 因为当守卫执行前,组件实例还没被创建
      },
    
      //动态路由参数改变就会触发这个函数
      beforeRouteUpdate (to, from, next) {
        // 在当前路由改变,但是该组件被复用时调用
        // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
        // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
        // 可以访问组件实例 `this`
      },
    
      //离开当前页面时调用
      beforeRouteLeave (to, from, next) {
        // 导航离开该组件的对应路由时调用
        // 可以访问组件实例 `this`
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    所有守卫和生命周期函数的执行顺序:

    news.js(这个文件是从 index.js 文件中抽取拆分出来的,最终要被引入到 insex.js 文件中):

    import News from '@/views/News'
    import Detail from '@/views/Detail'
    import Login from '@/views/Login'
    
    const routes = [
      {
        path: '/news',
        component: News,
      },
      {
        path: '/news/:id',
        name: 'xw',
        component: Detail,
        beforeEnter: (to, from, next) => {
          console.log('路由独享守卫 -- detail --- beforeEnter')
          next()
        }
      },
        {
          // 这是登录页
          path: '/login',
          component: Login,
          // 路由独享守卫 
          // 只有当前的路由规则才生效,比如登录页面的路由独享守卫在进入新闻页面时就不会生效
          // 路由独享守卫在每次进入到当前路由页面时都会执行
          beforeEnter: (to, from, next) => {
            console.log('路由独享守卫 ==login -- --- beforeEnter')
            next()
          },
        }
    ]
    
    export default routes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    详情页(index.vue):

    <template>
      <div>
        <h3>新闻详情页h3>
      div>
    template>
    
    <script>
    export default {
      // 当路由访问到此组件时,执行此钩子函数
      beforeRouteEnter(to, from, next) {
        console.log("组件 --- beforeRouteEnter");
        next();
      },
    
      // 离开当前路由组件
      beforeRouteLeave(to, from, next) {
        console.log("组件 --- beforeRouteLeave");
        next();
      },
    
      // 路由参数的改变,触发路由组件守卫
      beforeRouteUpdate(to, from, next) {
        console.log(this);
        console.log("组件 --- beforeRouteUpdate");
        next();
      },
    
      // 和生命周期函数比较以下执行顺序
      // 所有路由解析完毕以后,才开始执行生命周期函数
      beforeCreate() {
        console.log('组件 === beforeCreate')
      },
    
      beforeDestroy() {
        console.log('组件 === beforeDestroy')
      },
      destroyed() {
        console.log('组件 === destroyed')
      },
    };
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    下面我们来看beforeRouteUpdate函数什么时候执行。

    详情页(index.vue):

    <template>
      <div>
        <h3>新闻详情页h3>
        <router-link to="/news/1">111router-link><br />
        <router-link to="/news/2">222router-link><br />
        <router-link to="/news/3">333router-link>
      div>
    template>
    
    <script>
    export default {
      // 当路由访问到此组件时,执行此钩子函数
      beforeRouteEnter(to, from, next) {
        console.log("组件 --- beforeRouteEnter");
        next();
      },
    
      // 离开当前路由组件
      beforeRouteLeave(to, from, next) {
        console.log("组件 --- beforeRouteLeave");
        next();
      },
    
      // 路由参数的改变,触发路由组件守卫
      // 可以用来监听页面是否发生变化
      beforeRouteUpdate(to, from, next) {
        // console.log(this);
        console.log("组件 --- beforeRouteUpdate");
        next();
      },
        
      // 监听器也可以用来监听页面是否发生变化
      // watch:{
      //   '$route'(n){
      //     console.log('watch --- ' ,n);
      //   }
      // },
    
      // 和生命周期函数比较以下执行顺序
      // 所有路由解析完毕以后,才开始执行生命周期函数
      beforeCreate() {
        console.log('组件 === beforeCreate')
      },
    
      beforeDestroy() {
        console.log('组件 === beforeDestroy')
      },
      destroyed() {
        console.log('组件 === destroyed')
      },
    };
    script>
    
    <style lang="scss" scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    在这里插入图片描述

  • 相关阅读:
    JAVA SE 基础总结
    读书笔记:Java8 Streams用法总结大全 之 Stream中的常见操作
    Linux实验操作二
    Python 使用 Opencv 库调用摄像头
    聊聊在不确定环境下的个人成长
    项目上线就炸,这谁受得了
    记录一下工作中completableFutures异步多线程的使用
    初识Spring(一)
    视频汇聚/视频云存储/视频监控管理平台EasyCVR部署后无法正常启用是什么问题?该如何解决?
    Excel中的subtotal函数
  • 原文地址:https://blog.csdn.net/weixin_45605541/article/details/126911493