需求:不涉及任何角色权限,基本实现目标,有token就可查看任何页面,否则就去登陆,来一步步实现
1. 创建你的路由页面,此处略了
2. 导航守卫拦截判断思路
// 创建路由
const router = createRouter({
history: createWebHistory(),
routes: [],
})
// 开始拦截,如果是登陆页,就放行,放行后进入下一个页面
router.beforeEach((to, _, next) => {
....
})
2.1 判断当前是不是登陆页面,如果是,那么点击登陆后,就放行,即调用next(),进入下一个页面
// 开始拦截,如果是登陆页,就放行,放行后进入下一个页面
router.beforeEach((to, _, next) => {
if (to.path === '/login') {
next()
}
// 这里这么写,只是为了演示能进入下一个页面,如果不写这个,
// 你点击跳转了,路由的to.path 已经变为其它的路径了,
// 你是看不到下个页面的
next()
})
2.1.1 演示1,如果不写第二个next(),你会看到这个演示
可以看到 点击后,[to.path] 变成了/home
, 所以判断不再走 if 了,为了能看到后边的页面,你需要next()
2.1.2 演示2,加入第二个next(),你会看到这个演示
2.2 如果不是登录页,思路就是 判断有木有 登陆过,即有木有token,如果登陆过,就放行,即next(),可以查看任何页面,如果没有登陆过,就跳转到登录页
- 不需要登陆,就可以看到的页面就不说了,你创建个白名单数组判断下就可以了,直接放行,这里不做演示
登陆跳转
// 点击登陆... 代码省略
// 拿到token,存起来
localStorage.setItem('token', 'token')
// 接着跳转到下个路径
router.push('/home')
守卫的代码就是,判断不是登陆页的时候,如果有token,放行,没有的话,跳转回登陆页
router.beforeEach((to, _, next) => {
// 获取token
const token = localStorage.getItem('token')
if (to.path === '/login') {
next()
} else {
// 判断有木有token
token && next()
next('/login')
}
})
2.2.1 演示1- 有token, 页面随便进,如果清了token, 刷新页面,就跳转回 登录页
这里有个不好的体验,登陆成功了,还可以回退回去,当然你可以 通过 跳转时用replace 方法解决,虽然解决了,但是,想要的效果应该是:你回退到了登录页,如果登陆过了,就直接回到上个页面,而不是通过不把路由存入到路由栈的思路
2.2.2 演示2- 登陆成功了,用户还可以通过浏览器的回退按钮,返回到登陆页
2.3 解决上述问题
- 跳转还是通过 push 方法去跳转
只需要加个判断,即你不让它跳就行了, 即 next(false),也就是说,如果有token,就调用 next(false)
router.beforeEach((to, _, next) => {
// 获取token
const token = localStorage.getItem('token')
if (to.path === '/login') {
token && next(false)
next()
} else {
// 判断有木有token
token && next()
next('/login')
}
})
2.3.1 演示登陆过了不能再跳转到 登陆页
- 这里退出的回调里,一定要清除token , 否则你跳转不回到登录页的,因为判读了有token, 就 next(false)了
2.3.2 虽然解决了问题,但是新的bug又来了,如果你改变地址栏为login, 你会发现是空白,这是因为next(false),拦截了渲染
2.3.3 解决以上这个bug, 强制跳转回一个固定路径,确切的说,自己输入了地址栏路径,等于是强制刷新了,所以路径肯定是 ‘/’ [根据你自己定义路由的规则判断哦]
router.beforeEach((to, from, next) => {
// 获取token
const token = localStorage.getItem('token')
if (to.path === '/login') {
token && next(from.fullPath || '/')
next()
} else {
// 判断有木有token
token && next()
next('/login')
}
})