vue3-vuex持久化实现
- 一、背景描述
- 二、实现思路
- 1.定义数据结构
- 2.存值
- 3.取值
- 4.清空
- 三、具体代码
- 1.定义插件
- 2.使用插件
- 四、最终效果
一、背景描述
有时候我们可能需要在vuex中存储一些静态数据,比如一些下拉选项的字典数据。这种数据基本很少会变化,所以我们可能希望将其存储起来,这样就减少了请求的数量。
但是在每个位置都进行存储,好像是在做重复的逻辑,所以我们可以考虑将这个功能提取出来,作为一个插件使用。
注意:建议不要滥用持久化存储,因为这可能导致你不能获取到最新的数据,只建议在一些长期不会变化的数据中使用。
二、实现思路
做到持久化存储,那就要在页面销毁之前将值存到storage中,页面初始化的时候,再将值取到vuex中进行数据初始化
1.定义数据结构
我们首先要规定哪些值需要存储,因为我们没必要持久化存储大部分的vuex数据,所以没必要进行全量存储。
我这里将数据结构定义为数组:
const storageItem = [
{
storageType: 'local', // 存储类型:local或者session
storageKey: 'name', // 存储的key
storageValue: () => Store.getters.getName || '', // 需要存储的值,也可以用 () => Store.state.name 这种形式
storeMutations: 'SET_NAME' // vuex设置值时的mutations,用于页面刷新完成之后初始化vuex
}
]
每多一个需要持久化存储的内容,就增加一个元素即可。
2.存值
在页面销毁前存值我们可以直接在window的beforeunload回调中进行即可
window.addEventListener('beforeunload', () => {
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
storage.setItem(item.storageKey, item.storageValue())
})
})
也可以在vue组件的onUnmounted回调中进行存储,但是这样就需要你在vue组件中执行这个逻辑了。当然你也可以考虑将逻辑封装为hooks。
3.取值
在页面渲染前从storage中取到值,并且初始化vuex。
有一点可能要注意,我们从后端获取一些全局数据时,一般会在routerBeforeEach中进行接口调用。所以不建议在window的load回调中调用。我们执行初始化尽量在routerBeforeEach之前执行,这样我们就可以判断vuex如果存在值,就不用再调用接口了。
我这里在main.js中调用插件时执行:
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
let storageValue = storage.getItem(item.storageKey)
try {
storageValue = JSON.parse(storageValue as string)
} catch {}
if (storageValue) {
if (item.storeMutations) {
Store.commit(item.storeMutations, storageValue)
}
}
})
4.清空
我们可以提供一个清空的方法,便于某些时候清空所有的存储(如果担心数据时效性,可以设置一个时间,超出这个时间段之后就全部清空)
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
storage.removeItem(item.storageKey)
})
三、具体代码
1.定义插件
新建一个storeStorage.js
import Store from '@/store'
/**
* 统一移除存储的vuex数据
*/
export const removeStoreStorage = () => {
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
storage.removeItem(item.storageKey)
})
}
// 持久化存储相应vuex数据
const storageItem = [
{
storageType: 'local', // 存储类型:local或者session
storageKey: 'name', // 存储的key
storageValue: () => Store.getters.getName || '', // 需要存储的值
storeMutations: 'SET_NAME' // vuex设置值时的mutations,用于页面刷新完成之后初始化vuex
}
]
export default {
install() {
this.getStoreStorage()
this.setStoreStorage()
},
/**
* 页面销毁前,存储数据
*/
setStoreStorage() {
window.addEventListener('beforeunload', () => {
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
storage.setItem(item.storageKey, item.storageValue())
})
})
},
/**
* 页面刷新时,重新加载存储的vuex数据
*/
getStoreStorage() {
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
let 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>
输入内容再刷新页面就会发现值被缓存了。
注:插件、routerBeforeEach和window.load执行顺序
router.beforeEach((to, from, next) => {
console.log('routerBeforeEach')
next()
})
window.addEventListener('load', () => {
console.log('load')
})
插件中的部分代码
/**
* 页面刷新时,重新加载存储的vuex数据
*/
getStoreStorage() {
storageItem.forEach(item => {
const storage =
item.storageType === 'session' ? sessionStorage : localStorage
let 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')
}
执行结果: