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

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刷新的时候出现数据消失

(0)

相关推荐

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

    通常,我们在使用vue编写页面时,会需要使用vuex在组件间传递(或者说共同响应)同一个数据的变化.例如:用户的登录信息. 下面,我们使用传递用户登录信息的例子来一步步解决这个问题. 首先,我们的第一个问题是:我在一个组件(例如登录组件页面)中登录了后,其它页面要怎么获取和响应这个变化?(就是这么小白,/(ㄒoㄒ)/~~) 这个答案就是使用vuex啦,在中文版的文档中有这样一句话: 而这里的计算属性就是我们的伟大的computed属性啦~ (至于前面的通过mutation之类的把数据存入vuex

  • vue.js实现刷新当前页面的方法教程

    前言 Vue.js(是一套构建用户界面的渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库只关注视图层,是一种数据驱动的前端框架 我们在开发vue的页面的时候,有时候会遇到需要刷新当前页面功能,但是vue框架自带的router是不支持刷新当前页面功能的,它只支持在路由路径变化时刷新页面.基于这个原理,为了实现刷新页面,可以先跳转到一个空页面,然后马上跳回来,从而实现这个功能. 开发工具环境 vue.js webstorm 方法如下 一.原理 如上图所示,我

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

    VBox持续进行中,哀家苦啊,有没有谁给个star. vuex是vue用于数据存储的,和redux充当同样的角色. 最近在VBox开发的时候遇到的问题,页面刷新或者关闭浏览器再次打开的时候数据归零.这是头疼的问题. 网上搜,大家的方案都是把数据转移到 localStorage或者其他持久化存储(例如indexDB). 这倒是可以,我在设计之初因为匆忙,没有考虑周全,这下好,然不成每个 mutation都去存一下. 这个弄的我很不开心,周六在公司,本来就困的要死,又想不到合理的解决方案,昏昏沉沉睡

  • 使用sessionStorage解决vuex在页面刷新后数据被清除的问题

    1.原因 2.解决方法 localStorage没有时间期限,除非将它移除,sessionStorage即会话,当浏览器关闭时会话结束,有时间期限,具有自行百度 我这里使用sessionStorage,这里需要注意的是vuex中的变量是响应式的,而sessionStorage不是,当你改变vuex中的状态,组件会检测到改变,而sessionStorage就不会了,页面要重新刷新才可以看到改变,所以应让vuex中的状态从sessionStorage中得到,这样组件就可以响应式的变化 3.具体实现

  • 解决vue页面刷新vuex中state数据丢失的问题

    页面刷新后,原有的 vuex 中的 state 会发生改变,如果在页面刷新之前,可以将 state 信息保存,页面重新加载时,再将该值赋给 state,那么该问题即可解决. 1.localstorage 可以使用 localstorage 来保存信息. [在某组件中添加如下钩子函数.比如 App.vue中] created() { //在页面加载时读取localStorage里的状态信息 if (localStorage.getItem("store") ) { this.$store

  • 详解刷新页面vuex数据不消失和不跳转页面的解决

    先说点什么 vuex和路由拦截这一块捣鼓的有一段时间了,总算是爬出来了,特地来分享一下,首先声明没有什么基础介绍,用的是登录状态存储sessionStorage的方法!!! 进入正题 刷新 刷新相当与重启项目,之前获取到的数据也只是通过store暂存起来,项目关闭时就不见了,这有些像电脑重启,存储在RAM的数据会消失.但是储存在sessionstorage.localstorage和cookie里的内容不会消失. Vuex 方法思路 首先得熟悉vuex,官网中介绍 Vuex 是一个专为 Vue.

  • 解决vue页面刷新或者后退参数丢失的问题

    在toB的项目中,会经常遇到列表数据筛选查询的情景,当要打开某一项的详情页或者暂时离开列表页,再返回(后退时),选择的筛选条件会全部丢失,辛辛苦苦选择好的条件全没了,还得重新选择,如果有分页的更头大,还得重新一页页翻到之前看到的那一页,用户体验极度不友好. 我的解决有两种: 第一种方法:用vue 的<keep-alive>,即在<router-view>外套一层<keep-alive>. 虽然可以达到一定效果,但是控制起来比较麻烦,比如项目中并不是所有页面都需要缓存,代

  • 使用vuex解决刷新页面state数据消失的问题记录

    在实际的vue项目中,当我们的应用遇到多个组件之间的共享问题时,通常会用到Vuex(一个状态管理的插件,可以解决不同组件之间的数据共享和数据持久化),解决组件之间同一状态的共享问题. 因子: Vuex优势:相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到. Vuex劣势:在刷新页面后,vuex会重新更新state,所以,存储的数据会丢失. 言而总之: 实际问题:在vue项目中,使用Vuex做状态管理时,调试页面时,刷新后state上的数据消失了,该

  • vuex管理状态 刷新页面保持不被清空的解决方案

    mutation文件 import { RECEIVE_PUBLICHTIT } from './mutation-types' //保证刷新页面数据不消失* function storeLocalStore (state) { window.localStorage.setItem("publicTit",JSON.stringify(state)); } export default { [RECEIVE_PUBLICHTIT] (state,{title}){ state.pub

  • Vuex持久化插件(vuex-persistedstate)解决刷新数据消失的问题

    页面刷新后,想保存页面未保存的数据.我们总是习惯于放在浏览器的sessionStorage和localStorage中.但是用了vue后,vuex便可以被应用了. vuex优势:相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到. vuex劣势:在F5刷新页面后,vuex会重新更新state,所以,存储的数据会丢失. vuex可以进行全局的状态管理,但刷新后刷新后数据会消失,这是我们不愿意看到的.怎么解决呢,我们可以结合本地存储做到数据持久化,也可以

  • 解决vuex刷新数据消失问题

    前言 vue构建的单页大型项目中,可能会用到Vuex .Vuex 的状态存储是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新. 但是有一个问题就是:vuex的存储的数据只是在页面的中,相当于我们定义的全局变量,刷新之后,里边的数据就会恢复到初始化状态.但是这个情况有时候并不是我们所希望的. 比如,用户已经登录了,我把登录状态放到state中了,一刷新页面,还要重新登录?购物车里的添加的数据,一刷新要重新添加? 解

  • vuex页面刷新导致数据丢失的解决方案

    解决vuex页面刷新导致数据丢失问题 vuex数据是存在内存当中,当页面刷新之后vuex数据自然会丢失.我们有两种方法解决该问题: 1.使用vuex-along 2.使用localStorage或者sessionStroage 1.使用vuex-along vuex-along的实质也是将vuex中的数据存放到localStorage或者sessionStroage中,只不过这个存取过程这个组件会帮我们完成,我们只需要用vuex的读取数据方式操作就可以了,简单了解一下vuex-along的使用方

随机推荐