一、token + 全局前置路由守卫
项目中:登录成功以后,服务器会返回token【存储于vuex当中】,如果想获取用户信息 还需要再发请求【用户信息】,携带token给服务器。
问题:为什么刷新页面,用户信息就消失?为什么去别的模块【非home模块】获取用户信息失败?
Vuex存储数据并非是持久化的,所以用户刷新页面,token也就消失了,且没有携带给服务器,所以用户信息也就消失了。
因为你去别的模块根本没有发请求获取用户信息,没办法展示用户信息了
解决:
因为vuex存储数据是非持久化的,所以我们在用户登陆,服务器派发token是,用本地存储将token存储起来
import { setToken, getToken, removeToken } from '@/util/token';
//用户登陆
async userLogin({ commit }, data) {
let result = await reqUserLogin(data);
// console.log(result);
// token是服务器上传下来的, 是唯一标识
if (result.code === 200) {
commit('USERLOGIN', result.data.token);
//持久化存储token
setToken(result.data.token);
//setToken是引入一个专门封装token操作的JS模块
return 'ok'
} else {
return Promise.reject(new Error('Fail'));
}
},
const state = {
token: getToken(), //vuex中数据存储短暂(一刷新页面就没),所以采用本地存储
}
//当退出登陆时,也需要将token清除
const mutations = {
//清除本地数据
CLEARINFO(state) {
//将仓库中token清空
state.token = "";
//本地存储数据清空
removeToken();
}
}
当我们想去别的模块时,即路径发生变化,而全局前置路由守卫正好可以监测到这一变化,所以我们可以将获取用户信息,携带token的请求放置在其中,这样去别的模块,用户信息就不会消失了。(其中逻辑判断最为复杂、重要)
router.beforeEach(async(to, from, next) => {
/*
to:可以获取到你要跳转到哪个路由的信息
from:可以获取到你从哪个路由来的信息
next:放行函数
*/
// 如果有stroe.state.user.token,则说明用户已经登陆
if (stroe.state.user.token) {
// 如果用户登陆还想去登陆组件,不准且跳转到首页
if (to.path == '/login' || to.path == '/register') {
next('/');
} else {
// 去的不是登陆组件,而是其他组件
// 如果有stroe.state.user.userInfo.name,则说明用户信息已经存在,则放行
if (stroe.state.user.userInfo.name) {
next();
} else {
// 没有用户信息,则派发action让仓库存储用户信息后在跳转
try {
await stroe.dispatch('userInfo');
next()
} catch (error) {
// token失效了,获取不到用户信息,则从新获取
// 删除原来的,再重新登陆
await stroe.dispatch('userLogout');
next('/login');
}
}
}
} else {
//未登录:不能去到交易相关、支付相关、个人中心组件
//如果想去直接跳转到登陆界面,登陆后直接跳转
if (to.path == '/center/myorder' || to.path == '/pay' || to.path == '/shopcart' || to.path == '/paysuccess') {
next('/login?redirect=' + to.path);
} else {
next()
}
}
})
二、其他路由守卫
路由独享守卫:
//beforeEnter 守卫 只在进入路由时触发,不会在 params、query 或 hash 改变时触发
beforeEnter: (to, from, next) => {
if (from.path == '/trade') {
next()
} else {
next(false);
/*
next(false)取消当前的导航。
如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮)
那么 URL 地址会重置到 from 路由对应的地址
*/
}
},
组件内守卫(不常用):
beforeRouteEnter(to, from[,next]) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from[,next]) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from[,next]) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},