如何解決vuex頁面刷新數據丟失問題?


1、問題描述:

一般在登錄成功的時候需要把用戶信息,菜單信息放置vuex中,作為全局的共享數據。但是在頁面刷新的時候vuex里的數據會重新初始化,導致數據丟失。因為vuex里的數據是保存在運行內存中的,當頁面刷新時,頁面會重新加載vue實例,vuex里面的數據就會被重新賦值。

2、解決思路:

辦法一:將vuex中的數據直接保存到瀏覽器緩存中(sessionStorage、localStorage、cookie)

辦法二:在頁面刷新的時候再次請求遠程數據,使之動態更新vuex數據

辦法三:在父頁面向后台請求遠程數據,並且在頁面刷新前將vuex的數據先保存至sessionStorage(以防請求數據量過大頁面加載時拿不到返回的數據)

分析:

辦法一的缺點是不安全,不適用大數據量的存儲;

辦法二適用於少量的數據,並且不會出現網絡延遲;

辦法三是要講的重點,辦法二和辦法一一起使用。

3、解決過程:@1

3.1、選擇合適的瀏覽器存儲

localStorage -- 是永久存儲在本地,除非你主動去刪除;

sessionStorage -- 是存儲到當前頁面關閉為止,和其他tab頁沒關聯;

cookie -- 則根據你設置的有效時間來存儲,但缺點是不能儲存大數據且不易讀取,會和后台進行交互。

本方法選擇的是sessionStorage,選擇的原因是由於vue是單頁面應用,操作都是在一個頁面跳轉路由,另一個原因是sessionStorage可以保證打開頁面時sessionStorage的數據為空,而如果是localStorage則會讀取上一次打開頁面的數據。

3.2、解決方案

由於state里的數據是響應式,所以sessionStorage存儲也要跟隨變化,而且只能通過mutations來改變state中的值。

首先在用戶登錄成功之后,然后把用戶信息、菜單信息通過actions分發保存至vuex中。然后在菜單頁面計算vuex中state的菜單數據,將數據解析組裝成前端組件所需的格式,然后渲染組件,生成菜單樹。如果頁面沒有刷新,則一切正常。

登錄成功后將用戶和菜單數據同步至vuex

在菜單頁面監聽vuex中菜單數據

頁面刷新的解決方案:

頁面刷新的時候異步請求后台數據,然后動態更新vuex中的數據,其中會有一種情況就是,網絡延遲、數據量大的問題。此時還沒等vuex獲取到后台返回的數據,頁面就已經加載完成了,這樣就會造成數據丟失。所以該解決方案就是,監聽瀏覽器刷新前事件,在瀏覽器刷新之前就把vuex里的數據保存至sessionStorage中,刷新成功后如果異步請求的數據還沒返回則直接獲取sessionStorage里的數據,否則獲取vuex里的數據。(只有刷新后還沒取到后台數據,才會從sessionStorage里取。確保數據的安全性,就算獲取sessionStorage里的數據也是安全的,因為每次刷新都會重新賦值,不必擔心數據被篡改問題,其次就是對sessionStorage里的數據做了加密操作)

在父頁面向后台請求數據,並且監聽瀏覽器刷新前事件,將vuex數據保存至sessionStorage

在父頁面向后台請求數據,將返回的數據分發至vuex

3、解決過程:@2 vuex-persistedstate

原理:

將vuex的state存在localStorage或sessionStorage或cookie中一份

刷新頁面的一瞬間,vuex數據消失,vuex會去sessionStorage中拿回數據,變相的實現了數據刷新不丟失~

使用方法:

安裝:npm install vuex-persistedstate --save

在store下的index.js中,引入並配置

import createPersistedState from "vuex-persistedstate"

const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()]
})

此時可以選擇數據存儲的位置,可以是localStorage/sessionStorage/cookie,此處以存儲到sessionStorage為例,配置如下:

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage
  })]
})

存儲指定state:

