用vue開發中大型應用時候,咱們一般都會使用vuex進行狀態管理,但刷新後刷新後存在內存中的vuex數據將會丟失。在不少場景中,咱們不肯意看到這樣的結果的。javascript
Vuex 社區中有相關的解決方案,好比vue-savedata,vuex-persistedstate,解決思路都是state裏的數據保存一份到本地存儲(localStorage、sessionStorage、cookie)中。vue
實現插件以前,先看下怎麼實現一個簡單的插件java
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 中全部的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))
})
}
}
複製代碼
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']}
]
})
]
})
複製代碼