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) => {
// ...
}
}
]
})
beforeEnter
和 beforeEach
完全相同,如果都设置则在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
官方文档