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

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] = value
LStorage.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 = -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,或者初始化就没有设置默认值,是不会被监听到的,应该是放到一级属性监听里面, 进行一个判断
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
参考文章:
解决VUEX刷新的时候出现数据消失
# vuex页面刷新数据丢失
# vuex
# 页面刷新
# vue刷新页面数据丢失
# 详解Vue中使用Echarts的两种方式
# 使用Vue开发动态刷新Echarts组件的教程详解
# vue结合Echarts实现点击高亮效果的示例
# vue中echarts3.0自适应的方法
# 在Vue中使用echarts的方法
# 在vue中通过axios异步使用echarts的方法
# 解决vue 路由变化页面数据不刷新的问题
# 详解刷新页面vuex数据不消失和不跳转页面的解决
# vue使用keep-alive实现数据缓存不刷新
# 解决VUEX刷新的时候出现数据消失
# vue.js中使用echarts实现数据动态刷新功能
# 为空
# 我觉得
# 用了
# 之初
# 歌曲列表
# 都是
# 应该是
# 这是
# 有什么
# 我就
# 我要
# 下首
# 我在
# 你可以
# 是有
# 一句
# 我都
# 你也
# 我一
# 可以用
相关文章:
高端建站三要素:定制模板、企业官网与响应式设计优化
黑客入侵网站服务器的常见手法有哪些?
如何在IIS7中新建站点?详细步骤解析
西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?
洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?
如何在云主机快速搭建网站站点?
儿童网站界面设计图片,中国少年儿童教育网站-怎么去注册?
微信小程序制作网站有哪些,微信小程序需要做网站吗?
如何高效生成建站之星成品网站源码?
如何在Golang中使用encoding/gob序列化对象_存储和传输数据
免费视频制作网站,更新又快又好的免费电影网站?
如何挑选优质建站一级代理提升网站排名?
建设网站制作价格,怎样建立自己的公司网站?
枣阳网站制作,阳新火车站打的到仙岛湖多少钱?
企业微网站怎么做,公司网站和公众号有什么区别?
制作假网页,招聘网的薪资待遇,会有靠谱的吗?一面试又各种折扣?
SAX解析器是什么,它与DOM在处理大型XML文件时有何不同?
潍坊网站制作公司有哪些,潍坊哪家招聘网站好?
网站制作公司排行榜,抖音怎样做个人官方网站
如何通过WDCP绑定主域名及创建子域名站点?
商务网站制作工程师,从哪几个方面把握电子商务网站主页和页面的特色设计?
行程制作网站有哪些,第三方机票电子行程单怎么开?
焦点电影公司作品,电影焦点结局是什么?
php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】
手机网站制作与建设方案,手机网站如何建设?
建站之星如何取消后台验证码生成?
网站海报制作教学视频教程,有什么免费的高清可商用图片网站,用于海报设计?
魔毅自助建站系统:模板定制与SEO优化一键生成指南
如何在万网ECS上快速搭建专属网站?
公司门户网站制作流程,华为官网怎么做?
如何在Windows 2008云服务器安全搭建网站?
武汉网站如何制作,黄黄高铁武穴北站途经哪些村庄?
阿里云网站制作公司,阿里云快速搭建网站好用吗?
如何快速打造个性化非模板自助建站?
建站之星好吗?新手能否轻松上手建站?
如何基于云服务器快速搭建个人网站?
建站之星2.7模板快速切换与批量管理功能操作指南
潮流网站制作头像软件下载,适合母子的网名有哪些?
小型网站建站如何选择虚拟主机?
如何在云主机上快速搭建网站?
如何用虚拟主机快速搭建网站?详细步骤解析
建站主机SSH密钥生成步骤及常见问题解答?
合肥做个网站多少钱,合肥本地有没有比较靠谱的交友平台?
北京网站制作网页,网站升级改版需要多久?
定制建站方案优化指南:企业官网开发与建站费用解析
如何生成腾讯云建站专用兑换码?
建站主机选哪种环境更利于SEO优化?
如何用好域名打造高点击率的自主建站?
如何基于云服务器快速搭建网站及云盘系统?
建站之星代理平台如何选择最佳方案?
*请认真填写需求信息,我们会在24小时内与您取得联系。