vuex页面数据丢失_关于页面刷新vuex数据消失问题解决方案

本文介绍了在Vue项目中使用Vuex遇到的页面刷新后数据丢失问题,以及如何通过ES6的Proxy实现数据持久化,解决此问题。通过创建一个代理,将Vuex的state与localStorage进行同步,实现在刷新页面后仍能保留数据。虽然该方法目前只能代理二级属性,但减少了对现有代码的修改,简化了state与持久化存储的同步过程。
摘要由CSDN通过智能技术生成

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

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

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

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

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

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

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

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

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

这里有两个问题

1. 初始值的问题。

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

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

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

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

createHanlder 创建二级属性的代理

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

proxy 创建state的代理

/**

代理二级属性

@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] = value

LStorage.setItem(lsKey,item)

}

return Reflect.set(target,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,receiver) {

ks.indexOf(key) >= 0 && LStorage.setItem(lsKey,copy(target,keys))

return Reflect.set(target,receiver)

}

})

}

export { proxy }

调用这边,基本就没有什么变化,就多了一句 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 = -1

songs.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 = -1

songmids.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,或者初始化就没有设置默认值,是不会被监听到的,应该是放到一级属性监听里面,进行一个判断

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。

参考文章:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值