一、安装依赖
需要安装 Pinia 及其持久化插件。你可以使用 npm
或 yarn
进行安装:
# 使用 npm
npm install pinia pinia-plugin-persistedstate
# 或使用 yarn
yarn add pinia pinia-plugin-persistedstate
二、全局配置(main.js
/ main.ts
)
在项目的入口文件中,初始化 Pinia 并注册持久化插件。以下是基本的配置步骤:
1. 基础配置
// main.js 或 main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from './App.vue';
// 创建 Pinia 实例
const pinia = createPinia();
// 注册持久化插件(全局启用,默认配置)
pinia.use(piniaPluginPersistedstate);
// 挂载 Vue 应用
const app = createApp(App);
app.use(pinia);
app.mount('#app');
2. 自定义插件配置(可选)
如果需要自定义持久化行为,可以在注册插件时传入配置对象。例如:
// main.js 或 main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import App from './App.vue';
// 创建 Pinia 实例
const pinia = createPinia();
// 自定义持久化插件配置
pinia.use(piniaPluginPersistedstate({
storage: sessionStorage, // 使用 sessionStorage 替代默认的 localStorage
key: (store) => `app_${store.$id}`, // 使用 store 的 id 作为存储键的前缀
paths: ['token', 'theme'], // 全局默认持久化字段(可覆盖单个 Store 的配置)
debug: true, // 开启调试模式,控制台输出日志
beforeHydrate: (context) => {
console.log('数据恢复前触发');
// 可以在这里添加自定义逻辑,例如修改即将加载的数据
},
afterHydrate: (context) => {
console.log('数据恢复后触发');
// 数据已经恢复完成,可以在这里执行其他操作
}
}));
// 挂载 Vue 应用
const app = createApp(App);
app.use(pinia);
app.mount('#app');
配置参数说明:
-
storage
: 指定使用的存储机制,默认为localStorage
。可以设置为sessionStorage
或其他自定义存储。 -
key
: 定义存储键的前缀。默认为。通过函数可以根据不同 store 动态生成键名。 -
paths
: 指定默认需要持久化的字段路径。如果不设置,默认持久化所有可序列化的字段。 -
debug
: 是否开启调试模式,开启后会在控制台输出相关日志,便于开发调试。 -
beforeHydrate
和afterHydrate
: 数据恢复前后的钩子函数,可以在其中执行一些自定义逻辑。
三、Store 定义(组合式 API)
Pinia 支持组合式 API,使得定义 store 更加简洁直观。下面展示如何在组合式 API 中配置持久化。
1. 基础配置(持久化全部字段)
// stores/user.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useUserStore = defineStore('user', () => {
// 状态定义
const token = ref(''); // 用户 token
const userInfo = ref(null); // 用户信息
const theme = ref('light'); // 主题模式
// 方法
function login() {
token.value = 'new-token-123';
userInfo.value = { name: 'John', age: 25 };
}
// 返回状态和方法
return { token, userInfo, theme, login };
}, {
persist: true // 默认存储到 localStorage,键为 'user'
});
说明:
-
defineStore
:定义一个名为'user'
的 store。第二个参数为状态和方法的定义,第三个参数为 store 的配置对象。 -
persist: true
:启用持久化功能,使用全局配置或默认设置。此时,整个 store 的所有可序列化字段将被持久化。
2. 高级配置(自定义存储策略)
// stores/user.js
export const useUserStore = defineStore('user', () => {
const token = ref('');
const userInfo = ref(null);
const theme = ref('light');
function login() {
token.value = 'new-token-123';
userInfo.value = { name: 'John', age: 25 };
}
return { token, userInfo, theme, login };
}, {
persist: {
storage: sessionStorage, // 使用 sessionStorage(默认是 localStorage)
key: 'custom-user-key', // 自定义存储键(默认是 store.)
paths: ['token', 'theme'], // 仅持久化 token 和 theme 字段
serializer: { // 自定义序列化与反序列化(处理非 JSON 数据)
serialize: (value) => JSON.stringify(value),
deserialize: (value) => JSON.parse(value)
}
}
});
高级配置说明:
-
storage
:指定持久化存储的位置,可以是localStorage
、sessionStorage
,甚至是自定义的存储机制。 -
key
:自定义存储键名,确保唯一性以避免覆盖。这里设置为'custom-user-key'
。 -
paths
:指定需要持久化的字段路径。仅token
和theme
会被持久化,userInfo
不会被保存。 -
serializer
:自定义序列化和反序列化方法。默认情况下,插件使用JSON.stringify
和JSON.parse
。对于复杂的数据类型(如Date
、Map
),可以通过自定义序列化器来处理。
四、Store 定义(选项式 API)
除了组合式 API,Pinia 也支持选项式 API,以下是选项式 API 的配置示例。
1. 基础配置(持久化全部字段)
// stores/user.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
token: '', // 用户 token
userInfo: null, // 用户信息
theme: 'light' // 主题模式
}),
actions: {
login() {
this.token = 'new-token-123';
this.userInfo = { name: 'John', age: 25 };
}
},
persist: true // 默认存储到 localStorage,键为 'user'
});
说明:
-
state
:定义 store 的状态。 -
actions
:定义 store 的方法。 -
persist: true
:启用基础持久化功能。
2. 高级配置(自定义存储策略)
// stores/user.js
export const useUserStore = defineStore('user', {
state: () => ({
token: '',
userInfo: null,
theme: 'light'
}),
actions: {
login() {
this.token = 'new-token-123';
this.userInfo = { name: 'John', age: 25 };
}
},
persist: {
storage: sessionStorage, // 使用 sessionStorage(默认是 localStorage)
key: 'custom-user-key', // 自定义存储键(默认是 store.)
paths: ['token', 'theme'], // 仅持久化 token 和 theme 字段
serializer: { // 自定义序列化与反序列化(处理非 JSON 数据)
serialize: (value) => JSON.stringify(value),
deserialize: (value) => JSON.parse(value)
}
}
});
说明:
与组合式 API 类似,选项式 API 也支持 persist
配置,用于自定义持久化行为。以上配置实现了仅持久化 token
和 theme
,并使用自定义的存储键 'custom-user-key'
。
五、组件中使用(组合式 API)
在组件中,可以使用组合式 API 引入并使用 store,同时提供清除本地存储的方法。以下是一个基于组合式 API 的示例组件。
User.vue(组合式 API)
<template>
<div>
<p>Token: {{ userStore.token }}</p>
<p>主题模式: {{ userStore.theme }}</p>
<button @click="userStore.login">登录</button>
<button @click="clearStorage">清除本地存储</button>
</div>
</template>
<script setup>
import { useUserStore } from '@/stores/user';
// 引入 Store
const userStore = useUserStore();
// 清除本地存储的方法
const clearStorage = () => {
localStorage.removeItem('user'); // 根据 persist.key 自定义键名,此处为默认值 'user'
};
</script>
说明:
-
使用
setup
语法糖引入 store。 -
userStore.token
和userStore.theme
直接绑定到模板中。 -
clearStorage
方法用于手动清除本地存储中的 store 数据。根据persist.key
的设置,可能需要调整键名。例如,如果使用了自定义键名'custom-user-key'
,则应相应地修改localStorage.removeItem
的参数。
六、组件中使用(选项式 API)
对于习惯选项式 API 的,也可以在组件中使用 store。以下是一个基于选项式 API 的示例组件。
User.vue(选项式 API)
<template>
<div>
<p>Token: {{ userStore.token }}</p>
<p>主题模式: {{ userStore.theme }}</p>
<button @click="userStore.login">登录</button>
<button @click="clearStorage">清除本地存储</button>
</div>
</template>
<script>
import { useUserStore } from '@/stores/user';
import { defineComponent } from 'vue';
export default defineComponent({
setup() {
const userStore = useUserStore();
return { userStore };
},
methods: {
clearStorage() {
localStorage.removeItem('user'); // 根据 persist.key 自定义键名,此处为默认值 'user'
}
}
});
</script>
说明:
-
使用
setup
函数引入 store,并通过返回对象将其暴露给模板。 -
clearStorage
方法定义在methods
中,同样根据persist.key
设置相应的存储键名。 -
如果使用了自定义键名,如
'custom-user-key'
,需将'user'
替换为对应的键名。例如:localStorage.removeItem('custom-user-key')
。
七、高级功能
pinia-plugin-persistedstate
提供了更多高级功能,以满足复杂的应用场景需求。以下是一些高级功能的详细说明和使用示例。
1. 选择性持久化字段(pick
/ omit
)
有时我们只需要持久化 store 中的部分字段,而不是全部。插件提供了 pick
和 omit
选项来实现这一点。这两个选项互斥,即使用其中一个时另一个将被忽略。
使用 pick
(仅持久化指定字段)
// stores/user.js(组合式 API)
export const useUserStore = defineStore('user', () => {
const token = ref('');
const userInfo = ref(null);
const theme = ref('light');
function login() { /* ... */ }
return { token, userInfo, theme, login };
}, {
persist: {
pick: ['token', 'theme'] // 仅持久化 token 和 theme,忽略 userInfo
// omit: ['userInfo'] // 如果使用 omit,效果相同,但两者不能同时使用
// key: 'custom-user-key', // 可选,自定义存储键名
// storage: sessionStorage, // 可选,自定义存储位置
// paths: [] // 如果使用 pick/omit,paths 将被忽略或覆盖
// ...其他配置项
}
});
示例解释:
-
pick: ['token', 'theme']
:表示只持久化token
和theme
,其他字段如userInfo
不会被持久化。这在敏感信息不需要持久化时非常有用。 -
omit
:如果你更倾向于指定哪些字段不持久化,可以使用omit
。例如,omit: ['userInfo']
达到的效果与pick: ['token', 'theme']
相同。注意两者不能同时使用。 -
优先级:当同时指定
pick
/omit
和paths
时,pick
/omit
将覆盖paths
。这是因为pick
/omit
更加明确地表达了意图。 -
存储键名与位置:可以结合使用自定义的
key
和storage
,以灵活控制数据的存储位置和命名。例如,将敏感数据存储到sessionStorage
,并使用不同的键名以区分不同类型的数据。 -
嵌套路径:如果需要更细粒度地选择字段路径,可以继续使用
paths
。不过通常在简单的场景中,pick
/omit
已经足够使用。例如,如果有一个嵌套的对象结构,可以使用类似['profile.name']
的路径来仅持久化特定的嵌套属性。但在本例中,由于没有嵌套结构,所以未使用paths
。如果有嵌套需求,可以在pick
/omit
同时使用paths
,具体取决于实际需求和插件的处理逻辑。一般来说,为了避免冲突,建议在使用时只选择一种方式来指定要持久化的字段。如果确实需要同时使用,应该仔细测试以确保它们按预期工作。此外,插件文档通常会有详细的优先级和使用说明,建议参考官方文档以获取最新和最准确的信息。在实际项目中,根据团队的习惯和项目的复杂度选择合适的字段选择方式。对于简单项目,可能只需要基础的持久化配置;而对于复杂的应用,可能需要更精细地控制哪些数据被持久化以及如何存储这些数据。通过合理配置pinia-plugin-persistedstate
,可以有效地管理应用的状态持久化需求,提升用户体验和应用的稳定性。