VBox持续进行中,哀家苦啊,有没有谁给个star。

Github地址:https://github.com/xiangwenhu/vbox, 欢迎大家点赞 

vuex是vue用于数据存储的,和redux充当同样的角色。

最近在VBox开发的时候遇到的问题,页面刷新或者关闭浏览器再次打开的时候数据归零。这是头疼的问题。

网上搜,大家的方案都是把数据转移到 localStorage或者其他持久化存储(例如indexDB)。

这倒是可以,我在设计之初因为匆忙,没有考虑周全,这下好,然不成每个 mutation都去存一下。

这个弄的我很不开心,周六在公司,本来就困的要死,又想不到合理的解决方案,昏昏沉沉睡着了。

醒了后,最初想采用 柯里化和高阶函数来解决这个问题,很可惜,没有正解。

最小化修改,又不想动现有代码,代理二字最为不过。记得上次我写IBook之初,也用Proxy来拦截修改,同时存数据到磁盘文件。

没错方案就是 ES6的Proxy,尝试之后,确实是可以的。

源码地址:https://github.com/xiangwenhu/vbox/tree/master/src/utils

这里有两个问题

1. 初始值的问题。

2. 我要可以配置哪些字段需要持久化,store里面的数据,不代表我都需要持久化。

首先解决是 localStorage存储的问题,因为需要转换字符串,简单封装一个 LStorage.js,当然你也可以用 https://github.com/tsironis/lockr , https://github.com/nbubna/store 或者你喜欢的,小轮子我就自己写了。

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)}
}

其次就是代理的简单封装,LSproxy.js

这个版本还是有问题的,现在只能代理二级属性,对现在的我而言已经是够用了的。

createHanlder 创建二级属性的代理

copy 复制对象,当然你可以写更加兼容优雅的方法

proxy  创建state的代理

import LStorage from './LStorage'/*** 代理二级属性* @param {*} lsKey 存在localStorage的key* @param {*} pk    一级属性的key*/
function createHanlder(lsKey, pk) {return {set: function (target, key, value, receiver) {let item = LStorage.getItem(lsKey)if (item && item[pk]) {item[pk][key] = valueLStorage.setItem(lsKey, item)}return Reflect.set(target, key, value, receiver)}}
}/*** 仅仅存需要存放的数据* @param {*} source * @param {*} keys */
function copy(source, keys = []) {if (!source) {return source}let d = Object.create(null)keys.forEach(k => { d[k] = source[k] })return d
}/*** 代理state* @param {*} initState 初始化的值* @param {*} lsKey  localStorage的key* @param {*} keys   需要存储的键*/
const proxy = function (initState, lsKey, keys = []) {let ks = keys, obj = Object.assign({}, initState, LStorage.getItem(lsKey))// 代理二级属性keys.forEach(k => {obj[k] = new Proxy(obj[k], createHanlder(lsKey, k))})// 存入合并的值
  LStorage.setItem(lsKey, copy(obj, keys))return new Proxy(obj, {set: function (target, key, value, receiver) {ks.indexOf(key) >= 0 && LStorage.setItem(lsKey, copy(target, keys))return Reflect.set(target, key, value, receiver)}})
}export { proxy }

调用这边,基本就没有什么变化, 就多了一句  state = proxy(state, 'playing', ['list'])

import { proxy } from '../utils/LSProxy'
let state = {list: [],current: null
}
state = proxy(state, 'playing', ['list'])const mutations = {/*** 添加歌曲* @param {*} state * @param {*} song 歌曲信息 */addSong(state, song) {let index = state.list.findIndex(s => s.songmid === song.songmid)if (index < 0) {state.list.push(song)}},/*** 添加歌曲* @param {*} state  内置* @param {*} songs  歌曲列表*/addSongs(state, songs) {let index = -1songs.forEach(song => {index = state.list.findIndex(s => s.songmid === song.songmid)if (index < 0) {state.list.push(song)}})},/*** 删除歌曲* @param {*} state * @param {*} songmid  歌曲媒体id */removeSong(state, songmid) {let index = state.list.findIndex(s => s.songmid === songmid)index >= 0 && state.list.splice(index, 1)},/*** 批量删除歌曲* @param {*} state * @param {*} songmids 歌曲媒体列表 */removeSongs(state, songmids = []) {let index = -1songmids.forEach(songmid => {index = state.list.findIndex(s => s.songmid === songmid)index >= 0 && state.list.splice(index, 1)})},/*** 播放下一首,* @param {*} state * @param {*} song 为空*/next(state, song) {// 如果song不为空,表示是插放,(前提是已经添加到playing)if (song) {let index = state.list.findIndex(s => s.songmid === song.songmid)if (index >= 0) {state.current = state.list[index]return}return}// 如果current为空,表示没有播放的歌曲if (!state.current && state.list && state.list.length > 0) {state.current = state.list[0]return}// 如果不是插放,并且current不为空if (!song && state.current) {// 播放的歌曲是不是在当前的列表let index = state.list.findIndex(s => s.songmid === state.current.songmid)// 如果在歌曲列表里面,接着播放下首if (index >= 0) {state.current = (index === state.list.length - 1 ? state.list[0] : state.list[index + 1])} else {state.current = state.list[0]}}}
}export default {namespaced: true,state,mutations
}

这种方案的缺点也是很明显的,

1. 代码只能代理二级,对我一般情况应该是够用了,扁平化state

2. 代理二级属性和数组,要是属性平凡修改的时候,代理是会重复触发的,比如,添加30首歌曲的时候,是发生了30次存储。 当然我觉得也是有方案可以优化的。

优点我觉得是,

1. state的数据与localStorage的同步过程分离开

2. 对现有代码的注入是相当少的。

当然我上面代码本身也还是存在问题的

1. 二级监听不能在proxy执行的时候返回,因为如果属性默认值为null/undefined,或者初始化就没有设置默认值,是不会被监听到的,应该是放到一级属性监听里面, 进行一个判断

不知道各位大神有什么好的方法,可以分享出来。

参考文章:

解决VUEX刷新的时候出现数据消失

页面刷新vuex数据消失问题解决方案相关推荐

  1. vue:vue页面刷新vuex数据消失问题

    vuex中数据刷新页面消失问题: a页面请求的数据保存在vuex中,只要不刷新,那跳转到b页面里也可以用,但如果b页面刷新,那vuex里的数据就会消失, 可以得解决方法:a页面用的数据a页面的生命周期 ...

  2. vue 添加完数据后刷新页面_页面刷新vuex数据消失

    1.前言 vue构建的项目中,vuex的状态存储是响应式的,当vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会得到高效刷新,问题来了,vuex存储的数据只是在页 ...

  3. vue项目中解决浏览器刷新vuex数据消失问题

    vue项目中解决浏览器刷新vuex数据消失问题 说明 vuex中的数据经过浏览器刷新后会消失,所以应设置在浏览器刷新之前将数据存入浏览器或者cookie中. 操作 打开App.vue,在created ...

  4. 页面刷新 vuex 数据重新被初始化

    1.原因 vuex里用来存储的也只是一个全局变量,当页面刷新,该全局变量自然不存在了. 2.解决 使用localStorage存储一份 (1)storage.js /** * vuex localSt ...

  5. 【vue】使用localStorage解决vuex在页面刷新后数据被清除的问题

    [vue]使用localStorage解决vuex在页面刷新后数据被清除的问题 参考文章: (1)[vue]使用localStorage解决vuex在页面刷新后数据被清除的问题 (2)https:// ...

  6. vue刷新浏览器vuex数据消失

    1 下载插件 npm install --save vuex-persistedstate 2 引入 import persistedState from 'vuex-persistedstate'/ ...

  7. websocket中自动生成身份编号(获取sessionID,将sid值设置为sessionID的方法),并在页面刷新时沿用sid的解决方案

    websocket如果需要1对1通信,或者说将服务器数据发送到指定的客户端上,就需要给每一个新生成的websocket加上编号.比较常见的,是在地址映射中加上编号,比如: @ServerEndpoin ...

  8. H5在安卓微信浏览器返回时动态获取的数据不会保留(页面刷新了数据初始化了)

    解决思路: 判断机型 跳转前将 动态构建的页面内容缓存在sessionStorage中 页面加载时,先从sessionStorage中获取数据 存在缺陷: 抑制了在窗口刷新能力 点击刷新,页面动态数据 ...

  9. vuex页面数据丢失_解决 vuex 中的数据在页面刷新之后就丢失的问题

    在vue的项目中我们一般都会使用到vuex,在vuex中我们会保存一个需要全局使用的变量或者状态,这样方便我们使用.但是vuex的store中的数据有一个特性,那就是在页面刷新时,页面会重新加载vue ...

最新文章

  1. 前端之css基础学习(更正版)
  2. 1126 Eulerian Path
  3. 盘启动盘_[装机]推荐唯二的两个开源免费的启动盘工具,轻松创建USB启动盘
  4. java子类对象不能调用父类protected方法和域的原因。
  5. Eclipse+Web3j开发以太坊应用
  6. IIS请求筛选模块被配置为拒绝超过请求内容长度的请求
  7. Injector Job深入分析
  8. 上海应用技术学院c语言实验报告9,上海工程技术大学C语言实验报告
  9. C# xml文件读取与修改
  10. @清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?
  11. 基于Matlab----MSK调制与解调
  12. CPU卡发卡总结(三)——充值和消费
  13. window10 20H2安卓模拟器VT检测不到问题解决方法
  14. java开发之异常处理_SimpleMappingExceptionResolver
  15. 五、产业互联网价值——构建“双螺旋”产业结构,实现产业价值指数增长
  16. 中国移动java面试_中国移动软件工程师面试经验
  17. android横竖屏切换动画,Android应用怎么实现屏幕横竖屏切换功能
  18. Flink应用实践-唯品会
  19. 云业CMS开源企业建站系统v2.1.6源码
  20. 迈克尔逊干涉仪仿真程序_使用迈克尔逊编程语言在Tezos上编写智能合约[操作指南]-第2部分...

热门文章

  1. 前后端分离实践(试探篇)
  2. XingXingMVC页面跳转处理
  3. 利用组策略防止计算机访问共享资源
  4. Linux系统端口聚合技术bonding
  5. markdown to html
  6. NSArray排序问题
  7. Office 365管理员指引 17——Sharepoint 讨论版
  8. A potentially dangerous Request.Form value was detected from the client
  9. VBS学习日记(二) 基础知识
  10. Ajax兼容处理+发送请求+接收返回信息