vue中实现动态菜单功能数据存储问题
(刚接触前端不久,有问题请积极指正)
在vue.js中通过router.beforeEach(async(to, from, next) => {})方法来拦截路由实现动态菜单功能,这时候就需要一个存储介质来实现用户角色或者用户路由数据的存储.
最开始我针对动态菜单功能的解决方案是使用localStroage来存储用户对应的路由数组信息,但是在实际应用中出现了登录不同用户路由数据更新异常的bug.
在项目中中login的登录方法中调用获取路由数组的方法,登录方法的返回值中返回用户角色id,将用户角色id传入获取路由数组的方法中,获取用户路由数组,然后存储到localStroage中.
this.$store.dispatch('user/login', this.loginForm).then(response => {
if(response.errorCode=='0'){
this.$store.dispatch('user/getMenu', {roleId:response.errorMsg}).then(response => {
//使用localStroage存储数据是永久的,会导致不同角色下路由不更新
//window.localStorage.setItem("routerMenu",JSON.stringify(response))
//在这里使用sessionStroage存储数据
sessionStorage.setItem("role",JSON.stringify(response))
})
//登录成功跳转first首页
// this.$router.push({
// path: this.redirect || '/first'
// })
this.$router.push({path:'/first'})
this.loading = false
}else{
this.$message.error('用户名密码错误!')
this.loading=false
}
})
当登录不同的用户时,由于localStroage中存储的数据时永久的,导致不同用户角色下路由不刷新.
因为刚开始对vue中的vuex不是很熟悉,又想到使vuex的state来存储用户路由数组信息,但是出现了F5刷新页面路由数据丢失的问题,原来vuex在F5页面刷新的时候,会进行初始化,导致存储的全局共享变量丢失的问题.
//这是store中的user.js中定义的变量
const getDefaultState = () => {
return {
token: getToken(),
name: '',
avatar: '',
role:''
}
}
const mutations = {
RESET_STATE: (state) => {
Object.assign(state, getDefaultState())
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLE: (state,role)=>{
state.role = role
}
}
const actions = {
login({ commit }, loginForm) {
return new Promise((resolve, reject) => {
login(loginForm).then(response => {
if(response.errorCode=='0'){
setToken('token-xxxxx')
//使用vuex存储数据,页面刷新数据会消失.
//将数据存储到vuex中
//commit('SET_ROLE', response.errorMsg)
}
resolve(response)
}).catch(error => {
reject(error)
})
})
},
}
后来想到使用sessionStroage来存储用户的路由信息,因为sessionStroage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过它存储的数据也就被清空了。这个特性可以用来保证页面刷新数据不丢失的问题,同时解决了localStroage永久存储数据的问题.
最终的解决代码:
if (hasGetUserInfo) {
next()
} else {
try {
await store.dispatch('user/getInfo')
//vuex存储的数据在页面刷新时会消失,这里使用sessionStroage存储角色数据
getRouter=JSON.parse(sessionStorage.getItem("role"))
let getRouterMenu=filterAsyncRouter(getRouter,false,true)
//404页面一定要在最后添加,否则会导致所有页面被拦截至404页面
getRouterMenu.push({ path: '*', redirect: '/404', hidden: true })
//在addRoutes之前要将路由对象push到路由数组中
for(let item of getRouterMenu){
router.options.routes.push(item)
}
router.addRoutes(getRouterMenu) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
//next()
} catch (error) {
//删除token
await store.dispatch('user/resetToken')
Message.error('Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
注释:(这里引用度娘的数据)
localStroage和sessionStroage的区别:
localStorage和sessionStorage一样都是用来存储客户端临时信息的对象。
他们均只能存储字符串类型的对象(虽然规范中可以存储其他原生类型的对象,但是目前为止没有浏览器对其进行实现)。
localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。
sessionStorage生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过sessionStorage存储的数据也就被清空了。
不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标 签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。