失敗獅計劃——在localStorage中儲存vuex狀態
前言
最近碰到了這麼一個需求變動:在當前頁點選一個按鈕開啟一個新的頁籤(本來是在當前頁通過路由跳轉進入一個新的元件),對於傳統jq專案來說這個應該是不費吹灰之力可以實現的,但是對於vue專案來說就要好好斟酌一下了,當時我想到了3種方法來實現:
- 首先,最容易理解的就是構建一個簡單的多頁應用,即新建一個html入口,不過由於之前沒有這樣做過,對於要踩哪些坑沒有什麼把握,同時需要後臺進行相關的配置,而這個需求需要馬上上線,於是我決定先放棄這個待以後研究。
- 直接使用
window.open
開啟新的路由再從vuex種讀取之前儲存的狀態,這種方法直接開啟新的頁籤是無法獲取到上一個頁面儲存在vuex中的資訊的。(由於這個專案是多人同時開發而且有些思想不太統一,導致我接手的時候發現有好多路由跳轉之前都將一些資訊存到了vuex中,個人認為在pc端跨路由最好不要使用vuex,否則重新整理頁面就啥也沒了…) - 既然前兩種都暫時行不通,我又想到了使用
localStorage
儲存vuex中的資訊,因為之前就面臨過重新整理頁面的尷尬,所以使用了sessionStorage
來儲存當前登入使用者的資訊,而sessionStorage
存在時效性,故而選擇了localStorage
。(後來發現直接開啟新頁籤,之前頁籤的sessionstorage還是存在的)
###實現過程
1.在開啟新頁籤之前將需要用的vuex狀態儲存到localStorage
中去,由於這部分內容都在一個模組裡面,故可以直接將一個Module
儲存到localStorage
,儲存Module
物件的時候需要轉為JSON字串(JSON.stringify()
- 讀取存入的vuex狀態,使用
localStorage.getItem()
讀取之後再用JSON.parse()
即可拿到存入的物件。 - 那麼問題來了,如何將取出的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;
};
之後在元件中常規引入,成功取到了!
- 引入
mutation
和action
就在我準備依葫蘆畫瓢準備搞定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的問題或許會少走些彎路。
題外話
'失敗獅’這個詞一出現在我的腦海中我第一個反應是皇家海軍,結果百度了一下發現——好吧,我還是提督當久了。