Vue-Router导航守卫快速了解与应用

北极光之夜。 发表于 2021/07/14 15:24:34 2021/07/14
【摘要】 一.简介与小案例:  嘿,最近你还好吗?ヽ(。◕‿◕。)ノ゚。我昨晚看到了这样的一句话: 他们想把我埋了,却不知道我是一颗种子。我不知道作者是谁,不过我想肯定是一个温柔且坚强的人吧。希望我和你们都可以充满希望,向阳而开。对了,今天,就分享一下vue导航守卫的快速了解与应用,对这部分基础不了解的同学可以快速上手。  在我们通过 vue-router 路由发生跳转时的,也可以用导航这一词概括。...

一.简介与小案例:

  嘿,最近你还好吗?ヽ(。◕‿◕。)ノ゚。今天,就分享一下vue路由导航守卫的快速了解与应用,对这部分基础不了解的同学可以快速上手。

  在我们通过 vue-router 路由发生跳转时的,也可以用导航这一词概括。导航就是表示路由正在发生改变。而导航守卫就可以说成是监听这一改变。当路由跳转时不能直接跳转,会先经过导航守卫设定的条件,通过条件判断接下来该执行什么操作,给不给跳转,或者应该跳到哪里,或者其它操作。
   先不谈 vue 提供的导航守卫,假如我们要自己实现 ‘守卫’ 该怎么实现呢?下面有一个小案例,快速了解 ‘守卫’ 概念。

 1.首先新建了一个vue脚手架项目,并新建一个login.vue与user.vue文件,(假如login为自己定义的登录页,user为个人信息页)然后在路由配置中添加这两个文件的路径,最后在App.vue页面中添加对应的路由链接。以上,为路由的基本使用,就不演示了。最后运行效果如下:

在这里插入图片描述
其中,路由配置我是这样:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/login/login.vue'
import User from '../views/user/user.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path:'/login',
    component: Login
  },
  {
    path:'/user',
    component:User
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

 2. 现在,要实现守卫的概念。就是当我没有在登录页进行登录时,直接点击User时,路由不会跳转到user页面,会直接跳转到login登录页面,只有当我在登录页登录后,点击User才能跳转到user页面:

login.vue页面代码如下,本来登录是要向服务器发一次请求的,因为是演示,所以这里登录不会调用接口。那我们就假如登录后会把账号存储在浏览器本地存储中,当跳转到user页面时,user页面判断本地存储是否存在登录账号信息,存在则显示,否则强行跳到登录页:

<template>
  <div>
    <h3>这是登录页面,登录后才可查看个人信息页面</h3>
    <div>
      <div>账号:<input type="text" v-model="username" /></div>
      <div>密码:<input type="text" v-model="password" /></div>
      <button @click="signIn">登录</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
      password: "",
    };
  },
  methods: {
    signIn() {
    // 保存账号信息
      let token = this.username;
      // 本地存储
      localStorage.setItem("token", token);
    },
  },
};
</script>
<style scoped>
</style>

使用 localStorage 创建一个本地存储的 name/value 对。

user.vue页面如下,在生命周期 created 阶段,进行判断是否登录:

<template>
  <div>
    <h2>个人信息页面</h2>
    <div>账号:{{ username }}</div>
    <div>博客:北极光之夜。</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
    };
  },
  methods: {},
  created() {
  // 获取本地存储
    var token = localStorage.getItem("token");
    console.log(token);
    // 判断是否有登录信息
    if (token) {
       // 有则给username赋值
      this.username = token;
    } else {
    // 没有则路由跳转到登录页
      this.$router.push("/login");
    }
  },
};
</script>
<style scoped>
</style>

效果如下,没登录时,本地存储没信息,路由不会跳转到user页面,会直接跳转到login登录页面:

在这里插入图片描述
登录后,本地存储有值,可以跳转:

在这里插入图片描述




 以上,就基本演示了下守卫的概念,不过是比较繁琐的,假如有很多页面,我们不可能在每个页面都写一次获取和判断,所以我们要引入 vue 中导航守卫,快速实现守卫。

二.vue导航守卫:

导航守卫官方文档链接:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

1.全局前置守卫:

 全局前置守卫用于控制每一次路由跳转,叫做 router.beforeEach,可以使用 router.beforeEach 注册一个全局前置守卫。这个一般写在vue项目中的src文件夹下的 main.js 中:
我的main.js文件内容:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false

// 添加全局前置守卫
router.beforeEach((to,from,next)=>{
     console.log(to,from,next);
     next();
})

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

可以看到,写法如下:

router.beforeEach((to,from,next)=>{
     console.log(to,from,next);
     next();
})

看控制台输出,to,from,next代表什么:

在这里插入图片描述

看得出to、from都是对象,next为方法。还是直接上概念,其中to、from、next 参数意思如下:

参数 意义
to 代表将要跳到哪个路由
from 代表之前是来自哪个路由
next() 进行正常跳转
next(false) 取消跳转
next(“路径”)或者next({ path: ‘路径’ }) 路由重定向,跳转到其它页面

 需要注意的是,要确保 next 函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错。

 如,我现在要实现无法跳转到login页面,其它页面能正常跳转,应该如下实现:

router.beforeEach((to,from,next)=>{
  //如果将要跳到login,则取消跳转
    if(to.path=='/login'){
      next(false);
    }else{
      // 否则正常跳转
      next();
    }
})

效果:

在这里插入图片描述
现在,用全局前置守卫实现第一大点那个小案例:

router.beforeEach((to,from,next)=>{
   if(to.path == '/user'){      
      if(localStorage.getItem("token")){
         next();
      }else{
        next('/login');
      }

   }else{
     next();
   }
})

看,也是一样可以的:

在这里插入图片描述
假如现在进入about页面也要登录才能进,则如下直接在 if 里添加一个或条件就好:

router.beforeEach((to,from,next)=>{
   if(to.path == '/user' || to.path == '/about'){      
      if(localStorage.getItem("token")){
         next();
      }else{
        next('/login');
      }

   }else{
     next();
   }
})

2. 路由守卫:

 运行在路由上的守卫,只有进入到当前路由页面的时候才会执行的守卫函数,叫做 beforeEnter。它一般直接在路由配置里写的。

如我在/user的配置对象里写,只有在user页面这个守卫在生效:

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path:'/login',
    component: Login
  },
  //  在user这里面写
  {
    path:'/user',
    component:User,
    beforeEnter: (to, from, next) => {
           // 输出看看
      console.log(to,from,next);
    }
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

看效果,只有在点击user页面才会有输出:

在这里插入图片描述
 这些守卫与全局前置守卫的方法参数是一样的。用法也是差不多一样的 。现在在路由守卫里实现第一大点的案例:

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path:'/login',
    component: Login
  },
  //  在user这里面写
  {
    path:'/user',
    component:User,
    beforeEnter: (to, from, next) => {
      if(localStorage.getItem('token')){
        next();
      }else{
        next('/login');
      }
    }
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

效果:

在这里插入图片描述

3.组件内守卫:

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

名称 调用时期
beforeRouteEnter 进入组件之前执行
beforeRouteUpdate 组件复用时执行
beforeRouteLeave 离开组件之前执行

 它们也是函数,跟生命周期钩子函数有点像,跟data()、created()这些函数也是同一个级别的。它既然是写在组件里的,那说明它也是在该组件中有效的。比如在user.vue页面写:

beforeRouteEnter:

<template>
  <div>
    <h2>个人信息页面</h2>
    <div>账号:{{ username }}</div>
    <div>博客:北极光之夜。</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
    };
  },
  // 进入组件之前调用,beforeRouteEnter,这个比较少用
  beforeRouteEnter(to, from, next) {
    console.log(to, from, next);
    next();
  },
  methods: {},
  created() {},
};
</script>
<style scoped>
</style>

 这些守卫与全局前置守卫的方法参数也是是一样的。现在我们同样实现第一大点的小案例,在这之前需要注意的是不能获取组件实例的this,因为当守卫执行前,组件实例还没被创建:

  // 进入组件之前调用
  beforeRouteEnter(to, from, next) {
    if (to.path == "/user") {
      if (localStorage.getItem("token")) {
        next();
      } else {
        next("/login");
      }
    }
  },

