【前言】当我们在做类似于登录页面的时候,从登录页跳转到首页需要对token做一个判断,如果我们的token存在的话那么我们就可以直接进行跳转,如没有token的话会自动跳转登录页。或者当我们在处理页面跳转时,对某一些条件进行一个判断,true走什么路径/false走什么路径。
补充路由的声明与写法详见:http://t.csdn.cn/YCsD7
一、路由守卫介绍
1.什么是路由导航守卫?
通俗来讲就是我们在路由跳转的时候执行的一个回调函数
守卫:类似于门卫,你做某件事之前会对你进行一个检查
2.为什么要有路由导航守卫?
在项目开发中,并不是每一个路由跳转都是明确的。 例如很多页面跳转需要登录判断,如果你有登录,则跳转到指定页面,没有登录则跳转到登录页面。
举例子:我想进小区(个人信息),门卫(导航守卫)会检查我有没有做核酸(是否登录),如果做了就让我进去(跳转个人信息)。没做就让我去核酸点(登录页面)做完核算才可以进去。
3.路由导航守卫有哪些?
前置守卫:跳转前执行
后置勾子:跳转后执行
二、路由守卫的使用
1.前置守卫
1. 所有的路由一旦被匹配到,在真正渲染解析之前,都会先经过全局前置守卫
2. 只有全局前置守卫放行,才能看到真正的页面
参数写法:
任何路由,被解析访问前,都会先执行这个回调
from 你从哪里来, 从哪来的路由信息对象
to 你往哪里去, 到哪去的路由信息对象
next() 是否放行,如果next()调用,就是放行 => 放你去想去的页面
next(路径) 拦截到某个路径页面
我们创建文件打印一下查看下:
router.beforeEach((to, from, next) => { console.log(to, 'to目的路由') console.log(from, 'from从哪里来') next() // 必须写next() })
控制台效果查看:
当我配置好路由时,点击跳转时控制台打印打印to\from,页面实现了跳转到了B页面并且我们的to与from当中都包含了我们去的路由信息。
一定要注意,在导航守卫中必须要调用next()否则你的路由无法跳转
此时我引入下前置守卫:在路由跳转的前先执行我们写的回调函数
我想实现的效果:如果我去B页面就放行,当我不去B页面的时候就都跳转到C页面去。
按照常规的逻辑书会是这样的:
router.beforeEach((to, from, next) => { // console.log(to, 'to目的路由') // console.log(from, 'from目的路由') console.log(to.path, ' --to ', from.path, ' --from') if (to.path === '/BPage') { console.log('前置守卫被触发') next() } else { console.log('不是去BPage与CPage的路由走这') next('/CPage') } })
逻辑上并没有什么问题:当我不去B页面的时候,守卫就帮我切换到C页面去。可当博主打开控制台查看的时候却出现了:
很奇怪,为什么重复跑路由呢?后在一群大佬一起分析找到了报错的原因:
我的判断没有写的完善,当我路由跳转时便又会触发一次路由守卫。因此会出现一直反复执行路由守卫,直到出现红字的报错:
RangeError: Maximum call stack size exceeded
当我尝试用翻译可得知,原来是我路由重复的跳执行直到将我的内存占满了。
因此我们需要做出下以下的改变:再判断的时候加一条去CPage就给与放行。这样重复跑的时候遇到了CPage就放行了让他去CPage
修改后源代码见下:
router.beforeEach((to, from, next) => { // console.log(to, 'to目的路由') // console.log(from, 'from目的路由') console.log(to.path, ' --to ', from.path, ' --from') if (to.path === '/BPage' || to.path === '/CPage') { console.log('前置守卫被触发') next() } else { console.log('不是去BPage与CPage的路由走这') next('/CPage') } })
这样就完美的实现了我们的需要:去BPage放行,不是BPage统一放行到CPage
最重要的是:
我们在路由进行跳转的前可以看到我们执行了我们写在前置守卫中的回调函数
2.后置守卫
实现当我们路由跳转之后实现我们回调函数
参数写法:
当我们的路由进行跳转之后我们将会执行一个回调函数
from 你从哪里来, 从哪来的路由信息对象
to 你往哪里去, 到哪去的路由信息对象
原理同前置守卫只是不需要写next()
// 后置守卫 router.afterEach((to, from) => { console.log(to, 'to') console.log(from, 'from') if (to.path === '/BPage') { console.log('后置守卫被触发') } else { console.log('不是去BPage走这里(后置)') } })
控制台效果查看:
可以看到当我们的路由跳转结束后会执行我们的回调函数
三、路由守卫对比拦截器区别
刚开始接触路由导航守卫你会发现和axios拦截器有点像,实际上它们是两个不同的东西。
1.相同点
(1)都是钩子函数(回调函数的一种,到某个时机了自动触发)
(2)都是起到拦截作用
2.不同点
(1)功能不同 :axios拦截器拦截网络请求, 导航守卫拦截路由跳转
(2)应用场景不同 :
axios拦截器一般用于发送token
导航守卫用于页面跳转权限管理(有的页面可以无条件跳转,例如登录注册页可以无条件跳转。有的页面需要满足条件才能跳转,例如购物车页面就需要用户登录才可以跳转)
四、学习小结
1.前置守卫
1. 所有的路由一旦被匹配到,在真正渲染解析之前,都会先经过全局前置守卫
2. 只有全局前置守卫放行,才能看到真正的页面,需要写next()
2.后置守卫
当路由实现跳转之后我们再走后置守卫执行我们的后置守卫
对比前置守卫不需要写next()
[上述所有的源代码以及相关路由源代码]
router/index.js
import Vue from 'vue' import VueRouter from 'vue-router' // import BPage from '@/views/BPage',用了下面的新写法就不需要写导入路径 // import APage from '@/views/APage' // import CPage from '@/views/CPage' /* 前置守卫 任何路由,被解析访问前,都会先执行这个回调 1. from 你从哪里来, 从哪来的路由信息对象 2. to 你往哪里去, 到哪去的路由信息对象 3. next() 是否放行,如果next()调用,就是放行 => 放你去想去的页面 next(路径) 拦截到某个路径页面 */ Vue.use(VueRouter) const routes = [ { path: '/APage', name: 'APage', component: () => import('@/views/APage') }, { path: '/BPage', name: 'BPage', component: () => import('@/views/BPage') }, { path: '/CPage', name: 'CPage', component: () => import('@/views/CPage') } ] const router = new VueRouter({ routes }) router.beforeEach((to, from, next) => { // console.log(to, 'to目的路由') // console.log(from, 'from目的路由') console.log(to.path, ' --to ', from.path, ' --from') if (to.path === '/BPage' || to.path === '/CPage') { console.log('前置守卫被触发') next() } else { console.log('不是去BPage与CPage的路由走这') next('/CPage') } }) // 后置守卫 router.afterEach((to, from) => { console.log(to, 'to') console.log(from, 'from') if (to.path === '/BPage') { console.log('后置守卫被触发') } else { console.log('不是去BPage走这里(后置)') } }) export default router
views/APage.vue
<template> <div>这是A页面 <br> <button @click="$router.push('/BPage')">点我去B页面</button> </div> </template> <script> export default { name: 'APage' } </script> <style> </style> views/BPage.vue <template> <div>这是B页面 <br> <button @click="$router.push('/APage')">点我去A页面</button> </div> </template> <script> export default { name: 'BPage' } </script> <style> </style>
App.vue
<template> <div> <!-- 路由出口,必须写否则没有路由 --> <router-view ></router-view> <!-- 路由导航了类似于A超链接 --> <router-link to="/APage">AAA</router-link> </div> </template> <script> export default { } </script> <style> </style>
views/CPage.vue
<template> <div>这是C页面 <br> <button @click="$router.push('/APage')">点我去A页面</button> </div> </template> <script> export default { name: 'CPage' } </script> <style> </style>