之前我寫了一篇用ES6 Proxy方案解決數據同步的文章 頁面刷新vuex數據消失問題解決方案.
今天和同事溝通這個vuex數據還原問題,我說我的方法很奇異。聊着聊着,同事咋不用 store.subscribe , 當時還有點覺得不可能,仔細再去看vuex官方文檔。
這個還真的是可行,但當然也是存在不方便的地方的。
此方案現在已經應用我基於vue開發的音樂web app VBOX 上,歡迎大家給star.
基本方案和步驟如下
1. 簡單的按照鍵復制對象
2. localStorage存儲的封裝
3. vuex插件編寫
4. localStorage的數據還原和初始化 Vuex.Store
第一:簡單的按照鍵復制對象
/** * 數據簡單復制 * @param {*} source * @param {*} keys */ const copy = function (source, keys = []) { if (!source) { return source } let d = Object.create(null) keys.forEach(k => { d[k] = source[k] }) return d } export { copy }
第二:localStorage的簡單封裝
const ls = window.localStorage // https://github.com/tsironis/lockr export default { getItem(key) { try { return JSON.parse(ls.getItem(key)) } catch (err) { return null } }, setItem(key, val) { ls.setItem(key, JSON.stringify(val)) }, clear() { ls.clear() }, keys() { return ls.keys() }, removeItem(key) { ls.removeItem(key) } }
第三:vuex插件
主要是一個lsKey,存到localStorage的key,
另外一個是 mutation白名單,白名單內的觸發不會觸發數據同步
實際上這里是存在一定問題的,這里適用模塊后的store
(1) 無法快速有效便捷的定位什么時候該觸發同步
import ls from '../utils/LStorage' import { copy } from '../utils/utils' export const createLSPlugin = function (lsKey, mappings, whitelist = []) { let k = lsKey || 'lsKey' return store => { store.subscribe((mutation, state) => { if (whitelist.findIndex(m => m === mutation.type) < 0) { let cd = Object.create(null) Object.keys(state).forEach(k => { if (mappings[k]) { cd[k] = copy(state[k], mappings[k]) } }) ls.setItem(k, cd) } }) } }
第四:初始化Vuex.Store
主要是從localStore里面還原數據合並到state里面,如果state沒有分模塊還是比較簡單的。
import Vue from 'vue' import Vuex from 'vuex' import playing from './playing' import player from './player' import searchHistory from './searchHistory' import { createLSPlugin } from '../plugin/syncls' import ls from '../utils/LStorage' const LS_KEY = 'vbox' const lsData = ls.getItem(LS_KEY) let mapping = { playing: ['list', 'current'], player: ['mode'], searchHistory: ['list'] } let mWhiteList = ['player/timeUpdate', 'player/setState'] if (lsData) { let { playing: ls_playing, player: ls_player, searchHistory: ls_searchHistory } = lsData Object.assign(playing, { state: ls_playing }) Object.assign(player, { state: ls_player }) Object.assign(searchHistory, { state: ls_searchHistory }) } Vue.use(Vuex) const plugin = createLSPlugin(LS_KEY, mapping, mWhiteList) const store = new Vuex.Store({ modules: { playing, player, searchHistory }, plugins: [plugin] }) export default store
優點
1. 代碼簡單,對代碼改動不大
2. 對原始的state沒有額外干預
缺點
1. 觸發存儲條件不好控制
2. 存儲限制實現會相對復雜