页面刷新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或者你喜欢的,小轮子我就自己写了。

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. 对现有代码的注入是相当少的。

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

参考文章:

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

时间: 2024-11-05 11:33:47

页面刷新vuex数据消失问题解决方案的相关文章

页面刷新vuex数据消失问题解决方案 之 vuex中间件

之前我写了一篇用ES6 Proxy方案解决数据同步的文章 页面刷新vuex数据消失问题解决方案. 今天和同事沟通这个vuex数据还原问题,我说我的方法很奇异.聊着聊着,同事咋不用  store.subscribe , 当时还有点觉得不可能,仔细再去看vuex官方文档. 这个还真的是可行,但当然也是存在不方便的地方的. 此方案现在已经应用我基于vue开发的音乐web app VBOX 上,欢迎大家给star. 基本方案和步骤如下 1. 简单的按照键复制对象 2. localStorage存储的封装

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

vuex中数据刷新页面消失问题:a页面请求的数据保存在vuex中,只要不刷新,那跳转到b页面里也可以用,但如果b页面刷新,那vuex里的数据就会消失,可以得解决方法:a页面用的数据a页面的生命周期函数里请求,b页面用的数据b页面的生命周期函数里请求 你需要知道JavaScript代码是运行在内存中的,代码运行时的所有变量,函数,也都是保存在内存中的.刷新页面,以前申请的内存被释放,重新加载脚本代码,变量重新赋值,所以这些数据要想储存就必须储存在外部,例如:Local Storage, Sessi

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

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

Vue 路由跳转传递参数,子组件页面刷新后数据不丢失

原文地址:https://www.cnblogs.com/yscec/p/12408492.html

Vuex数据页面刷新丢失问题解决方案

用Vue做项目开发很久了,对于vuex能用.会用,但是因为状态脱离页面和刷新丢失两个原因,一直都有种抵触,特别是一些简单的数据都是通过query或者本地存储就解决了,然而对于一些复杂内容,不可避免的还是要使用Vuex去处理(真香),但是刷新丢失的问题,的确叫人头大.最近闲下来,我们来研究下怎么干掉这个问题- 不大了解Vuex的同学,可以先去官网溜溜 由于Vuex的数据是存储在内存中的,相当于memory cache,当页面刷新的时候内存被清空重载新内容,原来的数据就丢了,为了解决这个我们可以借助

vuex页面刷新数据不保留,解决方法(转)

今天这个问题又跟页面的刷新有一定的关系,虽然说跟页面刷新的关系不大,但确实页面刷新引起的这一个问题. 场景: VueX里存储了 this.$store.state.PV这样一个变量,这个变量是在app.vue里通过接口获取然后存储在vueX里的,在路由activity.vue中,我们需要用到这个变量,并且通过这个变量的值来控制路由页面里某一段dom元素的显示与否. 这个需求这样描述起来,是很好实现的.于是我就简单写了几段代码,很简单轻松的实现了这个需求: //acitity.vue Dom结构

vue el-form鼠标事件导致页面刷新解决方案;vue 阻止多次点击提交数据通用方法

一.阻止表单自动提交刷新页面:<el-form> <el-form-item :inline="true" @submit.native.prevent> <el-input @keyup.enter.native='submit'></el-input> </el-form-item> </el-form> 注意: 鼠标事件导致页面刷新问题,在el-form上增加 @submit.native.prevent 可

解决vuex页面刷新导致数据丢失问题

vuex是大家使用vue时大多数都会选择的,但是当页面刷新之后vuex数据会丢失,因为页面刷新之后代码重新加载这样vuex的数据自然就会为空.怎么解决这个问题呢?vuex自身好像没有太好的解决方案,但是我们可以利用localStorage和sessionStorage对数据进行保存.这样这个问题就解决了.这个方法比较简单但是其实这样做就和vuex没有太大的关系了,我们可以将数据存在localStorage中为什么还要用vuex呢?所以这种方法可用但是不建议,那么还有什么解决方案呢? 其实网上也有

vuex页面刷新数据丢失的解决办法

在vue项目中用vuex来做全局的状态管理, 发现当刷新网页后,保存在vuex实例store里的数据会丢失. 原因: 因为store里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值初始化 解决思路: 将state的数据保存在localstorage.sessionstorage或cookie中(三者的区别),这样即可保证页面刷新数据不丢失且易于读取. localStorage: localStorage的生命周期是永久的,关闭页面或浏览器之