目录
🔽 概述
1. 全局守卫——全局钩子函数
1.1 全局前置守卫——beforeEach
1.2 全局后置路由守卫
1.3 整合
2. 路由独享的守卫——路由独享的钩子函数
3.组件内的守卫——组件内的钩子函数
🔽 参考资料
Vue-Router导航(路由)守卫就是路由跳转前、中、后过程中的一些钩子函数,本文详细的介绍了Vue中路由守卫的具体使用——vue-router钩子函数实现路由守卫,具有一定的参考价值,对vue感兴趣的同学可以参考一下。
🔽 概述
何为路由守卫?路由守卫有点类似于ajax的请求拦截器,就是请求发送之前先给你拦截住做一些事情之后再去发送请求,同样这里的路由守卫意思差不多;简单理解为就是你在进路由之前,首先把你拦住,对你进行检查;这是不是有点中学门口的保安?进来之前拦住,有学生证就进,没有学生证就不让进;当然,路由守卫不仅仅只是在你进入之前拦住你,还有其他的钩子函数进行其他操作。
闲话:有的时候,需要通过路由来进行一些操作,比如,最常见的登录权限验证,当用户满足条件时,才让其进入导航,否则就取消跳转,并跳到登录页面让其登录。 为此有很多种方法可以植入路由的导航过程:全局的,单个路由独享的,或者组件级的。
路由守卫的作用:对路由进行权限控制
路由守卫的分类:全局守卫、独享守卫、组件内守卫
vue-router一共给我们提供了三大类钩子函数来实现路由守卫:
1、全局钩子函数(beforeEach、afterEach) ——全局路由钩子
2、路由独享的钩子函数(beforeEnter) ——路由独享守卫
3、组件内钩子函数(beforeRouterEnter、beforeRouterUpdate、beforeRouterLeave)——组件内的守卫
首先我们先来看一下全局钩子函数:
1. 全局守卫——全局钩子函数
1.1 全局前置守卫——beforeEach
顾名思义,前置守卫主要是在你进行路由跳转之前根据你的状态去 进行一系列操作(全局前置是为在路由初始化以及跳转之前都会触发)
你可以使用router.beforeEach注册一个全局前置守卫(Each:每个,即在任意一个路由跳转的时候都会触发)
每个守卫方法接收三个参数:
to:Route:即将进入目标的路由对象
from:Route:当前导航正要离开的路由对象
next:function:一定要调用该方法来resolve这个钩子。执行效果依赖next方法的调用参数
(1). next():进行管道中的下一个钩子(to),即进入该路由。如果钩子执行完了,则导航状态就是confirmed(确认的)
(2). next(false):中断当前的导航,取消进入路由。如果浏览器的URL改变了(可能用户手动或者浏览器按后退按钮),那么地址会重置到from路由对应的地址。
(3). next('/")或者next( { path: '/' } ):跳转到一个新的地址。当前的导航被中断,然后进行下一个新的导航。你可以想next传递任意对象,且允许设置诸如replace:true、name:'home‘ 之类的选项以及任何用下router-link的 to prop或者router.push中的选项
确保next函数在任何给定的导航守卫中被严格调用一次,它可以出现多余一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或者错误。
1.1.1 使用
可以打印出from、to、next看他们究竟会保存那些信息
举例
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import About from "../views/About.vue";
import News from "../views/News.vue";
import Message from "../views/Message.vue";
Vue.use(VueRouter);
const routes = [
{
path: "/home",
name: "Home",
component: Home,
children: [
{
path: "message", //此处不要写成:/message
component: Message,
},
],
},
{
path: "/about",
name: "aboutName",
component: About,
children: [
{
//通过children配置子级路由
path: "news", //此处不要写成:/news
component: News,
},
],
},
];
const router = new VueRouter({
routes,
});
//全局前置路由守卫---初始化的时候被调用、每次路由切换的时候被调用
router.beforeEach((to, from, next) => {
console.log(to); //这里是一个简单的例子 //即判断用户是否进入了需要鉴权的路由下(这里举例为news和message)
if (to.path == "/home/message" || to.path === "/about/news") {
//如果进入了,那就判断本地是否缓存了信息(这里模拟登录的token)
if (localStorage.getItem("name") === "kaodigua") {
next();
}
} else {
//如果不是,则直接放行即可
next();
}
});
export default router;
上面这个例子有个不足之处是,当需要鉴权的路由很多的时候,那你需要一个一个的去判断?那大可不必,因此这里引入路由的另一属性,即meta,可以在每个路由中进行配置,一般用来标识具有标识性的属性,可以用来统一判断,具体如下:
Vue.use(VueRouter);
// 路由字典
const routes = [
{
path: "/home",
name: "Home",
children: [
// 通过children配置子级路由
{
path: "message", //此处不要写成: /news
component: MessageChannel,
meta: {
isAuth: true, //用于判断是否需要鉴权
},
},
],
},
{
path: "/about",
name: "/aboutName",
component: About,
children: [
// 通过children配置子级路由
{
path: "news", // 此处不要写成:/news
component: News,
meta: {
isAuth: false, // 表示不需要鉴权
},
},
],
},
];
// 路由器对象
const router = new VueRouter({ routes });
//使用meta
router.beforeEach((to, from, next) => {
console.log(to);
if (to.meta.isAuth) { //判断是否需要鉴权
//如果进入了,那就判断本地是否缓存了信息(这里模拟登录的token)
if (localStorage.getItem("name") === "kaodigua") {
next();
}
} else {
// 如果不是,直接放行即可
next();
}
});
关于全局前置守卫——beforeEach
beforeEach一共接收三个参数,分别是to、from、next;to:即将进入的路由对象;from:正要离开的路由对象;next:路由的控制参数;
next一共有四种调用方式:
👉 next():一切正常调用这个方法进入下一个钩子;
👉 next(false):取消路由导航,这时的url显示的是正要离开的路由地址;
👉 next('/login'):当前路由被终止,进入一个新的路由导航(路由地址可以自由指定)
👉 next(error):路由导航终止并且错误会被传递到router.onError()注册过的回调中;
我们一般是用全局钩子来控制权限,像什么进页面没有登录就跳登录页,需要用户达到什么级别才能访问当前页面都是属于页面权限控制,都是可以通过beforeEach钩子函数来实现:
main.js(全局钩子函数我们一般是在main.js中进行书写):
// 进入路由前方法勾子 router.beforeEach((to, from, next) => { console.log(to, '前置第一个参数') console.log(from, '前置第二个参数') console.log(next, '前置第三个参数') /* to 目标路由 from 源路由 next 跳转到下一个路由 */ //这里暂时用local、storange来简单模拟验证权限 if (window.localstorange.getItem("token")) { // 如果存在,则直接跳转到对应路由 next(); } else { // 如果不存在,则跳转到登录页 next('/login'); } });
1.2 全局后置路由守卫
//全局后置路由守卫---初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to, from) => {
if (to.meta.title) {
document.title = to.meta.title || '路由跳转举例'//修改网页的title
}else{
document.title = 'vue_test'
}
})
关于全局后置守卫——afterEach
AfterEach和beforeEach一样都是属于全局守卫钩子,都是在main.js中进行调用;其中AfterEach比beforeEach少一个next参数;
to:即将进入的路由对象;
from:正要离开的路由对象;
afterEach()我们一般用来重置页面滚动条位置:假如我们有一个页面很长,滚动后其中的某个位置后跳转,这时新的页面的滚动条位置就会在上一个页面停留的位置;这个时候我们就可以利用afterEach进行重置://全局路由改变后的钩子 router.afterEach((to, from) => { //将滚动条恢复到最顶端 window.scrollTo(0, 0); })
1.3 整合
全局守卫
// 全局前置守卫---初始化时执行、每次路由切换前执行
router.beforeEach((to, from, next) => {
console.log('beforeEach',to,from);
if (to.meta.isAuth) {//判断当前路由是否需要进行权限控制
//如果进入了,那就判断本地是否缓存了信息(这里模拟登录的token)
if (localStorage.getItem("school") === "atguigu") {// 权限控制的具体规则
next(); // 放行
}else{
alert('您暂无权限查看')
// next({name:'guangyu'})
}
} else {
next(); // 放行
}
});
//全局后置守卫---初始化时执行、每次路由切换后执行
router.afterEach((to, from) => {
console.log('afterEach',to,from);
if (to.meta.title) {
document.title = to.meta.title //修改网页的title
}else{
document.title = 'vue_test'
}
})
2. 路由独享的守卫——路由独享的钩子函数
你可以在路由配置直接定义beforeEnter守卫,这些参数与全局前置守卫的方法参数是一样的
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
关于路由独享守卫——beforeEneter
路由独享顾名思义就是指定的路由才有这些钩子函数,通常这类路由独享的钩子函数我们是在路由配置文件中进行配置,只能设置改变前的钩子,不能设置改变后的钩子const router = new VueRouter({ routes }); const routes = [ { path: "/page1", component: page1, children: [ { path: "phone", component: phone, }, { path: "computer", component: computer, }, ], //路由独享的钩子函数 beforeEnter: (to, from, next) => { console.log(to); console.log(from); next(false); }, }, ];
上述代码理解为只有进入/page1才会触发beforeEnter这个钩子,如果进入其他页面,是不触发的;
3.组件内的守卫——组件内的钩子函数
最后,你可以在路由组件内直接定义一下路由导航守卫:
- beforeRouterEnter
- beforeRouterUpdate
- beforeRouterLeave
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`
},
};
关于组件内的守卫——beforeRouterEnter、beforeRouterUpdate、beforeRouterLeave
👉 beforeRouteEnter(to,from,next)在路由进入前调用,因为此时的vue实例还没有创建,所以beforeEnter是唯一一个不能使用this的钩子函数;
to:即将要进入的路由对象;
from:正要离开的路由对象;
next:路由控制参数
👉 beforeRouteUpdate(to,from,next)在路由发生修改的时候进行调用,比如我们上一篇文章讲到的动态路由传参,这种情况我们的beforeRouteUpdate也是会被调用的;
to:即将要进入的路由对象;
from:正要离开的路由对象;
next:路由控制参数;
👉 beforeRouteLeave(to,from,next)在路由离开该组件时调用;
to:即将要进入的路由对象;
from:正要离开的路由对象;
next:路由控制参数
❗ 注意:beforeRouteEnter因为触发的时候vue实例还没有创建,所以这个钩子函数中不能使用this,而beforeRouteUpdate和beforeRouteLeave都是可以访问到实例的,因为当这两个函数触发的时候实例都已经被创建了;
当调用组件内的钩子函数的时候,我们通常是在组件内部进行调用,举个例子: <template> <div> <h1 id="h1">主页</h1> <p> <router-link to="/page1/phone">手机</router-link> <router-link to="/page1/computer">电脑</router-link> </p> <router-view></router-view> </div> </template> <script> export default { //路由进入前调用 beforeRouteEnter(to, from, next) { window.document.title = "欢迎"; next(); }, //路由修改时调用 beforeRouteUpdate(to, from, next) {}, //路由离开时调用 beforeRouteLeave(to, from, next) {}, data() { return { msg: "我是page1组件", }; }, }; </script>
🔽 参考资料
- 详解vue-router导航守卫
- vue的路由守卫和keep-alive后生命周期详解
- 快速理解Vue路由导航守卫