在开发环境的根组件App.vue中,定义组件对象创建以后的操作:将pinia的数据保存在浏览器的sessionStorage 中
<template>
<router-view />
</template>
<script>
import { usePiniaStore } from '@/piniaStore/index.js'
import CircularJSON from 'circular-json'
export default {
created() {
// pinia可持久化存储
var piniaStore = usePiniaStore()
// 添加监听页面加载的事件
window.addEventListener("beforeunload", () => {
window.sessionStorage.setItem("mianStore", CircularJSON.stringify(piniaStore.$state)) // 页面刷新时将pinia的数据转换为str保存在sessionSrtorage中
})
// 获取存储的pinia数据,并转换为js对象
if (window.sessionStorage.getItem("mianStore")) {
//将存储的pinia数据重新复制到pinia中
Object.assign(piniaStore.$state, CircularJSON.parse(window.sessionStorage.getItem("mianStore")))
}
}
}
</script>
<style></style>
之前项目使用vuex进行全局的状态管理,这种方式是可行的,后面改用pinia以后,在开发环境没毛病,上线部署以后就出问题:页面刷新导致数据丢失。使用pinia推荐的插件又报错,因为我的全局状态中存在的类型有的是对象,而插件本身是使用Json.parse和Json.stringify进行类型转换,所以会报错。
借鉴插件的实现原理,自定义一个pinia持久化保存的工具如下:
main.js
import { createApp, toRaw } from 'vue'
import CircularJSON from 'circular-json'
...
//先手写我们存储数据的localStorage
const getStorage = (key) => {
return sessionStorage.getItem(key) ? CircularJSON.parse(sessionStorage.getItem(key)) : {}
}
//存储数据
const setStorage = (key, value) => {
sessionStorage.setItem(key, CircularJSON.stringify(value)) //value可能是对象或者数组 所以JSON.stringify需要这个转换成字符串 ['1','2','3'] => '['1','2','3']'
}
//函数柯里化 柯里化就是将一个多参数的函数 转换成单参数的函数
const piniaPlugin = (options) => {
return (context) => { //拿取到pinpa的参数
console.log('context', context);
const { store } = context //解构我们需要的store
const data = getStorage(`${options?.key ?? __piniaKey__}-${store.$id}`) //获取到key
console.log('data', data);
//可以通过$subscribe监测到store数据变化
store.$subscribe(() => {
// 每当它发生变化时,将整个状态持久化到本地存储
//${options?.key ??__piniaKey__}-${store.$id} 唯一值key
setStorage(`${options?.key ?? __piniaKey__}-${store.$id}`, toRaw(store.$state)) //store.$state proxy对象 toRaw把它转为原始对象
})
return {
...data
}
}
}
const pinia = createPinia()
pinia.use(piniaPlugin({ key: 'pinia' }))
const app = createApp(App)
app.use(pinia)
....
效果:刷新页面以后: