重构PWA状态管理

This commit is contained in:
jxxghp
2025-07-07 14:05:11 +08:00
parent 73d7eb65b8
commit 0cf3342449
8 changed files with 489 additions and 975 deletions

219
src/plugins/stateRestore.ts Normal file
View File

@@ -0,0 +1,219 @@
/**
* PWA状态恢复插件 - 极简版
* 只专注2个核心功能路由、标签页
*/
import type { App } from 'vue'
// =============================================================================
// 1. 路由状态管理器
// =============================================================================
class RouteStateManager {
private readonly STORAGE_KEY = 'pwa-current-route'
// 保存当前路由
saveCurrentRoute() {
const route = {
path: window.location.pathname,
search: window.location.search,
hash: window.location.hash,
timestamp: Date.now(),
}
sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(route))
}
// 恢复路由
restoreRoute() {
try {
const saved = sessionStorage.getItem(this.STORAGE_KEY)
if (!saved) return null
const route = JSON.parse(saved)
// 检查是否过期1小时
if (Date.now() - route.timestamp > 60 * 60 * 1000) {
this.clearRoute()
return null
}
return route
} catch {
return null
}
}
// 清除路由状态
clearRoute() {
sessionStorage.removeItem(this.STORAGE_KEY)
}
// 初始化路由恢复
init() {
// 监听路由变化,自动保存
window.addEventListener('popstate', () => this.saveCurrentRoute())
// 页面隐藏时保存
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.saveCurrentRoute()
}
})
// 页面卸载时保存
window.addEventListener('beforeunload', () => {
this.saveCurrentRoute()
})
}
}
// =============================================================================
// 2. 动态标签页状态管理器
// =============================================================================
class TabStateManager {
private readonly STORAGE_KEY = 'pwa-active-tabs'
// 保存标签页状态
saveTabState(routePath: string, activeTab: string) {
try {
const allTabs = this.getAllTabStates()
allTabs[routePath] = {
activeTab,
timestamp: Date.now(),
}
sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(allTabs))
} catch (error) {
console.warn('保存标签页状态失败:', error)
}
}
// 获取标签页状态
getTabState(routePath: string): string | null {
try {
const allTabs = this.getAllTabStates()
const tabState = allTabs[routePath]
if (!tabState) return null
// 检查是否过期1小时
if (Date.now() - tabState.timestamp > 60 * 60 * 1000) {
delete allTabs[routePath]
sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(allTabs))
return null
}
return tabState.activeTab
} catch {
return null
}
}
// 获取所有标签页状态
private getAllTabStates(): Record<string, any> {
try {
const saved = sessionStorage.getItem(this.STORAGE_KEY)
return saved ? JSON.parse(saved) : {}
} catch {
return {}
}
}
// 清除标签页状态
clearTabState(routePath?: string) {
if (routePath) {
const allTabs = this.getAllTabStates()
delete allTabs[routePath]
sessionStorage.setItem(this.STORAGE_KEY, JSON.stringify(allTabs))
} else {
sessionStorage.removeItem(this.STORAGE_KEY)
}
}
}
// =============================================================================
// 3. 主状态恢复管理器
// =============================================================================
class StateRestore {
public route = new RouteStateManager()
public tab = new TabStateManager()
// 初始化
init() {
this.route.init()
this.setupAutoRestore()
}
// 设置自动恢复
private setupAutoRestore() {
// 页面显示时检查是否需要恢复状态
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
this.checkAndRestore()
}
})
// 页面加载完成后恢复状态
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => this.checkAndRestore(), 100)
})
} else {
setTimeout(() => this.checkAndRestore(), 100)
}
}
// 检查并恢复状态
private checkAndRestore() {
// 1. 恢复路由(如果当前路径与保存的不同)
const savedRoute = this.route.restoreRoute()
if (savedRoute && savedRoute.path !== window.location.pathname) {
const fullPath = savedRoute.path + savedRoute.search + savedRoute.hash
console.log('恢复路由:', fullPath)
window.history.replaceState(null, '', fullPath)
}
// 2. 发送恢复事件,让组件自行处理标签页恢复
window.dispatchEvent(
new CustomEvent('pwa-state-restore', {
detail: {
route: savedRoute,
tabs: this.tab,
},
}),
)
}
// 清除所有状态
clearAllStates() {
this.route.clearRoute()
this.tab.clearTabState()
}
}
// =============================================================================
// 4. Vue插件安装
// =============================================================================
const stateRestore = new StateRestore()
export default {
install(app: App) {
// 注册全局属性
app.config.globalProperties.$stateRestore = stateRestore
// 提供注入
app.provide('stateRestore', stateRestore)
// 初始化
stateRestore.init()
console.log('PWA状态恢复插件已安装路由 + 标签页)')
},
}
// 导出管理器实例
export { stateRestore }
// 导出类型
export type { RouteStateManager, TabStateManager, StateRestore }