1. 程式人生 > >失敗獅計劃——在localStorage中儲存vuex狀態

失敗獅計劃——在localStorage中儲存vuex狀態

前言

最近碰到了這麼一個需求變動:在當前頁點選一個按鈕開啟一個新的頁籤(本來是在當前頁通過路由跳轉進入一個新的元件),對於傳統jq專案來說這個應該是不費吹灰之力可以實現的,但是對於vue專案來說就要好好斟酌一下了,當時我想到了3種方法來實現:

  1. 首先,最容易理解的就是構建一個簡單的多頁應用,即新建一個html入口,不過由於之前沒有這樣做過,對於要踩哪些坑沒有什麼把握,同時需要後臺進行相關的配置,而這個需求需要馬上上線,於是我決定先放棄這個待以後研究。
  2. 直接使用window.open開啟新的路由再從vuex種讀取之前儲存的狀態,這種方法直接開啟新的頁籤是無法獲取到上一個頁面儲存在vuex中的資訊的。(由於這個專案是多人同時開發而且有些思想不太統一,導致我接手的時候發現有好多路由跳轉之前都將一些資訊存到了vuex中,個人認為在pc端跨路由最好不要使用vuex,否則重新整理頁面就啥也沒了…)
  3. 既然前兩種都暫時行不通,我又想到了使用localStorage儲存vuex中的資訊,因為之前就面臨過重新整理頁面的尷尬,所以使用了sessionStorage來儲存當前登入使用者的資訊,而sessionStorage存在時效性,故而選擇了localStorage。(後來發現直接開啟新頁籤,之前頁籤的sessionstorage還是存在的)
    ###實現過程
    1.在開啟新頁籤之前將需要用的vuex狀態儲存到localStorage中去,由於這部分內容都在一個模組裡面,故可以直接將一個Module儲存到localStorage,儲存Module物件的時候需要轉為JSON字串(JSON.stringify()
    )。
  4. 讀取存入的vuex狀態,使用localStorage.getItem()讀取之後再用JSON.parse()即可拿到存入的物件。
  5. 那麼問題來了,如何將取出的state,action,mutation等以最小的代價放入寫好的元件中呢?我為了仿造vuex的引入甚至參考了一下他的原始碼(真是高大上,讀起來真切感覺到了境界的差距)。
  • 引入state
    我們一般在元件中引入的時候用到了擴充套件運算子,這一部分的原理我以前一直不懂,通過做這個需求也研究了一二。
    觀摩vuex的原始碼發現其mapstate函式返回的是一個物件,那麼執行以下程式碼我們可以發現擴充套件運算子(解構賦值)可以將值’插入’到原物件中
        let fn = ()=> {
            return{
                b: 1,
                c: 2
            }
        }
        let obj = {
            a: 0,
            ...fn()
        }
        console.log(obj);// {a: 0, b: 1, c: 2}

剩下的就是仿照vuex編寫自己用的mapstate輔助函式

const PVLISTSTR = localStorage.getItem('pvList');
const PVLIST = JSON.parse(PVLISTSTR);
const MAPSTATE = () => {
    let res = {};
    Object.keys(PVLIST.state).forEach((k, i) => {
        res[k] = function() {
            return PVLIST.state[k];
        };
    });
    return res;
};

之後在元件中常規引入,成功取到了!

  • 引入mutationaction
    就在我準備依葫蘆畫瓢準備搞定mutation和action的時候卻漠然發現,原來localStorage並沒有將這兩個東西真正存進去,從瀏覽器中看到的localStorage裡面action和mutation都是空物件…,查閱相關資料發現了這麼一句話: JSON 不允許包含函式,JSON.stringify() 會刪除 JavaScript 物件的函式,包括 key 和 value。 不過我們可以先將函式轉化為字串再將整個物件轉化為JSON字串。這樣的話就得先遍歷一遍mutation和action了,到這裡往後又出現了兩個新的問題:
    1>怎麼在元件中讀取mutation,vuex官網上是這樣定義的: Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字串的 事件型別 (type) 和 一個 回撥函式 (handler)。 類似事件但又不是事件,導致我不知道怎麼將他放到元件中去。(原諒我實在看不懂原始碼了)
    2>怎麼使用mutation,在mutation中提交載荷來改變state這是vuex的一套邏輯,但是現在畢竟是仿造的(還不是高仿那種),想在短時間內實現和vuex一樣的邏輯對我來說有點不現實。

綜上所述我還是果斷放棄了localStorage

重回方法二

前文所述的第三種方案失敗了之後,我打算嘗試一下第二種方法,如果不行就只好用第一種了,第二種方法使用window.open直接開啟新的頁籤雖然無法將上一個路由中儲存的vuex狀態帶入下一個路由中,但是我開啟調式工具發現新的頁籤中仍然可以使用vuex,這也就為第二種方法創造了無限的可能!接下來的事就簡單而繁瑣了,將前一個路由要儲存的state全部作為vue-router的params傳入新頁籤路由,再通過新頁籤元件中的created將這些引數存入vuex中。(因為新路由中大量使用了上一個路由儲存的state,所以我儘量不改變之前的邏輯)這一個過程比較繁瑣但也沒有什麼難點了,只需要不斷測試檢查是否有遺漏之處。最後介紹一個小技巧:開啟新頁籤可以這樣用window.open(${window.location.origin}${window.location.pathname}#/)在#/後面加上自己的路由。

寫在後面

倉促實現這個需求的過程中也暴露出了自己的一些問題,最大的問題就是考慮不周全,使用方法三的時候並沒有先充分實驗調查就開始寫程式碼,結果浪費了一個晚上的時間寫出來的程式碼都作廢了,如果開始寫之前就瞭解到了mutation的問題或許會少走些彎路。

題外話

'失敗獅’這個詞一出現在我的腦海中我第一個反應是皇家海軍,結果百度了一下發現——好吧,我還是提督當久了。