vue 數據持久化(刷新保存數據)的探索


對於 PC 端的 VUE 項目來講,刷新頁面導致數據消失是一個繞不開的坑。好在 vuex-persistedstate插件能夠解決這個問題。

vuex-persistedstate

它的原理是:

  • 每次 mutation 都將整個 store 保存到本地(localStorage/sessionStorage/cookie);
  • 初始化時用本地數據替換(replaceState)掉 store。

它的代碼簡潔、邏輯清晰,且對業務代碼毫無侵入,可以說是我輩楷模。(劇終...

今天,咱就雞蛋里挑骨頭,站在個人的角度上主觀的評評這個方案的缺點。

第一:和 Vuex 綁定,對於大多數項目來說,用 Vuex 基本上是白白增加復雜度。

第二:對於超大型項目來講,頻繁的快照整個 store ,可能會有性能消耗。

第三:需要我們關注什么時候刪除本地數據。

那么,有沒有其他的可替代方案呢?

onbeforeunload

新的方案,個人覺得應該做到:

  • 不強制,需要才導入
  • 只在關鍵時刻才保存,這個時機就是頁面刷新的那一刻
  • 不依賴除 Vue 外的任何庫/框架

經過一番折騰,有了下面的代碼 saveBeforeUnload.mixin.js

import Store from "@/utils/sessionStorage";
const CACHE_PREFIX = "CACHE_KEY_";
const getCacheKey = path => CACHE_PREFIX + path;

export default {
  created() {
    const CACHE_KEY = getCacheKey(this.$route.path);
    const CACHE_DATA = Store.get(CACHE_KEY);
    if (CACHE_DATA) {
      Object.assign(this, CACHE_DATA);
      Store.remove(CACHE_KEY);
    }
  },

  beforeRouteEnter(to, from, next) {
    next(vm => {
      window.onbeforeunload = () => {
        const CACHE_KEY = getCacheKey(vm.$route.path);
        Store.set(CACHE_KEY, vm.$data);
        window.onbeforeunload = null;
      };
    });
  },
};

從文件名可以看出,它其實是一個 mixin,需要在頁面中導入。這段代碼有如下缺陷:

  • 刷新時,只能保存當前這個頁面的數據,如果多個頁面都 mixin 了,其他頁面的數據不會被保存
  • 由於是 mixin 方式,對業務代碼有些許侵入但不影響運行

進化版

如果想要保存多個頁面的數據,需要將代碼做如下更改:

import Store from "@/utils/sessionStorage";
const CACHE_PREFIX = "CACHE_KEY_";
const getCacheKey = path => CACHE_PREFIX + path;

const handler = {};

export default {
  created() {
    const CACHE_KEY = getCacheKey(this.$route.path);
    const CACHE_DATA = Store.get(CACHE_KEY);
    if (CACHE_DATA) {
      Object.assign(this, CACHE_DATA);
      Store.remove(CACHE_KEY);
    }
  },

  beforeRouteEnter(to, from, next) {
    next(vm => {
      const CACHE_KEY = getCacheKey(vm.$route.path);
      if (handler[CACHE_KEY]) return;

      handler[CACHE_KEY] = () => {
        Store.set(CACHE_KEY, vm.$data);
      }
      window.addEventListener('beforeunload', handler[CACHE_KEY]);
    });
  },

  destroyed() {
    const CACHE_KEY = getCacheKey(this.$route.path);
    if (handler[CACHE_KEY]) {
      window.addEventListener("beforeunload", handler[CACHE_KEY]);
      handler[CACHE_KEY] = null;
    }
  }
};

export function removeCachedData(location) {
  Store.remove(getCacheKey(location.path));
}

並在每次路由 push/replace 時,刪除 CACHE_KEY 對應的本地數據,防止舊數據被渲染。

const __push = router.push;
router.push = (location, ...args) => {
  if (typeof location === 'string') {
    location = {
     path: location
    }
  }

  removeCachedData(location);
  __push(location, ...args);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM