状态持久化 #
为什么需要持久化? #
默认情况下,Vuex 的状态存储在内存中,页面刷新后状态会丢失。持久化可以将状态保存到本地存储中。
手动实现 #
基本实现 #
javascript
// store/index.js
import { createStore } from 'vuex'
// 从 localStorage 读取初始状态
const savedState = localStorage.getItem('vuex-state')
const initialState = savedState ? JSON.parse(savedState) : {
user: null,
token: null,
settings: {}
}
const store = createStore({
state: initialState,
mutations: {
SET_USER(state, user) {
state.user = user
},
SET_TOKEN(state, token) {
state.token = token
}
}
})
// 监听状态变化,保存到 localStorage
store.subscribe((mutation, state) => {
localStorage.setItem('vuex-state', JSON.stringify(state))
})
export default store
选择性持久化 #
javascript
// 只持久化特定字段
store.subscribe((mutation, state) => {
const persistedState = {
user: state.user,
token: state.token,
settings: state.settings
// 不保存 loading、error 等临时状态
}
localStorage.setItem('vuex-state', JSON.stringify(persistedState))
})
使用 vuex-persistedstate #
安装 #
bash
npm install vuex-persistedstate
基本使用 #
javascript
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
const store = createStore({
plugins: [
createPersistedState()
],
state: {
user: null,
token: null
}
})
配置选项 #
javascript
createPersistedState({
// 存储键名
key: 'my-app-store',
// 存储方式
storage: window.localStorage,
// 要持久化的状态路径
paths: ['user', 'token', 'settings.theme'],
// 过滤 mutation
filter: (mutation) => {
return !mutation.type.startsWith('temp/')
},
// 状态序列化
reducer: (state) => ({
user: state.user,
token: state.token
})
})
使用 sessionStorage #
javascript
createPersistedState({
storage: window.sessionStorage
})
自定义存储 #
javascript
createPersistedState({
storage: {
getItem: (key) => {
return JSON.parse(localStorage.getItem(key))
},
setItem: (key, value) => {
localStorage.setItem(key, JSON.stringify(value))
},
removeItem: (key) => {
localStorage.removeItem(key)
}
}
})
模块持久化 #
持久化特定模块 #
javascript
const store = createStore({
plugins: [
createPersistedState({
paths: ['user', 'settings']
})
],
modules: {
user: {
namespaced: true,
state: () => ({
profile: null,
token: null
})
},
settings: {
namespaced: true,
state: () => ({
theme: 'light',
language: 'en'
})
},
// 不持久化的模块
notifications: {
namespaced: true,
state: () => ({
items: []
})
}
}
})
每个模块独立持久化 #
javascript
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
const store = createStore({
plugins: [
// 用户模块持久化
createPersistedState({
key: 'user',
paths: ['user']
}),
// 设置模块持久化
createPersistedState({
key: 'settings',
paths: ['settings']
})
]
})
加密存储 #
使用 crypto-js #
bash
npm install crypto-js
javascript
import CryptoJS from 'crypto-js'
const SECRET_KEY = 'your-secret-key'
const encryptedStorage = {
getItem: (key) => {
const encrypted = localStorage.getItem(key)
if (!encrypted) return null
try {
const bytes = CryptoJS.AES.decrypt(encrypted, SECRET_KEY)
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8))
} catch {
return null
}
},
setItem: (key, value) => {
const encrypted = CryptoJS.AES.encrypt(
JSON.stringify(value),
SECRET_KEY
).toString()
localStorage.setItem(key, encrypted)
},
removeItem: (key) => {
localStorage.removeItem(key)
}
}
// 使用
createPersistedState({
storage: encryptedStorage
})
过期时间 #
实现过期机制 #
javascript
const storageWithExpiry = {
getItem: (key) => {
const itemStr = localStorage.getItem(key)
if (!itemStr) return null
const item = JSON.parse(itemStr)
const now = new Date()
// 检查是否过期
if (now.getTime() > item.expiry) {
localStorage.removeItem(key)
return null
}
return item.value
},
setItem: (key, value) => {
const now = new Date()
const item = {
value,
expiry: now.getTime() + 24 * 60 * 60 * 1000 // 24小时过期
}
localStorage.setItem(key, JSON.stringify(item))
},
removeItem: (key) => {
localStorage.removeItem(key)
}
}
createPersistedState({
storage: storageWithExpiry
})
实战示例 #
完整持久化方案 #
javascript
// store/plugins/persistence.js
import createPersistedState from 'vuex-persistedstate'
import CryptoJS from 'crypto-js'
const SECRET_KEY = import.meta.env.VITE_ENCRYPTION_KEY
const encryptedStorage = {
getItem: (key) => {
const encrypted = localStorage.getItem(key)
if (!encrypted) return null
try {
const bytes = CryptoJS.AES.decrypt(encrypted, SECRET_KEY)
const decrypted = bytes.toString(CryptoJS.enc.Utf8)
const item = JSON.parse(decrypted)
// 检查过期
if (item.expiry && Date.now() > item.expiry) {
localStorage.removeItem(key)
return null
}
return item.value
} catch {
return null
}
},
setItem: (key, value) => {
const item = {
value,
expiry: Date.now() + 7 * 24 * 60 * 60 * 1000 // 7天过期
}
const encrypted = CryptoJS.AES.encrypt(
JSON.stringify(item),
SECRET_KEY
).toString()
localStorage.setItem(key, encrypted)
},
removeItem: (key) => {
localStorage.removeItem(key)
}
}
export default createPersistedState({
key: 'app-state',
storage: encryptedStorage,
paths: [
'user.profile',
'user.token',
'settings.theme',
'settings.language'
],
filter: (mutation) => {
// 不保存临时状态变更
const excludeMutations = [
'SET_LOADING',
'SET_ERROR',
'CLEAR_ERROR'
]
return !excludeMutations.includes(mutation.type)
}
})
使用插件 #
javascript
// store/index.js
import { createStore } from 'vuex'
import persistence from './plugins/persistence'
import user from './modules/user'
import settings from './modules/settings'
export default createStore({
plugins: [persistence],
modules: {
user,
settings
}
})
最佳实践 #
1. 选择性持久化 #
javascript
// 只持久化必要的数据
paths: ['user.token', 'user.preferences']
// 不持久化敏感数据、临时状态
2. 加密敏感数据 #
javascript
// 敏感数据加密存储
storage: encryptedStorage
3. 设置过期时间 #
javascript
// 避免永久存储
expiry: Date.now() + 7 * 24 * 60 * 60 * 1000
4. 版本控制 #
javascript
const STORE_VERSION = '1.0.0'
const store = createStore({
plugins: [
createPersistedState({
key: `app-store-v${STORE_VERSION}`
})
]
})
总结 #
持久化要点:
| 方式 | 说明 |
|---|---|
| 手动实现 | 使用 subscribe + localStorage |
| vuex-persistedstate | 推荐的插件方案 |
| 选择性持久化 | 只保存必要数据 |
| 加密存储 | 敏感数据加密 |
| 过期机制 | 避免永久存储 |
继续学习 严格模式,了解如何开启严格模式。
最后更新:2026-03-28