手機(jī)網(wǎng)站開發(fā) caso平臺(tái)
vue3-vuex持久化實(shí)現(xiàn)
- 一、背景描述
- 二、實(shí)現(xiàn)思路
- 1.定義數(shù)據(jù)結(jié)構(gòu)
- 2.存值
- 3.取值
- 4.清空
- 三、具體代碼
- 1.定義插件
- 2.使用插件
- 四、最終效果
一、背景描述
有時(shí)候我們可能需要在vuex中存儲(chǔ)一些靜態(tài)數(shù)據(jù),比如一些下拉選項(xiàng)的字典數(shù)據(jù)。這種數(shù)據(jù)基本很少會(huì)變化,所以我們可能希望將其存儲(chǔ)起來,這樣就減少了請(qǐng)求的數(shù)量。
但是在每個(gè)位置都進(jìn)行存儲(chǔ),好像是在做重復(fù)的邏輯,所以我們可以考慮將這個(gè)功能提取出來,作為一個(gè)插件使用。
注意:建議不要濫用持久化存儲(chǔ),因?yàn)檫@可能導(dǎo)致你不能獲取到最新的數(shù)據(jù),只建議在一些長期不會(huì)變化的數(shù)據(jù)中使用。
二、實(shí)現(xiàn)思路
做到持久化存儲(chǔ),那就要在頁面銷毀之前將值存到storage中,頁面初始化的時(shí)候,再將值取到vuex中進(jìn)行數(shù)據(jù)初始化
1.定義數(shù)據(jù)結(jié)構(gòu)
我們首先要規(guī)定哪些值需要存儲(chǔ),因?yàn)槲覀儧]必要持久化存儲(chǔ)大部分的vuex數(shù)據(jù),所以沒必要進(jìn)行全量存儲(chǔ)。
我這里將數(shù)據(jù)結(jié)構(gòu)定義為數(shù)組:
const storageItem = [{storageType: 'local', // 存儲(chǔ)類型:local或者sessionstorageKey: 'name', // 存儲(chǔ)的keystorageValue: () => Store.getters.getName || '', // 需要存儲(chǔ)的值,也可以用 () => Store.state.name 這種形式storeMutations: 'SET_NAME' // vuex設(shè)置值時(shí)的mutations,用于頁面刷新完成之后初始化vuex}
]
每多一個(gè)需要持久化存儲(chǔ)的內(nèi)容,就增加一個(gè)元素即可。
2.存值
在頁面銷毀前存值我們可以直接在window的beforeunload回調(diào)中進(jìn)行即可
window.addEventListener('beforeunload', () => {storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragestorage.setItem(item.storageKey, item.storageValue())})})
也可以在vue組件的onUnmounted回調(diào)中進(jìn)行存儲(chǔ),但是這樣就需要你在vue組件中執(zhí)行這個(gè)邏輯了。當(dāng)然你也可以考慮將邏輯封裝為hooks。
3.取值
在頁面渲染前從storage中取到值,并且初始化vuex。
有一點(diǎn)可能要注意,我們從后端獲取一些全局?jǐn)?shù)據(jù)時(shí),一般會(huì)在routerBeforeEach中進(jìn)行接口調(diào)用。所以不建議在window的load回調(diào)中調(diào)用。我們執(zhí)行初始化盡量在routerBeforeEach之前執(zhí)行,這樣我們就可以判斷vuex如果存在值,就不用再調(diào)用接口了。
我這里在main.js中調(diào)用插件時(shí)執(zhí)行:
storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragelet storageValue = storage.getItem(item.storageKey)try {storageValue = JSON.parse(storageValue as string)} catch {}if (storageValue) {if (item.storeMutations) {Store.commit(item.storeMutations, storageValue)}}})
4.清空
我們可以提供一個(gè)清空的方法,便于某些時(shí)候清空所有的存儲(chǔ)(如果擔(dān)心數(shù)據(jù)時(shí)效性,可以設(shè)置一個(gè)時(shí)間,超出這個(gè)時(shí)間段之后就全部清空)
storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragestorage.removeItem(item.storageKey)})
三、具體代碼
1.定義插件
新建一個(gè)storeStorage.js
import Store from '@/store'
/*** 統(tǒng)一移除存儲(chǔ)的vuex數(shù)據(jù)*/
export const removeStoreStorage = () => {storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragestorage.removeItem(item.storageKey)})
}
// 持久化存儲(chǔ)相應(yīng)vuex數(shù)據(jù)
const storageItem = [{storageType: 'local', // 存儲(chǔ)類型:local或者sessionstorageKey: 'name', // 存儲(chǔ)的keystorageValue: () => Store.getters.getName || '', // 需要存儲(chǔ)的值storeMutations: 'SET_NAME' // vuex設(shè)置值時(shí)的mutations,用于頁面刷新完成之后初始化vuex}
]
export default {install() {this.getStoreStorage()this.setStoreStorage()},/*** 頁面銷毀前,存儲(chǔ)數(shù)據(jù)*/setStoreStorage() {window.addEventListener('beforeunload', () => {storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragestorage.setItem(item.storageKey, item.storageValue())})})},/*** 頁面刷新時(shí),重新加載存儲(chǔ)的vuex數(shù)據(jù)*/getStoreStorage() {storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragelet storageValue = storage.getItem(item.storageKey)try {storageValue = JSON.parse(storageValue as string)} catch {}if (storageValue) {if (item.storeMutations) {Store.commit(item.storeMutations, storageValue)}}})}
}
2.使用插件
在main.js
中引入,并使用
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import storeStorage from '@/util/storeStorage'
import store from './store'
const app = createApp(App)
app.use(store).use(router).use(storeStorage).mount('#app')
其中vuex中index.js
定義:
import { createStore } from 'vuex'export default createStore({state: {name: '',age: ''},getters: {getName: state => state.name,getAge: state => state.age},mutations: {SET_NAME(state, name) {state.name = name},SET_AGE(state, age) {state.age = age}},actions: {},modules: {}
})
四、最終效果
app.vue
中
<template><input type="text" v-model="$store.state.name"/>
</template><style lang="scss">
#app {color: #2c3e50;
}
</style>
<script setup lang="ts">
</script>
輸入內(nèi)容再刷新頁面就會(huì)發(fā)現(xiàn)值被緩存了。
注:插件、routerBeforeEach和window.load執(zhí)行順序
router.beforeEach((to, from, next) => {console.log('routerBeforeEach')next()
})
window.addEventListener('load', () => {console.log('load')
})
插件中的部分代碼
/*** 頁面刷新時(shí),重新加載存儲(chǔ)的vuex數(shù)據(jù)*/getStoreStorage() {storageItem.forEach(item => {const storage =item.storageType === 'session' ? sessionStorage : localStoragelet storageValue = storage.getItem(item.storageKey)try {storageValue = JSON.parse(storageValue as string)} catch {}if (storageValue) {if (item.storeMutations) {Store.commit(item.storeMutations, storageValue)}}})console.log('getStoreStorage')}
執(zhí)行結(jié)果: