之前我写了一篇用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. 存储限制实现会相对复杂