<!-- App.vue -->
<template>
<div id="app">
<keep-alive :include="cachedComponents">
<router-view />
</keep-alive>
</div>
</template>
<script>
export default {
data() {
return {
cachedComponents: ['Home', 'UserList'] // 要缓存的组件名
}
}
}
</script>
// router/index.js
const routes = [
{
path: '/home',
name: 'Home',
component: () => import('./views/Home.vue'),
meta: {
keepAlive: true // 需要缓存
}
},
{
path: '/login',
name: 'Login',
component: () => import('./views/Login.vue'),
meta: {
keepAlive: false // 不需要缓存
}
}
]
<!-- App.vue -->
<template>
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />
</template>
<script>
export default {
name: 'MyComponent',
activated() {
// 组件被激活时调用
console.log('组件被激活,恢复状态')
},
deactivated() {
// 组件被停用时调用
console.log('组件被停用,保存状态')
}
}
</script>
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
user: null,
settings: {}
}
const mutations = {
SET_USER(state, user) {
state.user = user
// 保存到 localStorage
if (user) {
localStorage.setItem('user', JSON.stringify(user))
} else {
localStorage.removeItem('user')
}
},
LOAD_PERSISTED_STATE(state) {
// 加载持久化状态
const user = localStorage.getItem('user')
if (user) {
state.user = JSON.parse(user)
}
}
}
export default new Vuex.Store({
state,
mutations,
// 可选:使用插件自动持久化
plugins: [
store => {
// 初始化时加载
store.commit('LOAD_PERSISTED_STATE')
// 监听变化并保存
store.subscribe((mutation, state) => {
if (mutation.type === 'SET_USER') {
localStorage.setItem('user', JSON.stringify(state.user))
}
})
}
]
})
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
lastVisited: null
}),
actions: {
increment() {
this.count++
this.saveToStorage()
},
saveToStorage() {
localStorage.setItem('counterStore', JSON.stringify(this.$state))
},
loadFromStorage() {
const saved = localStorage.getItem('counterStore')
if (saved) {
this.$state = JSON.parse(saved)
}
}
}
})
// utils/storage.js
class StorageHelper {
constructor(namespace = 'app') {
this.namespace = namespace
}
set(key, value) {
const data = this.getAll()
data[key] = value
localStorage.setItem(this.namespace, JSON.stringify(data))
}
get(key, defaultValue = null) {
const data = this.getAll()
return data[key] || defaultValue
}
getAll() {
const data = localStorage.getItem(this.namespace)
return data ? JSON.parse(data) : {}
}
remove(key) {
const data = this.getAll()
delete data[key]
localStorage.setItem(this.namespace, JSON.stringify(data))
}
clear() {
localStorage.removeItem(this.namespace)
}
}
// 使用示例
const pageStorage = new StorageHelper('pageState')
// 在组件中使用
export default {
data() {
return {
formData: {}
}
},
created() {
// 加载保存的状态
const saved = pageStorage.get(this.$route.path)
if (saved) {
this.formData = saved
}
},
methods: {
saveForm() {
// 保存状态
pageStorage.set(this.$route.path, this.formData)
}
},
beforeRouteLeave(to, from, next) {
// 离开页面时保存状态
pageStorage.set(from.path, this.formData)
next()
}
}
// router/index.js
const router = new VueRouter({ ... })
// 页面状态管理器
const pageStateManager = {
saveState(route, state) {
const key = `page_state_${route.path}`
localStorage.setItem(key, JSON.stringify(state))
},
loadState(route) {
const key = `page_state_${route.path}`
const saved = localStorage.getItem(key)
return saved ? JSON.parse(saved) : null
},
clearState(route) {
const key = `page_state_${route.path}`
localStorage.removeItem(key)
}
}
// 全局路由守卫
router.beforeEach((to, from, next) => {
// 如果需要保存离开页面的状态
if (from.matched.some(record => record.meta.saveState)) {
const component = router.app.$children.find(
child => child.$vnode && child.$vnode.tag.includes(from.name)
)
if (component && component.getPageState) {
const state = component.getPageState()
pageStateManager.saveState(from, state)
}
}
// 如果需要恢复目标页面的状态
if (to.matched.some(record => record.meta.restoreState)) {
const savedState = pageStateManager.loadState(to)
to.meta.savedState = savedState
}
next()
})
<template>
<div>
<!-- 表单组件 -->
<input v-model="formData.name" />
<input v-model="formData.email" />
<button @click="saveForm">保存</button>
</div>
</template>
<script>
import { debounce } from 'lodash'
export default {
name: 'MyFormPage',
data() {
return {
formData: {
name: '',
email: ''
},
isDataLoaded: false
}
},
created() {
this.loadSavedData()
// 防抖保存
this.debouncedSave = debounce(this.autoSave, 1000)
},
activated() {
// keep-alive 激活时调用
if (!this.isDataLoaded) {
this.loadSavedData()
}
},
deactivated() {
// keep-alive 停用时自动保存
this.autoSave()
},
methods: {
loadSavedData() {
// 从多个源加载数据
const savedData =
localStorage.getItem(`form_${this.$route.path}`) ||
this.$store.getters.getPageState(this.$route.path)
if (savedData) {
this.formData = JSON.parse(savedData)
this.isDataLoaded = true
}
},
saveForm() {
// 保存到本地存储
localStorage.setItem(
`form_${this.$route.path}`,
JSON.stringify(this.formData)
)
// 保存到 Vuex
this.$store.commit('SAVE_PAGE_STATE', {
path: this.$route.path,
data: this.formData
})
},
autoSave() {
if (this.formData.name || this.formData.email) {
localStorage.setItem(
`form_${this.$route.path}_autosave`,
JSON.stringify(this.formData)
)
}
}
},
watch: {
formData: {
deep: true,
handler() {
this.debouncedSave()
}
}
}
}
</script>
npm install vuex-persistedstate
import createPersistedState from 'vuex-persistedstate'
export default new Vuex.Store({
// ...
plugins: [
createPersistedState({
key: 'vuex',
storage: window.localStorage,
reducer: (state) => ({
user: state.user,
settings: state.settings
})
})
]
})
npm install pinia-plugin-persistedstate
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
// 在 store 中使用
export const useUserStore = defineStore('user', {
state: () => ({
user: null
}),
persist: {
enabled: true,
strategies: [
{
key: 'user',
storage: localStorage
}
]
}
})
keep-alive
用户数据持久化:使用 Vuex/Pinia + 本地存储
表单状态临时保存:使用路由守卫 + sessionStorage
复杂应用:混合使用多种方案
SEO敏感页面:避免使用 keep-alive,改用服务端存储
根据具体需求选择合适的方案或组合使用多种方案,可以实现更灵活的状态管理。