1、问题描述:

一般在登录成功的时候需要把用户信息,菜单信息放置vuex中,作为全局的共享数据。但是在页面刷新的时候vuex里的数据会重新初始化,导致数据丢失。因为vuex里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,vuex里面的数据就会被重新赋值。

2、解决思路:

办法一:在页面刷新的前将vuex中的数据直接保存到浏览器缓存中(sessionStorage)
办法二:在页面刷新路由跳转前再次请求远程数据,使之动态更新vuex数据(该请求必须是在路由跳转前,以防页面已经加载完成了,还没有获取到后台返回的数据)
办法三:在页面刷新路由跳转前再次请求远程数据,并且在页面刷新前将vuex的数据先保存至sessionStorage(以防请求数据量过大页面白屏时间过长)

分析:
办法一:缺点是不安全,不适用大数据量的存储;
办法二:适用于少量的数据,并且不会出现网络延迟,否则白屏时间会长;
办法三:办法一和办法二一起使用;

3、实现:

(1)、分析:

1、选择合适的浏览器存储 (同一个域名下,不同页面的localStorage是共享的,sessionStorage不共享 )

localStorage:是永久存储在本地,重新打开页面时会读取上一次打开的页面数据,不断触发localStorage.setItem()方法对性能不是特别友好,而且一直将数据同步到localStorage中似乎就没必要再用vuex做状态管理,直接用localStorage即可;

sessionStorage:是储存到关闭为止;

cookie:则根据你设置的有效时间来存储,但缺点是不能储存大数据且不易读取,会和后台进行交互。

本方法选择的是sessionStorage,选择的原因是由于vue是单页面应用,操作都是在一个页面跳转路由,另一个原因是sessionStorage可以保证打开页面时sessionStorage的数据为空,而如果是localStorage则会读取上一次打开页面的数据。

2、方案选择(由于state里的数据是响应式,所以sessionStorage存储也要跟随变化,而且只能通过mutations来改变state中的值。首先在用户登录成功之后,然后把用户信息,菜单信息通过actions分发保存至vuex中。)

页面刷新的时候异步请求后台数据,然后动态更新vuex中的数据,当网络延迟、数据量大的情况下,此时还没等vuex获取到后台返回的数据,如果让页面加载就会造成数据丢失,如果不加载就会造成白屏时间延长。所以该解决方案就是:监听浏览器刷新前事件,在浏览器刷新之前就把vuex里的数据保存至sessionStorage中,刷新成功后如果异步请求的数据还没返回则直接获取sessionStorage里的数据,否则获取vuex里的数据。(只有刷新后还没取到后台数据,才会从sessionStorage里取。确保数据的安全性,就算获取sessionStorage里的数据也是安全的,因为每次刷新都会重新赋值,不必担心数据被篡改问题,其次就是对sessionStorage里的数据做了加密操作)

(2)、方法:

办法一:

监听页面是否刷新,如果页面刷新了,将state对象存入到sessionStorage/localStorage中。页面打开之后,判断sessionStorage/localStorage中是否存在state对象,如果存在,则说明页面是被刷新过的,将sessionStorage/localStorage中存的数据取出来给vuex中的state赋值。如果不存在,说明是第一次打开,则取vuex中定义的state初始值。

beforeunload事件在页面刷新时进行触发,可以监听这个方法,让页面在刷新前存store到sessionStorage中。

具体做法是在App.vue的created()周期函数中下如下代码:

//1、全局监听,页面刷新的时候将store里state的值存到sessionStorage中,然后从sessionStorage中获取,
//再赋值给store。然后再把session里面存的删除即可,相当于中间件的作用。
//在页面加载时读取sessionStorage里的状态信息
//vuex 单向数据流,推荐的commit 改变state数据
if (sessionStorage.getItem("store")) {
    this.$store.replaceState(
        Object.assign({},this.$store.state,JSON.parse(sessionStorage.getItem("store")))
    );
    sessionStorage.removeItem("store")
 }

//2、在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload", () => {
   sessionStorage.setItem("store", JSON.stringify(this.$store.state));
});

办法二:

 页面的刷新会触发路由的beforeEach函数,拦截路由的跳转异步请求后台数据,等数据返回存入vuex,再跳转路由。

router.beforeEach((to, from, next) => {
    if (!getToken()) {
      location.href = location.origin
    } else if (to.name === 'login') { // 前往的是登录页
      next({ name: 'error-403' })
      NProgress.done()
    } else if (to.name && to.name.indexOf('error') !== -1) { // 判断是否是错误页面
      next()
    } else if ((!to.path || to.path === '/') && to.name !== 'home') { // 通过name跳转 路径没有权限时path为/ 跳转到404
      next({ name: 'error-404' })
    } else {
      checkUser(next, to, router)
    }
})
//js
import { removeToken } from '@/utils/cookies'
import { findHomePage } from '@/utils/common'
import store from '@/store'

export const checkUser = async (next, to, router) => {
  next = _getNewNext(next, to.name)
  if (!store.getters.userInfo.userId) {
    try {
      let { authPath } = await store.dispatch('user/setUserInfo')
      let rawAppRouter = await store.dispatch('user/setAuth', authPath)
      let error404Page = { path: '/*', name: 'error-404', meta: { title: '404-页面不存在' }, component: () => import(`@/views/errorPage/404`) }
      router.addRoutes([...rawAppRouter, error404Page])
      let foundHomePages = findHomePage(rawAppRouter)
      if (to.path === '/' && foundHomePages) {
        next({ ...foundHomePages, replace: true })
      } else {
        next({ ...to, replace: true })
      }
    } catch (e) {
      removeToken()
      location.href = location.origin
    }
  } else {
    next()
  }
}

 

//vuex
actions: {
    // 获取用户信息
    setUserInfo ({ commit, dispatch }) {
      return new Promise((resolve, reject) => {
        getUserInfo().then(res => {
          if (res.result === 1) {
            commit('SET_USER', res.data)
            dispatch('setSysMenu')
            getAuthMenu().then(authres => {
              if (authres.result === 1) {
                commit('SET_EXTRA_AUTH', authres.data.extraAuth)
                commit('SET_MAINTAIN_PATH', authres.data.maintainPath)
                resolve(authres.data)
              } else {
                reject(authres.msg)
              }
            }, (err) => {
              reject(err)
            })
          } else {
            reject(res.msg)
          }
        }, (err) => {
          reject(err)
        })
      })
    }
}

办法三:

Logo

前往低代码交流专区

更多推荐