一样的效果:

在这里插入图片描述
beforeRouteLeave:

 接下来使用 beforeRouteLeave,它类似于生命周期函数的beforeDestroy,表示离开该组件时执行的守卫函数。离开就是说我要去其它页面了,比如跳去home页面,注意如果没有调用next将离不开该组件。方法参数也是一样的:

<script>
export default {
  data() {
    return {
      username: "",
    };
  },
  // 离开该组件时执行的守卫函数
  beforeRouteLeave(to, from, next) {
    next();
  },
  methods: {},
  created() {},
};
</script>

它有什么使用场景呢?

 比如因为用户误触使得要离开这个页面时,可以通过beforeRouteLeave函数跳出一个提示框,提示是否真的离开该页面(提示离开可能不会保存当前页面用户的输入的信息等)。实现如下:

<template>
  <div>
    <h2>个人信息页面</h2>
    <div>账号:{{ username }}</div>
    <div>博客:北极光之夜。</div>
    <div>输入1:<input type="text" /></div>
    <div>输入2:<input type="text" /></div>
    <div>输入3:<input type="text" /></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: "",
    };
  },
  // 离开该组件时执行的守卫函数
  beforeRouteLeave(to, from, next) {
    const r = window.confirm("那你走?输入信息将不会保留");
    if (r) {
      next();
    } else {
      next(false);
    }
  },
  methods: {},
  created() {},
};
</script>
<style scoped>
</style>

window.confirm() 方法方法用于显示一个带有指定消息和确认及取消按钮的对话框。如果访问者点击"确定",此方法返回true,否则返回false。

运行效果:
在这里插入图片描述
beforeRouteUpdate

 在组件复用时执行beforeRouterUpdate,什么是复用呢?当连续进入同一个动态路由页面时会产生复用。
 什么是动态路由呢?如果某些路由规则的一部分是一样的,只有另一部分是动态变化的,那我们可以把这些动态变化的部分形成路由参数,这些参数就叫做动态路由匹配。动态路由请看这篇文章第五点https://auroras.blog.csdn.net/article/details/117635206,这里就不细说了。

首先,在项目新建一个 details.vue文件,做为详情页,然后配置动态路由规则:

  {
    path:'/details/:id',
    component: Details
  },

然后添加两个路由链接:

...略
      <router-link to="/details/1">详情1</router-link> |
      <router-link to="/details/2">详情2</router-link> |
...略      

 效果如下,此时连续进入就发生了组件的复用,它们显示的其实都是details.vue文件。因为是复用,vue为了节省性能将会导致该组件生命周期钩子函数并不会再重头开始创建执行,所以这时beforeRouteUpdate就很有用处了:

在这里插入图片描述
设置beforeRouteUpdate守卫函数,details.vue文件内容如下:

<template>
  <div>详情页</div>
</template>

<script>
export default {
  data() {
    return {};
  },
  // 守卫函数
  beforeRouteUpdate(to, from, next) {
    console.log("复用了~");
    next();
  },
  methods: {},
};
</script>
<style scoped>
</style>

look:

在这里插入图片描述
 现在,实现通过beforeRouteUpdate守卫函数,当组件发生复用时,依旧能获取组件参数(生命周期created函数是不行的,因为组件复用时它不会重新执行):

<template>
  <div>详情页 {{ id }}</div>
</template>

<script>
export default {
  data() {
    return {
      id: "",
    };
  },
  beforeRouteUpdate(to, from, next) {
    this.id = to.params.id;
    next();
  },
  methods: {},
};
</script>
<style scoped>
</style>

看效果:

在这里插入图片描述

三.总结:

持续更新,建议收藏。
下次见啦~

在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。