vuex-persistedstate默認持久化所有state,指定需要持久化的state,配置如下:

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage,
      reducer(val) {
          return {
          // 只儲存state中的user
          user: val.user
        }
     }
  })]

此刻的val 對應store/modules文件夾下幾個js文件存儲的內容,也就是stor/index中import的幾個模塊,可以自己打印看看。希望哪一部分的數據持久存儲,將數據的名字在此配置就可以,目前我只想持久化存儲user模塊的數據。

注意:如果此刻想配置多個選項,將plugins寫成一個一維數組,不然會報錯。

import createPersistedState from "vuex-persistedstate"
import createLogger from 'vuex/dist/logger'
// 判斷環境 vuex提示生產環境中不使用
const debug = process.env.NODE_ENV !== 'production'
const createPersisted = createPersistedState({
  storage: window.sessionStorage
})
export default new Vuex.Store({
 // ...
  plugins: debug ? [createLogger(), createPersisted] : [createPersisted]
})

3、解決過程:@3 vuex-along

將state里的數據保存一份到本地存儲(localStorage、sessionStorage、cookie)

//App.vue

<script>
    export default{
        created() {
            //在頁面加載時讀取sessionStorage里的狀態信息
             if (sessionStorage.getItem("store") ) {
                this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem("store"))))
            }

            //在頁面刷新時將vuex里的信息保存到sessionStorage里
            window.addEventListener("beforeunload",()=>{
                sessionStorage.setItem("store",JSON.stringify(this.$store.state))
            })
        }
    }
</script>

2.使用第三方插件如vuex-along(本質上還是利用session等緩存到本地)

import Vue from 'vue'
import Vuex from 'vuex'
import VueXAlong from 'vuex-along'
Vue.use(Vuex)
let productData = require('@/assets/api/list.json')

const moduleA = {
    state: {
        a1: 'a1',
        a2: 'a2',
    }
}
export default new Vuex.Store({
    state: {
        productList: [],//列表數據
        cartList: [],//購物車數據
    },
    mutations: {
        //產品列表
        setProductList(state, data){
            state.productList = data
        },
        //加入購物車
        setCartList(state, id){
            let  cartIndex = state.cartList.findIndex(item => item.id === id)
            if(cartIndex < 0){
                state.cartList.push({id, count: 1})
            }else{
                state.cartList[cartIndex].count++
            }
        },
        //刪除購物車商品
        deleteCartList(state, id){
            let  cartIndex = state.cartList.findIndex(item => item.id === id)
            state.cartList.splice(cartIndex, 1)
        },
        //編輯購物車商品數量
        editCartList(state, data){
            let cartIndex = state.cartList.findIndex(item => item.id === data.id)
            state.cartList[cartIndex].count = data.count
        },
        clearCart(state){
            state.cartList = []
        },
    },
    actions: {
        getProductList(context){
            //模擬ajax請求,將返回的信息直接存儲在store
            setTimeout(()=>{
                context.commit('setProductList', productData)
            }, 2000)
        },
        buy(context){
            //模擬ajax請求通過返回promise對象將結果返回給操作提交的地方
            return new Promise((resolve, reject) => {
                setTimeout(()=>{
                    context.commit('clearCart')
                    resolve({msg:'下單成功', code: 200})
                    //reject({message: '提交失敗', code: 300})
                }, 1000)
            })
        }
    },
    modules: {
        ma: moduleA
    },
    //緩存state的數據到storage
    plugins: [VueXAlong()],
    //全量的參數配置(sessionStorage 數據恢復優先級高於 localStorage)
    /* plugins: [VueXAlong({
        // 設置保存的集合名字,避免同站點下的多項目數據沖突
        name: 'my-app-VueXAlong',
        //過濾ma的數據將其他的數據存入localStorage
        local: {
            list: ['ma'],//需要監聽的屬性名或者模塊名
            isFilter: true,//是否過濾而非保存
        },
        //保存ma的a1數據到sessionStorage
        session: {
            list: ['ma.a1'],
            isFilter: false,
        },
        //僅使用sessionStorage保存
        //justSession: true,
    })] */
})


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM