mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-28 03:27:54 +08:00
Remove console logs for silent PWA state restoration optimization
Co-authored-by: jxxghp <jxxghp@163.com>
This commit is contained in:
@@ -1,180 +0,0 @@
|
|||||||
# PWA 后台切换前台体验优化 - 修改总结
|
|
||||||
|
|
||||||
## 已完成的修改
|
|
||||||
|
|
||||||
### 1. 优化PWA状态管理器 (`src/utils/pwaStateManager.ts`)
|
|
||||||
|
|
||||||
#### 1.1 增强PWAStateController类
|
|
||||||
- 添加了状态恢复等待机制 (`waitForStateRestore()`)
|
|
||||||
- 添加了状态恢复状态跟踪 (`isRestoringState`)
|
|
||||||
- 改进了状态恢复流程,确保异步操作完成后才通知应用
|
|
||||||
- 添加了详细的日志记录,便于调试
|
|
||||||
|
|
||||||
#### 1.2 改进VisibilityStateManager类
|
|
||||||
- 添加了轻量级状态恢复指示器
|
|
||||||
- 改进了页面可见性处理逻辑
|
|
||||||
- 添加了防重入机制,避免重复恢复
|
|
||||||
- 优化了状态恢复的用户体验
|
|
||||||
|
|
||||||
### 2. 优化应用初始化 (`src/main.ts`)
|
|
||||||
|
|
||||||
#### 2.1 提前初始化PWA状态管理器
|
|
||||||
- 在Vue应用挂载前初始化PWA状态管理器
|
|
||||||
- 等待状态恢复完成后再挂载应用
|
|
||||||
- 确保PWA状态在应用启动时就已经准备就绪
|
|
||||||
|
|
||||||
#### 2.2 改进事件监听器设置
|
|
||||||
- 优化了状态恢复事件监听
|
|
||||||
- 移除了重复的初始化逻辑
|
|
||||||
- 简化了代码结构
|
|
||||||
|
|
||||||
### 3. 优化加载界面管理 (`src/App.vue`)
|
|
||||||
|
|
||||||
#### 3.1 智能加载界面移除
|
|
||||||
- 创建了`removeLoadingWithStateCheck()`函数
|
|
||||||
- 确保PWA状态恢复完成后才移除加载界面
|
|
||||||
- 添加了多重检查机制,包括全局设置和背景图片加载
|
|
||||||
|
|
||||||
#### 3.2 改进加载动画
|
|
||||||
- 添加了更平滑的加载完成动画
|
|
||||||
- 优化了过渡效果
|
|
||||||
- 添加了PWA状态恢复的视觉反馈
|
|
||||||
|
|
||||||
#### 3.3 增强样式和过渡效果
|
|
||||||
- 添加了PWA过渡效果类
|
|
||||||
- 优化了加载完成动画
|
|
||||||
- 改进了用户体验
|
|
||||||
|
|
||||||
### 4. 优化Service Worker缓存策略 (`vite.config.ts`)
|
|
||||||
|
|
||||||
#### 4.1 启用导航预加载
|
|
||||||
- 在Workbox配置中启用了导航预加载
|
|
||||||
- 提高了页面加载性能
|
|
||||||
|
|
||||||
#### 4.2 改进缓存策略
|
|
||||||
- 将页面缓存策略从`NetworkFirst`改为`StaleWhileRevalidate`
|
|
||||||
- 添加了缓存键优化,提高缓存命中率
|
|
||||||
- 忽略状态参数,避免缓存污染
|
|
||||||
|
|
||||||
### 5. 增强Service Worker功能 (`src/service-worker.ts`)
|
|
||||||
|
|
||||||
#### 5.1 添加状态预缓存
|
|
||||||
- 在Service Worker安装时预缓存关键状态数据
|
|
||||||
- 添加了错误处理机制
|
|
||||||
|
|
||||||
#### 5.2 改进激活事件
|
|
||||||
- 启用导航预加载功能
|
|
||||||
- 添加了缓存清理逻辑
|
|
||||||
- 优化了Service Worker生命周期管理
|
|
||||||
|
|
||||||
### 6. 创建加载状态管理器 (`src/utils/loadingStateManager.ts`)
|
|
||||||
|
|
||||||
#### 6.1 智能加载状态协调
|
|
||||||
- 创建了`PWALoadingStateManager`类
|
|
||||||
- 提供了统一的加载状态管理
|
|
||||||
- 支持多组件加载状态协调
|
|
||||||
|
|
||||||
#### 6.2 加载状态监听
|
|
||||||
- 添加了状态变化监听器
|
|
||||||
- 提供了等待所有加载完成的机制
|
|
||||||
- 支持状态重置和详细状态查询
|
|
||||||
|
|
||||||
## 关键特性
|
|
||||||
|
|
||||||
### 1. 状态恢复等待机制
|
|
||||||
- 应用在PWA状态恢复完成前不会显示
|
|
||||||
- 避免了用户看到不一致的状态
|
|
||||||
- 确保了平滑的用户体验
|
|
||||||
|
|
||||||
### 2. 轻量级状态恢复指示器
|
|
||||||
- 在页面可见性切换时显示轻量级指示器
|
|
||||||
- 避免了重新显示完整的加载界面
|
|
||||||
- 提供了即时的用户反馈
|
|
||||||
|
|
||||||
### 3. 智能缓存策略
|
|
||||||
- 优化了页面和资源的缓存策略
|
|
||||||
- 启用了导航预加载功能
|
|
||||||
- 提高了应用响应速度
|
|
||||||
|
|
||||||
### 4. 详细的日志记录
|
|
||||||
- 添加了全面的日志记录
|
|
||||||
- 便于调试和性能监控
|
|
||||||
- 提供了状态恢复过程的可见性
|
|
||||||
|
|
||||||
## 预期效果
|
|
||||||
|
|
||||||
### 1. 消除界面闪烁
|
|
||||||
- ✅ 状态恢复完成后才显示界面
|
|
||||||
- ✅ 避免了用户看到不一致的状态
|
|
||||||
- ✅ 提供了平滑的过渡效果
|
|
||||||
|
|
||||||
### 2. 提升加载性能
|
|
||||||
- ✅ 智能缓存策略减少了网络请求
|
|
||||||
- ✅ 导航预加载提高了响应速度
|
|
||||||
- ✅ 多重加载状态协调确保了资源就绪
|
|
||||||
|
|
||||||
### 3. 改善用户体验
|
|
||||||
- ✅ 添加了过渡动画和视觉反馈
|
|
||||||
- ✅ 轻量级指示器替代了完整加载界面
|
|
||||||
- ✅ 状态恢复过程更加透明
|
|
||||||
|
|
||||||
### 4. 接近原生体验
|
|
||||||
- ✅ 快速的状态恢复
|
|
||||||
- ✅ 平滑的切换动画
|
|
||||||
- ✅ 即时的用户反馈
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
### 1. 开发环境测试
|
|
||||||
1. 启动开发服务器:`npm run dev`
|
|
||||||
2. 在浏览器中打开应用
|
|
||||||
3. 使用开发者工具测试PWA功能
|
|
||||||
4. 检查控制台日志,确认状态恢复过程
|
|
||||||
|
|
||||||
### 2. 真机测试
|
|
||||||
1. 构建生产版本:`npm run build`
|
|
||||||
2. 部署到服务器或使用本地服务器
|
|
||||||
3. 在移动设备上安装PWA
|
|
||||||
4. 测试后台切换前台的各种场景
|
|
||||||
|
|
||||||
### 3. 性能监控
|
|
||||||
- 使用Chrome DevTools监控性能
|
|
||||||
- 检查状态恢复时间
|
|
||||||
- 监控内存使用情况
|
|
||||||
- 验证缓存策略效果
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
### 1. 兼容性
|
|
||||||
- 确保在不同浏览器上测试
|
|
||||||
- 特别关注iOS Safari和Android Chrome
|
|
||||||
- 测试不同版本的Service Worker支持
|
|
||||||
|
|
||||||
### 2. 性能
|
|
||||||
- 监控状态恢复的性能影响
|
|
||||||
- 避免过度的状态保存
|
|
||||||
- 定期清理过期的状态数据
|
|
||||||
|
|
||||||
### 3. 用户体验
|
|
||||||
- 确保状态恢复不会影响用户操作
|
|
||||||
- 提供适当的加载反馈
|
|
||||||
- 处理网络异常情况
|
|
||||||
|
|
||||||
## 后续优化建议
|
|
||||||
|
|
||||||
### 1. 高级功能
|
|
||||||
- 添加骨架屏支持
|
|
||||||
- 实现智能状态压缩
|
|
||||||
- 添加状态恢复统计
|
|
||||||
|
|
||||||
### 2. 性能优化
|
|
||||||
- 实现增量状态更新
|
|
||||||
- 优化状态序列化
|
|
||||||
- 添加状态恢复缓存
|
|
||||||
|
|
||||||
### 3. 用户体验
|
|
||||||
- 添加自定义状态恢复动画
|
|
||||||
- 实现状态恢复进度指示
|
|
||||||
- 支持用户自定义状态恢复偏好
|
|
||||||
|
|
||||||
这些修改将显著提升PWA应用从后台切换到前台时的用户体验,使其更接近原生应用的表现。
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
# PWA 后台切换前台体验优化分析报告
|
|
||||||
|
|
||||||
## 问题描述
|
|
||||||
|
|
||||||
从后台切换到前台时会显示加载界面,同时界面会有闪烁,切换的体验不是很好,跟原生APP还有差距。
|
|
||||||
|
|
||||||
## 问题分析
|
|
||||||
|
|
||||||
### 1. 核心问题原因
|
|
||||||
|
|
||||||
#### 1.1 状态恢复时机不当
|
|
||||||
- **PWA状态管理器初始化延迟**:在 `main.ts` 中,PWA状态管理器的初始化是在Vue应用挂载后进行的
|
|
||||||
- **异步状态恢复**:状态恢复是异步的,不会阻塞应用渲染,导致用户先看到初始状态
|
|
||||||
- **渲染完成检测不准确**:`ensureRenderComplete` 只检测Vue组件渲染完成,未考虑PWA状态恢复
|
|
||||||
|
|
||||||
#### 1.2 加载界面移除时机过早
|
|
||||||
```typescript
|
|
||||||
// 在App.vue中的问题代码
|
|
||||||
ensureRenderComplete(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
// 移除加载动画,显示页面
|
|
||||||
animateAndRemoveLoader()
|
|
||||||
// 页面完全显示后,检查未读消息
|
|
||||||
checkAndEmitUnreadMessages()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
加载界面在Vue组件渲染完成后立即移除,但此时:
|
|
||||||
- PWA状态尚未恢复
|
|
||||||
- 用户界面状态可能不完整
|
|
||||||
- 导致用户看到不一致的状态
|
|
||||||
|
|
||||||
#### 1.3 Service Worker状态同步延迟
|
|
||||||
Service Worker中的状态恢复通过消息传递实现,存在延迟:
|
|
||||||
```typescript
|
|
||||||
// 在service-worker.ts中
|
|
||||||
self.addEventListener('message', function (event) {
|
|
||||||
if (event.data && event.data.type === 'GET_PWA_STATE') {
|
|
||||||
getStateFromCache()
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(state => {
|
|
||||||
event.ports[0]?.postMessage({ state })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 具体表现
|
|
||||||
|
|
||||||
1. **界面闪烁**:
|
|
||||||
- 用户首先看到默认状态
|
|
||||||
- 然后看到状态恢复过程
|
|
||||||
- 最后看到完整的恢复状态
|
|
||||||
|
|
||||||
2. **加载界面显示**:
|
|
||||||
- 从后台切换到前台时,某些组件可能需要重新渲染
|
|
||||||
- 背景图片需要重新加载
|
|
||||||
- 网络请求需要重新发起
|
|
||||||
|
|
||||||
3. **状态不一致**:
|
|
||||||
- 滚动位置不对
|
|
||||||
- 表单数据丢失
|
|
||||||
- 用户选择状态丢失
|
|
||||||
|
|
||||||
## 解决方案建议
|
|
||||||
|
|
||||||
### 1. 优化状态恢复时机
|
|
||||||
|
|
||||||
#### 1.1 提前初始化PWA状态管理器
|
|
||||||
```typescript
|
|
||||||
// 修改main.ts,在应用挂载前初始化
|
|
||||||
const initializePWABeforeMount = async () => {
|
|
||||||
const isPWA = window.matchMedia('(display-mode: standalone)').matches ||
|
|
||||||
(window.navigator as any).standalone ||
|
|
||||||
document.referrer.includes('android-app://')
|
|
||||||
|
|
||||||
if (isPWA) {
|
|
||||||
console.log('检测到PWA模式,预初始化状态管理器')
|
|
||||||
const pwaStateController = new PWAStateController()
|
|
||||||
|
|
||||||
// 等待状态恢复完成
|
|
||||||
await pwaStateController.waitForStateRestore()
|
|
||||||
|
|
||||||
// 将状态管理器绑定到全局对象
|
|
||||||
;(window as any).pwaStateController = pwaStateController
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在创建Vue应用前调用
|
|
||||||
const pwaInitialized = await initializePWABeforeMount()
|
|
||||||
const app = createApp(App)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 1.2 实现状态恢复等待机制
|
|
||||||
```typescript
|
|
||||||
// 在PWAStateController中添加
|
|
||||||
export class PWAStateController {
|
|
||||||
private stateRestorePromise: Promise<void> | null = null
|
|
||||||
private stateRestoreResolve: (() => void) | null = null
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.stateRestorePromise = new Promise((resolve) => {
|
|
||||||
this.stateRestoreResolve = resolve
|
|
||||||
})
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForStateRestore(): Promise<void> {
|
|
||||||
return this.stateRestorePromise
|
|
||||||
}
|
|
||||||
|
|
||||||
private async checkAndRestoreState(): Promise<void> {
|
|
||||||
// 现有的状态恢复逻辑
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// 状态恢复完成后解决Promise
|
|
||||||
if (this.stateRestoreResolve) {
|
|
||||||
this.stateRestoreResolve()
|
|
||||||
this.stateRestoreResolve = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 优化加载界面管理
|
|
||||||
|
|
||||||
#### 2.1 条件化加载界面移除
|
|
||||||
```typescript
|
|
||||||
// 修改App.vue中的加载界面移除逻辑
|
|
||||||
const removeLoadingWithStateCheck = async () => {
|
|
||||||
// 检查PWA状态是否已恢复
|
|
||||||
const pwaController = (window as any).pwaStateController
|
|
||||||
if (pwaController) {
|
|
||||||
await pwaController.waitForStateRestore()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保关键资源已加载
|
|
||||||
await Promise.all([
|
|
||||||
// 等待背景图片加载完成
|
|
||||||
loadBackgroundImages(),
|
|
||||||
// 等待关键API数据加载完成
|
|
||||||
loadCriticalData()
|
|
||||||
])
|
|
||||||
|
|
||||||
// 移除加载界面
|
|
||||||
animateAndRemoveLoader()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
await globalSettingsStore.initialize()
|
|
||||||
configureApexCharts()
|
|
||||||
updateHtmlThemeAttribute(globalTheme.name.value)
|
|
||||||
|
|
||||||
// 使用优化后的加载界面移除逻辑
|
|
||||||
ensureRenderComplete(() => {
|
|
||||||
nextTick(removeLoadingWithStateCheck)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2.2 实现智能加载状态检测
|
|
||||||
```typescript
|
|
||||||
// 新增工具函数
|
|
||||||
export class PWALoadingStateManager {
|
|
||||||
private loadingStates: Map<string, boolean> = new Map()
|
|
||||||
|
|
||||||
setLoadingState(key: string, loading: boolean) {
|
|
||||||
this.loadingStates.set(key, loading)
|
|
||||||
}
|
|
||||||
|
|
||||||
isAnyLoading(): boolean {
|
|
||||||
return Array.from(this.loadingStates.values()).some(loading => loading)
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForAllComplete(): Promise<void> {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
const checkComplete = () => {
|
|
||||||
if (!this.isAnyLoading()) {
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
setTimeout(checkComplete, 100)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
checkComplete()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 优化页面可见性处理
|
|
||||||
|
|
||||||
#### 3.1 改进页面可见性监听
|
|
||||||
```typescript
|
|
||||||
// 修改VisibilityStateManager
|
|
||||||
export class VisibilityStateManager {
|
|
||||||
private isRestoring = false
|
|
||||||
private restorePromise: Promise<void> | null = null
|
|
||||||
|
|
||||||
private handlePageVisible(): void {
|
|
||||||
if (this.isRestoring) return
|
|
||||||
|
|
||||||
this.isRestoring = true
|
|
||||||
this.restorePromise = this.performStateRestore()
|
|
||||||
}
|
|
||||||
|
|
||||||
private async performStateRestore(): Promise<void> {
|
|
||||||
try {
|
|
||||||
// 显示恢复指示器
|
|
||||||
this.showRestoreIndicator()
|
|
||||||
|
|
||||||
const restoredState = this.stateManager.restoreState()
|
|
||||||
if (restoredState) {
|
|
||||||
await this.restoreAppState(restoredState)
|
|
||||||
console.log('页面显示,已恢复状态')
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.isRestoring = false
|
|
||||||
this.hideRestoreIndicator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private showRestoreIndicator(): void {
|
|
||||||
// 显示轻量级的状态恢复指示器,而不是完整的加载界面
|
|
||||||
const indicator = document.createElement('div')
|
|
||||||
indicator.id = 'pwa-restore-indicator'
|
|
||||||
indicator.innerHTML = `
|
|
||||||
<div class="restore-indicator">
|
|
||||||
<div class="restore-spinner"></div>
|
|
||||||
<div class="restore-text">正在恢复状态...</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
document.body.appendChild(indicator)
|
|
||||||
}
|
|
||||||
|
|
||||||
private hideRestoreIndicator(): void {
|
|
||||||
const indicator = document.getElementById('pwa-restore-indicator')
|
|
||||||
if (indicator) {
|
|
||||||
indicator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 优化Service Worker缓存策略
|
|
||||||
|
|
||||||
#### 4.1 改进缓存预热
|
|
||||||
```typescript
|
|
||||||
// 修改vite.config.ts中的PWA配置
|
|
||||||
VitePWA({
|
|
||||||
workbox: {
|
|
||||||
// 添加导航预加载
|
|
||||||
navigationPreload: true,
|
|
||||||
// 优化缓存策略
|
|
||||||
runtimeCaching: [
|
|
||||||
{
|
|
||||||
urlPattern: ({ request }) => request.destination === 'document',
|
|
||||||
handler: 'StaleWhileRevalidate', // 改为更快的策略
|
|
||||||
options: {
|
|
||||||
cacheName: 'pages-cache',
|
|
||||||
cacheKeyWillBeUsed: async ({ request }) => {
|
|
||||||
// 忽略状态参数,提高缓存命中率
|
|
||||||
const url = new URL(request.url)
|
|
||||||
url.searchParams.delete('restored')
|
|
||||||
return url.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4.2 实现状态预缓存
|
|
||||||
```typescript
|
|
||||||
// 在service-worker.ts中添加
|
|
||||||
self.addEventListener('install', event => {
|
|
||||||
event.waitUntil(
|
|
||||||
(async () => {
|
|
||||||
// 预缓存关键状态数据
|
|
||||||
const cache = await caches.open(STATE_CACHE_NAME)
|
|
||||||
const existingState = await cache.match(STATE_ENDPOINT)
|
|
||||||
|
|
||||||
if (existingState) {
|
|
||||||
// 预热状态数据
|
|
||||||
const state = await existingState.json()
|
|
||||||
console.log('预缓存状态数据:', state)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 增强用户体验
|
|
||||||
|
|
||||||
#### 5.1 添加过渡动画
|
|
||||||
```scss
|
|
||||||
// 添加到App.vue的样式中
|
|
||||||
.pwa-transition {
|
|
||||||
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pwa-restoring {
|
|
||||||
opacity: 0.8;
|
|
||||||
transform: scale(0.98);
|
|
||||||
}
|
|
||||||
|
|
||||||
.restore-indicator {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
z-index: 10000;
|
|
||||||
background: rgba(0, 0, 0, 0.8);
|
|
||||||
color: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.restore-spinner {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
border-top: 2px solid white;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes spin {
|
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5.2 实现骨架屏
|
|
||||||
```vue
|
|
||||||
<!-- 添加到App.vue中 -->
|
|
||||||
<template>
|
|
||||||
<div class="app-wrapper">
|
|
||||||
<!-- 骨架屏 -->
|
|
||||||
<div v-if="isRestoring" class="skeleton-screen">
|
|
||||||
<div class="skeleton-header"></div>
|
|
||||||
<div class="skeleton-content">
|
|
||||||
<div class="skeleton-line"></div>
|
|
||||||
<div class="skeleton-line"></div>
|
|
||||||
<div class="skeleton-line short"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 主要内容 -->
|
|
||||||
<VApp v-else :class="{ 'transparent-app': isTransparentTheme }">
|
|
||||||
<RouterView />
|
|
||||||
</VApp>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 实施建议
|
|
||||||
|
|
||||||
### 优先级排序
|
|
||||||
|
|
||||||
1. **高优先级**:
|
|
||||||
- 优化状态恢复时机
|
|
||||||
- 改进加载界面管理
|
|
||||||
- 实现状态恢复等待机制
|
|
||||||
|
|
||||||
2. **中优先级**:
|
|
||||||
- 优化页面可见性处理
|
|
||||||
- 添加过渡动画
|
|
||||||
- 改进Service Worker缓存策略
|
|
||||||
|
|
||||||
3. **低优先级**:
|
|
||||||
- 实现骨架屏
|
|
||||||
- 添加高级用户体验功能
|
|
||||||
|
|
||||||
### 测试建议
|
|
||||||
|
|
||||||
1. **真机测试**:
|
|
||||||
- 在iOS Safari上测试PWA模式
|
|
||||||
- 在Android Chrome上测试PWA模式
|
|
||||||
- 测试后台切换前台的各种场景
|
|
||||||
|
|
||||||
2. **性能测试**:
|
|
||||||
- 使用Chrome DevTools监控状态恢复性能
|
|
||||||
- 测试不同网络状况下的表现
|
|
||||||
- 监控内存使用情况
|
|
||||||
|
|
||||||
3. **用户体验测试**:
|
|
||||||
- 测试快速切换应用场景
|
|
||||||
- 测试长时间后台后的恢复
|
|
||||||
- 测试网络断开重连场景
|
|
||||||
|
|
||||||
## 预期效果
|
|
||||||
|
|
||||||
实施以上优化后,预期能够:
|
|
||||||
|
|
||||||
1. **消除界面闪烁**:状态恢复完成后再显示界面
|
|
||||||
2. **减少加载时间**:智能预加载和缓存策略
|
|
||||||
3. **提升用户体验**:平滑的过渡动画和反馈
|
|
||||||
4. **接近原生体验**:快速的状态恢复和响应
|
|
||||||
|
|
||||||
这些优化将显著提升PWA应用从后台切换到前台时的体验,使其更接近原生应用的表现。
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
# PWA 静默优化总结 - 完全无感的后台切换体验
|
|
||||||
|
|
||||||
## 优化目标
|
|
||||||
|
|
||||||
实现PWA应用从后台切换到前台时的**完全无感体验**,不显示任何指示器或加载界面,让用户感觉不到任何延迟或状态恢复过程。
|
|
||||||
|
|
||||||
## 核心优化策略
|
|
||||||
|
|
||||||
### 1. 静默状态恢复
|
|
||||||
- ✅ **移除所有视觉指示器**:不显示任何状态恢复提示
|
|
||||||
- ✅ **后台静默处理**:状态恢复在后台完全静默进行
|
|
||||||
- ✅ **即时响应**:用户操作不会被阻塞或延迟
|
|
||||||
|
|
||||||
### 2. 智能状态管理
|
|
||||||
- ✅ **宽松的恢复策略**:即使URL不完全匹配也尝试恢复合适的状态
|
|
||||||
- ✅ **选择性状态恢复**:只在合适的情况下恢复特定状态(如滚动位置)
|
|
||||||
- ✅ **延长状态有效期**:从30分钟延长到60分钟
|
|
||||||
|
|
||||||
### 3. 性能优化
|
|
||||||
- ✅ **减少延迟**:将等待时间从200ms减少到50ms
|
|
||||||
- ✅ **并行处理**:多个资源并行加载
|
|
||||||
- ✅ **静默错误处理**:错误不会干扰用户体验
|
|
||||||
|
|
||||||
## 具体实现
|
|
||||||
|
|
||||||
### 1. 移除视觉反馈 (`src/utils/pwaStateManager.ts`)
|
|
||||||
```typescript
|
|
||||||
// 移除了指示器显示逻辑
|
|
||||||
private async performStateRestore(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const restoredState = this.stateManager.restoreState()
|
|
||||||
if (restoredState) {
|
|
||||||
await this.restoreAppState(restoredState)
|
|
||||||
console.log('页面显示,已静默恢复状态')
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.isRestoring = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 优化状态恢复决策
|
|
||||||
```typescript
|
|
||||||
export class StateRestoreDecision {
|
|
||||||
private maxStateAge = 60 * 60 * 1000 // 延长到60分钟
|
|
||||||
|
|
||||||
shouldRestoreState(savedState: PWAState | null, currentContext: PWAContext): boolean {
|
|
||||||
// 更宽松的匹配策略
|
|
||||||
if (!this.isUrlCompatible(savedState.url, currentContext.url)) {
|
|
||||||
// 即使URL不匹配,也恢复基础状态
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 智能状态过滤
|
|
||||||
```typescript
|
|
||||||
private async restoreState(state: PWAState): Promise<void> {
|
|
||||||
const urlMatches = this.isUrlExactMatch(state.url, currentUrl)
|
|
||||||
|
|
||||||
// 只有URL完全匹配时才恢复滚动位置
|
|
||||||
if (state.scrollPosition && urlMatches) {
|
|
||||||
window.scrollTo({ top: state.scrollPosition, behavior: 'auto' })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤状态恢复
|
|
||||||
if (state.appData) {
|
|
||||||
this.restoreAppSpecificState(state.appData, urlMatches)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 移除UI状态跟踪 (`src/App.vue`)
|
|
||||||
```typescript
|
|
||||||
// 移除了状态跟踪变量
|
|
||||||
// const isRestoring = ref(false) // 已删除
|
|
||||||
|
|
||||||
// 移除了视觉反馈类
|
|
||||||
// <VApp :class="{ 'transparent-app': isTransparentTheme }"> // 简化
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 优化加载检查
|
|
||||||
```typescript
|
|
||||||
async function removeLoadingWithStateCheck() {
|
|
||||||
// 静默检查PWA状态恢复
|
|
||||||
const pwaController = (window as any).pwaStateController
|
|
||||||
if (pwaController) {
|
|
||||||
await pwaController.waitForStateRestore() // 无任何UI反馈
|
|
||||||
}
|
|
||||||
|
|
||||||
// 并行加载,减少延迟
|
|
||||||
await Promise.all([
|
|
||||||
globalSettingsStore.initialize(),
|
|
||||||
new Promise(resolve => setTimeout(resolve, 50)) // 50ms vs 原200ms
|
|
||||||
])
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 用户体验改进
|
|
||||||
|
|
||||||
### 1. 完全无感知
|
|
||||||
- ❌ **无加载指示器**:用户看不到任何状态恢复过程
|
|
||||||
- ❌ **无界面闪烁**:状态恢复不会影响当前界面
|
|
||||||
- ❌ **无延迟感知**:操作响应依然即时
|
|
||||||
|
|
||||||
### 2. 智能恢复
|
|
||||||
- ✅ **适应性强**:即使在不同页面也能恢复合适的状态
|
|
||||||
- ✅ **安全可靠**:错误不会影响正常使用
|
|
||||||
- ✅ **持久有效**:更长的状态保持时间
|
|
||||||
|
|
||||||
### 3. 性能优异
|
|
||||||
- ✅ **快速响应**:减少了不必要的等待时间
|
|
||||||
- ✅ **并行处理**:多任务同时进行
|
|
||||||
- ✅ **资源优化**:只恢复必要的状态
|
|
||||||
|
|
||||||
## 技术特点
|
|
||||||
|
|
||||||
### 1. 静默处理
|
|
||||||
```typescript
|
|
||||||
// 错误静默处理
|
|
||||||
} catch (error) {
|
|
||||||
// 静默处理错误,不输出详细错误信息
|
|
||||||
}
|
|
||||||
|
|
||||||
// 状态恢复静默进行
|
|
||||||
console.log('PWA状态静默恢复成功') // 仅开发调试用
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 智能过滤
|
|
||||||
```typescript
|
|
||||||
// 根据URL匹配情况决定恢复内容
|
|
||||||
private restoreAppSpecificState(appData: any, urlMatches: boolean = true): void {
|
|
||||||
// 总是恢复UI状态(如主题等)
|
|
||||||
if (appData.uiState) {
|
|
||||||
this.restoreUIState(appData.uiState)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只有在URL匹配时才恢复表单状态
|
|
||||||
if (appData.formState && urlMatches) {
|
|
||||||
this.restoreFormState(appData.formState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 宽松策略
|
|
||||||
- 允许URL不匹配时的状态恢复
|
|
||||||
- 设备方向变化不阻止恢复
|
|
||||||
- 延长状态有效期到60分钟
|
|
||||||
|
|
||||||
## 测试验证
|
|
||||||
|
|
||||||
### 1. 用户体验测试
|
|
||||||
- [x] 后台切换前台无任何指示器
|
|
||||||
- [x] 状态恢复过程完全静默
|
|
||||||
- [x] 用户操作不受影响
|
|
||||||
- [x] 界面无闪烁或跳动
|
|
||||||
|
|
||||||
### 2. 功能测试
|
|
||||||
- [x] 滚动位置正确恢复(同页面)
|
|
||||||
- [x] 主题设置正确保持
|
|
||||||
- [x] 表单数据适当恢复
|
|
||||||
- [x] 跨页面状态处理正确
|
|
||||||
|
|
||||||
### 3. 性能测试
|
|
||||||
- [x] 状态恢复时间 < 100ms
|
|
||||||
- [x] 内存使用保持稳定
|
|
||||||
- [x] 网络请求不增加
|
|
||||||
- [x] 电池消耗无明显影响
|
|
||||||
|
|
||||||
## 兼容性保证
|
|
||||||
|
|
||||||
### 1. 浏览器兼容
|
|
||||||
- ✅ iOS Safari PWA模式
|
|
||||||
- ✅ Android Chrome PWA模式
|
|
||||||
- ✅ 桌面浏览器PWA模式
|
|
||||||
|
|
||||||
### 2. 降级处理
|
|
||||||
- ✅ Service Worker不可用时的备选方案
|
|
||||||
- ✅ 存储不可用时的容错处理
|
|
||||||
- ✅ 网络异常时的静默处理
|
|
||||||
|
|
||||||
## 维护建议
|
|
||||||
|
|
||||||
### 1. 监控指标
|
|
||||||
- 状态恢复成功率
|
|
||||||
- 状态恢复时间
|
|
||||||
- 错误发生频率
|
|
||||||
- 用户满意度
|
|
||||||
|
|
||||||
### 2. 定期优化
|
|
||||||
- 清理过期状态数据
|
|
||||||
- 优化状态序列化大小
|
|
||||||
- 监控性能指标
|
|
||||||
- 收集用户反馈
|
|
||||||
|
|
||||||
## 总结
|
|
||||||
|
|
||||||
通过这次优化,我们实现了:
|
|
||||||
|
|
||||||
1. **完全无感的PWA体验**:用户感觉不到任何状态恢复过程
|
|
||||||
2. **智能状态管理**:根据上下文智能决定恢复策略
|
|
||||||
3. **优异的性能表现**:快速、静默、高效的状态恢复
|
|
||||||
4. **可靠的容错处理**:错误不影响正常使用
|
|
||||||
|
|
||||||
PWA应用现在能够提供接近原生应用的切换体验,用户在后台切换前台时感受不到任何延迟或中断,实现了真正的无感状态恢复。
|
|
||||||
+5
-8
@@ -140,8 +140,6 @@ function animateAndRemoveLoader() {
|
|||||||
// 检查PWA状态并移除加载界面
|
// 检查PWA状态并移除加载界面
|
||||||
async function removeLoadingWithStateCheck() {
|
async function removeLoadingWithStateCheck() {
|
||||||
try {
|
try {
|
||||||
console.log('开始静默检查加载状态...')
|
|
||||||
|
|
||||||
// 设置各个组件的加载状态
|
// 设置各个组件的加载状态
|
||||||
globalLoadingStateManager.setLoadingState('pwa-state', true)
|
globalLoadingStateManager.setLoadingState('pwa-state', true)
|
||||||
globalLoadingStateManager.setLoadingState('global-settings', true)
|
globalLoadingStateManager.setLoadingState('global-settings', true)
|
||||||
@@ -175,13 +173,12 @@ async function removeLoadingWithStateCheck() {
|
|||||||
|
|
||||||
// 检查未读消息
|
// 检查未读消息
|
||||||
checkAndEmitUnreadMessages()
|
checkAndEmitUnreadMessages()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('移除加载界面时发生错误:', error)
|
// 即使出错也要移除加载界面
|
||||||
// 即使出错也要移除加载界面
|
globalLoadingStateManager.reset()
|
||||||
globalLoadingStateManager.reset()
|
animateAndRemoveLoader()
|
||||||
animateAndRemoveLoader()
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 加载背景图片
|
// 加载背景图片
|
||||||
async function loadBackgroundImages(retryCount = 0) {
|
async function loadBackgroundImages(retryCount = 0) {
|
||||||
|
|||||||
@@ -18,14 +18,13 @@ export function usePWAState() {
|
|||||||
const saveCurrentState = async () => {
|
const saveCurrentState = async () => {
|
||||||
if (window.pwaStateController) {
|
if (window.pwaStateController) {
|
||||||
await window.pwaStateController.saveCurrentState()
|
await window.pwaStateController.saveCurrentState()
|
||||||
console.log('手动保存PWA状态')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 手动触发状态恢复检查
|
// 手动触发状态恢复检查
|
||||||
const checkStateRestore = async () => {
|
const checkStateRestore = async () => {
|
||||||
if (window.pwaStateController) {
|
if (window.pwaStateController) {
|
||||||
console.log('检查状态恢复')
|
// 静默检查
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,8 +34,6 @@ export function usePWAState() {
|
|||||||
isStateRestored.value = true
|
isStateRestored.value = true
|
||||||
stateRestoreCount.value++
|
stateRestoreCount.value++
|
||||||
lastRestoredState.value = customEvent.detail.state
|
lastRestoredState.value = customEvent.detail.state
|
||||||
|
|
||||||
console.log('Vue组件收到状态恢复通知:', customEvent.detail.state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置状态恢复标志
|
// 重置状态恢复标志
|
||||||
@@ -115,7 +112,6 @@ export function useGlobalPWAState() {
|
|||||||
const clearStoredState = () => {
|
const clearStoredState = () => {
|
||||||
localStorage.removeItem('mp-pwa-app-state')
|
localStorage.removeItem('mp-pwa-app-state')
|
||||||
sessionStorage.removeItem('mp-pwa-session-state')
|
sessionStorage.removeItem('mp-pwa-session-state')
|
||||||
console.log('已清除PWA存储状态')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ const initializePWABeforeMount = async () => {
|
|||||||
document.referrer.includes('android-app://')
|
document.referrer.includes('android-app://')
|
||||||
|
|
||||||
if (isPWA) {
|
if (isPWA) {
|
||||||
console.log('检测到PWA模式,预初始化状态管理器')
|
|
||||||
const pwaStateController = new PWAStateController()
|
const pwaStateController = new PWAStateController()
|
||||||
|
|
||||||
// 等待状态恢复完成
|
// 等待状态恢复完成
|
||||||
@@ -124,7 +123,6 @@ if (pwaStateController) {
|
|||||||
// 监听状态恢复事件
|
// 监听状态恢复事件
|
||||||
window.addEventListener('pwaStateRestored', (event: Event) => {
|
window.addEventListener('pwaStateRestored', (event: Event) => {
|
||||||
const customEvent = event as CustomEvent
|
const customEvent = event as CustomEvent
|
||||||
console.log('PWA状态已恢复:', customEvent.detail.state)
|
|
||||||
|
|
||||||
// 可以在这里添加状态恢复后的处理逻辑
|
// 可以在这里添加状态恢复后的处理逻辑
|
||||||
// 例如:通知Vue组件状态已恢复
|
// 例如:通知Vue组件状态已恢复
|
||||||
|
|||||||
+4
-18
@@ -151,7 +151,6 @@ async function clearBadge() {
|
|||||||
|
|
||||||
// 安装事件
|
// 安装事件
|
||||||
self.addEventListener('install', event => {
|
self.addEventListener('install', event => {
|
||||||
console.log('Service Worker install')
|
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
(async () => {
|
(async () => {
|
||||||
// 预缓存关键状态数据
|
// 预缓存关键状态数据
|
||||||
@@ -162,10 +161,9 @@ self.addEventListener('install', event => {
|
|||||||
if (existingState) {
|
if (existingState) {
|
||||||
// 预热状态数据
|
// 预热状态数据
|
||||||
const state = await existingState.json()
|
const state = await existingState.json()
|
||||||
console.log('预缓存状态数据:', state)
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('预缓存状态数据失败:', error)
|
// 静默处理错误
|
||||||
}
|
}
|
||||||
|
|
||||||
// 强制等待中的Service Worker立即成为活动的Service Worker
|
// 强制等待中的Service Worker立即成为活动的Service Worker
|
||||||
@@ -176,13 +174,11 @@ self.addEventListener('install', event => {
|
|||||||
|
|
||||||
// 激活事件
|
// 激活事件
|
||||||
self.addEventListener('activate', event => {
|
self.addEventListener('activate', event => {
|
||||||
console.log('Service Worker activate')
|
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
(async () => {
|
(async () => {
|
||||||
// 启用导航预载功能以提高性能
|
// 启用导航预载功能以提高性能
|
||||||
if ('navigationPreload' in self.registration) {
|
if ('navigationPreload' in self.registration) {
|
||||||
await self.registration.navigationPreload.enable()
|
await self.registration.navigationPreload.enable()
|
||||||
console.log('导航预加载已启用')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清理旧版本的缓存
|
// 清理旧版本的缓存
|
||||||
@@ -190,7 +186,6 @@ self.addEventListener('activate', event => {
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
cacheNames.map(cacheName => {
|
cacheNames.map(cacheName => {
|
||||||
if (cacheName.includes('old-') || cacheName.includes('deprecated-')) {
|
if (cacheName.includes('old-') || cacheName.includes('deprecated-')) {
|
||||||
console.log('清理旧缓存:', cacheName)
|
|
||||||
return caches.delete(cacheName)
|
return caches.delete(cacheName)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -257,7 +252,6 @@ precacheAndRoute(self.__WB_MANIFEST)
|
|||||||
|
|
||||||
// 监听 push 事件,显示通知
|
// 监听 push 事件,显示通知
|
||||||
self.addEventListener('push', function (event) {
|
self.addEventListener('push', function (event) {
|
||||||
console.log('notification push')
|
|
||||||
if (!event.data) {
|
if (!event.data) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -266,7 +260,6 @@ self.addEventListener('push', function (event) {
|
|||||||
try {
|
try {
|
||||||
payload = event.data?.json()
|
payload = event.data?.json()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
|
||||||
payload = {
|
payload = {
|
||||||
title: event.data?.text(),
|
title: event.data?.text(),
|
||||||
}
|
}
|
||||||
@@ -290,14 +283,13 @@ self.addEventListener('push', function (event) {
|
|||||||
await Promise.all([self.registration.showNotification(payload.title, content), updateBadge(newCount)])
|
await Promise.all([self.registration.showNotification(payload.title, content), updateBadge(newCount)])
|
||||||
})(),
|
})(),
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
// 静默处理错误
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听通知点击事件
|
// 监听通知点击事件
|
||||||
self.addEventListener('notificationclick', function (event) {
|
self.addEventListener('notificationclick', function (event) {
|
||||||
console.log('notification click')
|
|
||||||
const info = event.notification
|
const info = event.notification
|
||||||
if (event.action === 'close') {
|
if (event.action === 'close') {
|
||||||
info.close()
|
info.close()
|
||||||
@@ -308,7 +300,6 @@ self.addEventListener('notificationclick', function (event) {
|
|||||||
|
|
||||||
// 监听来自主应用的消息,用于清除徽章或更新徽章数量
|
// 监听来自主应用的消息,用于清除徽章或更新徽章数量
|
||||||
self.addEventListener('message', function (event) {
|
self.addEventListener('message', function (event) {
|
||||||
console.log('service worker received message:', event.data)
|
|
||||||
|
|
||||||
if (event.data && event.data.type === 'CLEAR_BADGE') {
|
if (event.data && event.data.type === 'CLEAR_BADGE') {
|
||||||
// 清除徽章
|
// 清除徽章
|
||||||
@@ -317,7 +308,6 @@ self.addEventListener('message', function (event) {
|
|||||||
event.ports[0]?.postMessage({ success: true })
|
event.ports[0]?.postMessage({ success: true })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Failed to clear badge:', error)
|
|
||||||
event.ports[0]?.postMessage({ success: false, error: error instanceof Error ? error.message : String(error) })
|
event.ports[0]?.postMessage({ success: false, error: error instanceof Error ? error.message : String(error) })
|
||||||
})
|
})
|
||||||
} else if (event.data && event.data.type === 'UPDATE_BADGE') {
|
} else if (event.data && event.data.type === 'UPDATE_BADGE') {
|
||||||
@@ -329,7 +319,6 @@ self.addEventListener('message', function (event) {
|
|||||||
event.ports[0]?.postMessage({ success: true })
|
event.ports[0]?.postMessage({ success: true })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Failed to update badge:', error)
|
|
||||||
event.ports[0]?.postMessage({ success: false, error: error instanceof Error ? error.message : String(error) })
|
event.ports[0]?.postMessage({ success: false, error: error instanceof Error ? error.message : String(error) })
|
||||||
})
|
})
|
||||||
} else if (event.data && event.data.type === 'GET_UNREAD_COUNT') {
|
} else if (event.data && event.data.type === 'GET_UNREAD_COUNT') {
|
||||||
@@ -339,7 +328,6 @@ self.addEventListener('message', function (event) {
|
|||||||
event.ports[0]?.postMessage({ count })
|
event.ports[0]?.postMessage({ count })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Failed to get unread count:', error)
|
|
||||||
event.ports[0]?.postMessage({ count: 0 })
|
event.ports[0]?.postMessage({ count: 0 })
|
||||||
})
|
})
|
||||||
} else if (event.data && event.data.type === 'SAVE_PWA_STATE') {
|
} else if (event.data && event.data.type === 'SAVE_PWA_STATE') {
|
||||||
@@ -355,7 +343,6 @@ self.addEventListener('message', function (event) {
|
|||||||
event.ports[0]?.postMessage({ success: result.success })
|
event.ports[0]?.postMessage({ success: result.success })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Failed to save PWA state:', error)
|
|
||||||
event.ports[0]?.postMessage({ success: false, error: error instanceof Error ? error.message : String(error) })
|
event.ports[0]?.postMessage({ success: false, error: error instanceof Error ? error.message : String(error) })
|
||||||
})
|
})
|
||||||
} else if (event.data && event.data.type === 'GET_PWA_STATE') {
|
} else if (event.data && event.data.type === 'GET_PWA_STATE') {
|
||||||
@@ -366,7 +353,6 @@ self.addEventListener('message', function (event) {
|
|||||||
event.ports[0]?.postMessage({ state })
|
event.ports[0]?.postMessage({ state })
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Failed to get PWA state:', error)
|
|
||||||
event.ports[0]?.postMessage({ state: {} })
|
event.ports[0]?.postMessage({ state: {} })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export class PWALoadingStateManager {
|
|||||||
try {
|
try {
|
||||||
listener(isLoading)
|
listener(isLoading)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载状态监听器错误:', error)
|
// 静默处理错误
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,7 +312,6 @@ export class VisibilityStateManager {
|
|||||||
private handlePageHidden(): void {
|
private handlePageHidden(): void {
|
||||||
const currentState = this.getCurrentAppState()
|
const currentState = this.getCurrentAppState()
|
||||||
this.stateManager.saveState(currentState)
|
this.stateManager.saveState(currentState)
|
||||||
console.log('页面被隐藏,已保存状态')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handlePageVisible(): void {
|
private handlePageVisible(): void {
|
||||||
@@ -327,10 +326,9 @@ export class VisibilityStateManager {
|
|||||||
const restoredState = this.stateManager.restoreState()
|
const restoredState = this.stateManager.restoreState()
|
||||||
if (restoredState) {
|
if (restoredState) {
|
||||||
await this.restoreAppState(restoredState)
|
await this.restoreAppState(restoredState)
|
||||||
console.log('页面显示,已静默恢复状态')
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('状态恢复失败:', error)
|
// 静默处理错误
|
||||||
} finally {
|
} finally {
|
||||||
this.isRestoring = false
|
this.isRestoring = false
|
||||||
}
|
}
|
||||||
@@ -530,11 +528,10 @@ export class PWAStateController {
|
|||||||
const savedState = await source()
|
const savedState = await source()
|
||||||
if (this.restoreDecision.shouldRestoreState(savedState, currentContext)) {
|
if (this.restoreDecision.shouldRestoreState(savedState, currentContext)) {
|
||||||
await this.restoreState(savedState!)
|
await this.restoreState(savedState!)
|
||||||
console.log('PWA状态静默恢复成功')
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 静默处理错误,不输出详细错误信息
|
// 静默处理错误
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -566,8 +563,6 @@ export class PWAStateController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async restoreState(state: PWAState): Promise<void> {
|
private async restoreState(state: PWAState): Promise<void> {
|
||||||
console.log('开始静默恢复PWA状态')
|
|
||||||
|
|
||||||
const currentUrl = window.location.href
|
const currentUrl = window.location.href
|
||||||
const urlMatches = this.isUrlExactMatch(state.url, currentUrl)
|
const urlMatches = this.isUrlExactMatch(state.url, currentUrl)
|
||||||
|
|
||||||
@@ -586,7 +581,6 @@ export class PWAStateController {
|
|||||||
|
|
||||||
// 触发状态恢复事件
|
// 触发状态恢复事件
|
||||||
this.dispatchStateRestoreEvent(state)
|
this.dispatchStateRestoreEvent(state)
|
||||||
console.log('PWA状态静默恢复完成')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isUrlExactMatch(savedUrl: string, currentUrl: string): boolean {
|
private isUrlExactMatch(savedUrl: string, currentUrl: string): boolean {
|
||||||
@@ -678,7 +672,6 @@ export class PWAStateController {
|
|||||||
// 恢复UI状态
|
// 恢复UI状态
|
||||||
if (uiState.darkMode !== undefined) {
|
if (uiState.darkMode !== undefined) {
|
||||||
// 这里可以根据实际的主题切换逻辑来恢复
|
// 这里可以根据实际的主题切换逻辑来恢复
|
||||||
console.log('恢复主题状态:', uiState.darkMode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user