Vuex持久化插件

前言

用vue開發中大型應用時候,咱們一般都會使用vuex進行狀態管理,但刷新後刷新後存在內存中的vuex數據將會丟失。在不少場景中,咱們不肯意看到這樣的結果的。javascript

Vuex 社區中有相關的解決方案,好比vue-savedata,vuex-persistedstate,解決思路都是state裏的數據保存一份到本地存儲(localStorage、sessionStorage、cookie)中。vue

實現插件以前,先看下怎麼實現一個簡單的插件java

寫個 Vuex 插件

Vuex 的 store 接受 plugins 選項,這個選項暴露出每次 mutation 的鉤子。Vuex 插件就是一個函數,它接收 store 做爲惟一參數:vuex

const myPlugin = store => {
  // 當 store 初始化後調用
  store.subscribe((mutation, state) => {
    // 每次 mutation 以後調用
    // mutation 的格式爲 { type, payload }
  })
}
複製代碼

使用:緩存

const store = new Vuex.Store({
  // ...
  plugins: [myPlugin]
})
複製代碼

store.subscribe : 訂閱 store 的 mutation。handler 會在每一個 mutation 完成後調用,接收 mutation 和通過 mutation 後的狀態做爲參數cookie

實現一個簡單的Vuex持久緩存插件

缺點:vuex 中全部的state所有保存在本地storage中,而且每次觸發mutation,都會儲存state。若是頻繁操做vuex,會一直更新storage,性能太差session

export default (options = {}) => {
    return store => {
        store.replaceState(JSON.parse(window.localStorage.cacheStore))
        store.subscribe((mutation,state) => {
            window.localStorage.setItem('cacheStore',JSON.stringify(state))
        })
    }
}

複製代碼

設計一個完整的Vuex持久緩存插件

實現代碼

export default (options = {}) => {
    /** cache:緩存列表 delay:防抖或節流時間 mode:防抖或節流(debounce|throttle )自行實現吧(^_^) */
    let {cache = [],delay = 1000,mode='debounce'} = options
    
    // 緩存的數據
    let cacheData = {}
    
    // 本地儲存輔助函數 mode:緩存模式
    const storeage = (mode = "LS") => {
        if(mode.toUpperCase() == 'SS') {
            return window.sessionStorage
        }
        return window.localStorage
    }
    
    // 防抖函數
    const debounce = (fn, delay) => {
    	let timer = null;
    	let status = true;
    	return function () {
    		let args = arguments;
    		if (timer) clearTimeout(timer)
    		timer = setTimeout(() => fn.apply(this, args), delay)
    	}
    }
    
    // 判斷是否對象
    const isObject = value => Object.prototype.toString.call(value) == "[object Object]"
    
    // 合併對象
    const merge = (a,b) => {
        for (var key in b) {
            if (!a.hasOwnProperty(key)) {
                a[key] = b[key];
            } else if (isObject(b[key]) && isObject(a[key])) {
                merge(a[key], b[key]);
            }
        }
        return a;
    }
    
    // 窗口關閉觸發更新本地storeage的數據
    window.addEventListener('beforeunload',() => {
        Object.keys(cacheData).forEach(key => {
            let {mode,...other} = cacheData[key]
            storeage(mode).setItem(key,JSON.stringify(other))
        ]})
    },false)
    
    return store => {
        let {state:initState,_modulesNamespaceMap} = store
        // 判斷是否模塊
        const hasModule = name => !!_modulesNamespaceMap[name+'/']
        
        let data = cache.reduce((prev,curr) => {
            let {key,mode} = curr
            if(hasModule(key) && storeage(mode)[key]){
                prev[key] = JSON.parse(storeage(mode)[key]).data
            }else{ // Root state
                // 須要的能夠自行擴展
                // code
            }
            return prev
        },{})
        
        //合併本地storeage中的數據到Vuex state 中,並初始化
        merge(data,initState)
        store.replaceState(data)
        
        store.subscribe(debounce((mutation,state) => {
            let [key,type] = mutation.split('/')
            // 是否模塊
            if(type && hasModule(key)){ 
                let findItem = cache.find(option => option.key === key)
                //是否緩存
                if(findItem){
                    let {whiteList,mode} = findItem
                    // 是否在緩存白名單中
                    if(whiteList && !whiteList.includes(type) || !whiteList){
                        let module = state[key]
                        cacheData[key] = {
                            mode,
                            data:module
                        }
                    }
                }
            }else{ // Root state
                // 須要的能夠自行擴展
                // code
            }
        },delay))
    }
}
複製代碼

使用插件

import CachePlugin from './vuex-cache-plugin'
const store = new Vuex.Store({
  modules:{
      saveData:{
          namespaced:true
      },
      saveData2:{
          namespaced:true
      }
  }
  plugins: [
    CachePlugin({
        delay:1000,
        cache:[
            {key:'saveData',mode:'SS'}
            {key:'saveData2',whiteList:['SET_TEST']}
        ]
    })
  ]
})
複製代碼
相關文章
相關標籤/搜索