导航守卫----不登录就不给看!
相信大家也知道大部分的网页版引应用,“不登录就不给看!”,于是,我也给自己的项目添加了这个小细节。如何实现呢?当然是使用路由守卫啦。
正如其名,导航守卫就是通过跳转或取消的方式守卫导航。这里使用的vue-router提供的导航守卫。
没有守卫时
以vue3为例,使用脚手架搭建项目, 命令代码:npm init vue@latest。选择所需的插件,其中因为方便举例,这里都是会话缓存(用到时再解释),没有使用其他状态管理器,如vuex或者pinia...。需要安装vue-router,接下来的改变都是以最初始的页面为基础(接下来就同意称之为基础页面),进行添加路由守卫。
登录页面和首页页面:
//登录页面 views/LoginView.vue
<template>
<div class="login">
<h1>This is an login page</h1>
用户名:<input type="text" v-model="formState.username" />
<div class="btn" style="margin-top: 20px;">
<button @click="onFinish">登录</button>
</div>
</div>
</template>
//登录页面 js代码
<script>
//...引入defineComponent
export default defineComponent({
setup() {
const formState = reactive({
username: ''
})
const onFinish = async () => {
console.log('success', formState.username)
}
return {
formState,
onFinish
}
}
})
</script>
//首页页面 /views/HomeView.vue
<template>
<div class="home">
<h1>This is an home page</h1>
</div>
</template>
配置路由:
//路由配置 router/index.js
//...一些引入
const router = createRouter({
history: createWebHistory(
import.meta.env.BASE_URL),
routes: [{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: () => import('../views/HomeView.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/LoginView.vue')
}
]
})
export default router
最开始其实就是准备两个vue3脚手架搭建好两个页面,登录页面和首页页面,然后配置路由即可。 看看效果:
一、全局路由守卫
知识基础
-
全局前置守卫
可以使用router.beforeEach()注册一个全局前置守卫。当一个导航触发时,全局前置守卫按照创建顺序调用。此时,导航在所有守卫resolve完之前一直处于等待之中。
const router = createRouter({ ... }) router.beforeEach((to, from, next) => {//路由跳转前 if(...){//不存在token //回到登录页面 return {name:'login'} }else{ next()//只有调用next(),才能成功跳转;否则不成功 } })
参数:
(1)to:即将要进入的目标
(2)from:当前导航正要离开的路由
(3)next:去到下一个导航守卫调用。确保next在任何给定的导航守卫中都被严格调用一次。
-
全局解析守卫
使用router.beforeResolve()注册一个全局解析守卫。与全局前置守卫类似,在每次导航时触发,但是在确保导航被触发之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用。
const router = createRouter({ ... }) router.beforeResolve((to, from, next) => { //成功调到目的地页面之前 console.log(to, from); next(); })
-
全局后置钩子
使用router.afterEach()注册一个全局后置钩子,与守卫不同,它不接受next第三个参数,函数也不会改变导航本身。
const router = createRouter({ ... }) router.afterEach((to, from) => { console.log(to, from); if (!sessionStorage.getItem('age') && to.name !== 'LoginView') { router.push('LoginView');//以这种方式强制回到登录页面 } })
路由守卫
浏览器缓存:
-
本地缓存
LocalStorage.setItem(key,value) 设置本地缓存
LocalStorage.setItem(key) 获取本地缓存
永久性缓存,可手动清除缓存。
-
会话缓存
SessionStorage.setItem(key,value) 设置会话缓存
SessionStorage.setItem(key) 获取会话缓存
暂时性缓存,结束会话即缓存清除,可手动清除缓存。
在没有做路由守卫页面的基础上,在登录页面增加做缓存的功能:
//...登录页面的html代码
<script>
//...一些引入
//...其他代码(标准格式)
const onFinish = async () => {
console.log('success', formState.username)
//这里是新添加的做缓存功能代码
// 假设拿到后端数据,接下来做缓存,比如在xxxx天后登录失效
if (formState.username) {
//设置会话缓存
sessionStorage.setItem('username', formState.username)
//路由跳转
router.push('/home')
} else {
alert('用户名为空')
}
}
//...其他代码(标准格式)
</script>
接下来,在全局设置路由守卫,即在搭建的基础之上,添加路由守卫代码。
//全局路由守卫:main.js
//...一些引入
// 全局路由守卫----全局前置守卫
router.beforeEach((to, from, next) => { //路由跳转前
// console.log(to, from);
// 判断是否在缓存,在的话允许访问首页;否则,跳回登录页面
if (!sessionStorage.getItem('username') && to.name !== 'login') {//不存在
return next({//去登录页面
name: 'login'
})
} else {//存在,允许去你想要的页面
next(); //只有调用next(),才能成功跳转;否则不成功
}
})
//...一些use
来看看守卫的结果吧:
二、路由独享守卫
知识基础
-
路由独享的守卫
const routes = [ { path: '/users/:id', component: UserDetails, beforeEnter: (to, from,next) => { // return false if(...){//未登录或者为授权 //强制回到登录页面,或者retun false拒绝导航 next({ name: 'login' }) }else{ next()//去到下一个导航守卫 } }, }, ]
路由独享的守卫只有在进入路由时才会触发,不会再路径改变参数(params)、query、hash等时触发。它只是只有在从一个不同的路由导航时,才会被触发。也可以将函数数组传给beforeEnter,在为不同的路由重用守卫时大有作为。
路由守卫
在基础页面上,在你想要守卫的路由组件下面增加路由守卫,如下
//路由配置 router/index.js
{
path: '/home',
name: 'home',
component: () => import('../views/HomeView.vue'),
//这里是新添加的路由守卫代码
// 路由守卫---
beforeEnter: (to, from, next) => {
if (!sessionStorage.getItem('username')) {
alert('请先登录');
next({
name: 'login'
})
} else {
next();
}
}
}
看看路由守卫结果:
三、组件内的守卫
知识基础
-
beforeRouteEnter
beforeRouteEnter()一般在渲染该组件的对应路由被验证前调用,但是不能获取组件实例的this,因为当前守卫执行时,组件实例还没被创建。
beforeRouteEnter(to, from, next) { // 进入当前组件 if (...) {//没有满足要求 return next({ name: 'login' }) } else { next(); //只有调用next(),才能成功跳转;否则不成功 } }
-
beforeRouteUpdate
beforeRouteUpdate()一般在当前路由改变,但是该组件被复用时调用,如同一个路径下携带参数不一样的情况下。因为路径相同会渲染相同的组件,因此组件实例会被复用,而钩子函数就会在这个时候会被调用。在这种情况下,组件已经挂载就绪,导航守卫可以访问组件实例的this。正是因为可以使用this,所以不支持next的调用。
beforeRouteUpdate(to, from) { console.log(this) this.name=to.params.name },
-
beforeRouteLeave
beforeRouteLeave(),离开守卫,通常用来预防用户还在未保存修改之前就突然去其他页面。顾名思义,一般在导航离开渲染组件的对应路由时调用。也可以访问组件实例的this,同时也没有next可以调用。
beforeRouteLeave(to, from) { console.log(this) return false//可取消守卫 }
路由守卫
组件内的守卫,那么只需要在页面进行路由守卫即可,在基础1页面上,在需要守卫的页面上添加路由守卫:
//home页面js代码
<script>
import {
defineComponent
} from "vue"
export default defineComponent({
beforeRouteEnter(to, from, next) {
// 进入当前组件
if (!sessionStorage.getItem('username') && to.name !== 'login') {
return next({
name: 'login'
})
} else {
console.log(1233333333333);
next(); //只有调用next(),才能成功跳转;否则不成功
}
}
})
</script>
看看守卫结果:
总结
全局路由守卫三个钩子函数,全局前置守卫(beforeEach),全局解析守卫(beforeResolve)和全局后置守卫(afterEach),其中全局后置守卫(afterEach)没有next可以调用,即不能传递第三个回调参数next;
路由独享的守卫(beforeEnter),只有在进入路由时才会触发;
组件内的路由守卫,也有三个api可以使用,分别是beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave,其中因为beforeRouteEnter调用的时候,组件实例还没有被创建,所以只有beforeRouteEnter可以传递第三个回调参数next,因为beforeRouteUpdate,beforeRouteLeave被调用的时候,组件实例已经被挂载就绪,可以访问组件实例的this,所以没必要next的存在了。
转载自:https://juejin.cn/post/7160205116312649736