Skip to content

Commit f4d9ff3

Browse files
committed
修复图片闪烁问题
1 parent 97096f3 commit f4d9ff3

File tree

5 files changed

+284
-10
lines changed

5 files changed

+284
-10
lines changed
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
# 缓存清除指南
2+
3+
## 问题现象
4+
5+
更新网站后,可能出现以下问题:
6+
- ❌ CSP 错误:`connect-src 'self'` 阻止请求
7+
- ❌ 图标加载失败
8+
- ❌ 功能异常
9+
- ❌ 样式不更新
10+
11+
## 原因分析
12+
13+
浏览器缓存了旧版本的文件:
14+
1. **Service Worker 缓存**:缓存了旧的 `_headers` 文件
15+
2. **浏览器缓存**:缓存了旧的静态资源
16+
3. **HTTP 缓存**:CDN 或浏览器的 HTTP 缓存
17+
18+
## 解决方案
19+
20+
### 方法 1:使用清除缓存工具(推荐)
21+
22+
访问:`https://nav.weizwz.com/clear-cache.html`
23+
24+
点击"全部清除并刷新"按钮,自动完成所有清理工作。
25+
26+
### 方法 2:手动清除(开发者)
27+
28+
**Chrome/Edge**
29+
```
30+
1. F12 打开开发者工具
31+
2. Application → Storage → Clear site data
32+
3. 勾选所有选项
33+
4. 点击 "Clear site data"
34+
5. 刷新页面(Ctrl+Shift+R)
35+
```
36+
37+
**Firefox**
38+
```
39+
1. F12 打开开发者工具
40+
2. Storage → 右键 → Delete All
41+
3. 刷新页面(Ctrl+Shift+R)
42+
```
43+
44+
### 方法 3:浏览器设置清除
45+
46+
**所有浏览器**
47+
```
48+
1. Ctrl+Shift+Delete(Mac: Cmd+Shift+Delete)
49+
2. 选择"缓存的图片和文件"
50+
3. 时间范围选择"全部"
51+
4. 点击"清除数据"
52+
5. 刷新页面
53+
```
54+
55+
### 方法 4:隐身模式测试
56+
57+
```
58+
1. Ctrl+Shift+N(Chrome)或 Ctrl+Shift+P(Firefox)
59+
2. 访问网站
60+
3. 验证问题是否解决
61+
```
62+
63+
## 开发者:强制更新
64+
65+
### 1. 更新 Service Worker 版本
66+
67+
```javascript
68+
// public/sw.js
69+
const CACHE_NAME = 'weiz-nav-v5'; // v4 → v5
70+
const RUNTIME_CACHE = 'weiz-nav-runtime-v5';
71+
const IMAGE_CACHE = 'weiz-nav-images-v5';
72+
```
73+
74+
### 2. 更新 version.json
75+
76+
```json
77+
{
78+
"version": "1.0.5",
79+
"cacheVersion": "v5"
80+
}
81+
```
82+
83+
### 3. 部署
84+
85+
```bash
86+
git add public/sw.js public/version.json
87+
git commit -m "chore: 强制清除缓存 v5"
88+
git push
89+
```
90+
91+
### 4. 用户端自动更新
92+
93+
用户访问网站时:
94+
1. 检测到新版本 Service Worker
95+
2. 自动下载并安装
96+
3. 删除旧缓存(v1, v2, v3, v4)
97+
4. 激活新版本(v5)
98+
5. 自动刷新页面
99+
100+
## 验证缓存已清除
101+
102+
### 浏览器控制台
103+
104+
```javascript
105+
// 查看 Service Worker 版本
106+
navigator.serviceWorker.getRegistration().then(reg => {
107+
console.log('SW:', reg?.active?.scriptURL);
108+
});
109+
110+
// 查看缓存列表
111+
caches.keys().then(keys => {
112+
console.log('Caches:', keys);
113+
// 应该只看到 v4 的缓存
114+
});
115+
116+
// 查看 CSP 策略
117+
fetch('/').then(r => {
118+
console.log('CSP:', r.headers.get('content-security-policy'));
119+
});
120+
```
121+
122+
### DevTools 检查
123+
124+
```
125+
F12 → Application → Service Workers
126+
- 状态应该是 "activated and is running"
127+
- 版本应该是最新的
128+
129+
F12 → Application → Cache Storage
130+
- 应该只有 v4 的缓存
131+
- 旧版本(v1, v2, v3)应该被删除
132+
```
133+
134+
## 常见问题
135+
136+
### Q: 为什么清除后还是有问题?
137+
138+
**A**: 可能的原因:
139+
1. **CDN 缓存**:Cloudflare 边缘节点缓存了旧文件
140+
- 解决:在 Cloudflare 控制台清除缓存
141+
142+
2. **浏览器扩展**:某些扩展会缓存资源
143+
- 解决:禁用扩展或使用隐身模式
144+
145+
3. **DNS 缓存**:DNS 解析到旧的 IP
146+
- 解决:`ipconfig /flushdns`(Windows)或 `sudo dscacheutil -flushcache`(Mac)
147+
148+
### Q: 如何防止缓存问题?
149+
150+
**A**: 最佳实践:
151+
1. **版本化资源**:使用哈希文件名
152+
2. **合理的缓存策略**:
153+
- HTML: `max-age=0`
154+
- JS/CSS: `max-age=31536000` + 哈希
155+
- 图片: `max-age=2592000`
156+
3. **Service Worker 版本管理**:每次更新递增版本号
157+
158+
### Q: 用户需要手动清除吗?
159+
160+
**A**: 不需要!
161+
- Service Worker 会自动更新
162+
- 旧缓存会自动清除
163+
- 用户只需刷新页面
164+
165+
但如果遇到问题,可以:
166+
1. 访问 `/clear-cache.html`
167+
2. 点击"全部清除并刷新"
168+
169+
### Q: 清除缓存会丢失数据吗?
170+
171+
**A**: 不会!
172+
- ✅ LocalStorage 数据保留(用户的导航链接)
173+
- ✅ 用户设置保留
174+
- ❌ 只清除缓存的静态资源
175+
176+
## 预防措施
177+
178+
### 1. 开发时禁用缓存
179+
180+
```
181+
DevTools → Network → Disable cache(勾选)
182+
```
183+
184+
### 2. 使用版本号
185+
186+
```javascript
187+
// 在 URL 中添加版本号
188+
<script src="/app.js?v=1.0.4"></script>
189+
```
190+
191+
### 3. 设置正确的缓存头
192+
193+
```
194+
# public/_headers
195+
/*.html
196+
Cache-Control: public, max-age=0, must-revalidate
197+
198+
/*.js
199+
Cache-Control: public, max-age=31536000, immutable
200+
```
201+
202+
### 4. 监控缓存状态
203+
204+
```javascript
205+
// 定期检查缓存大小
206+
navigator.storage.estimate().then(estimate => {
207+
const used = (estimate.usage / 1024 / 1024).toFixed(2);
208+
const quota = (estimate.quota / 1024 / 1024).toFixed(2);
209+
console.log(`缓存: ${used}MB / ${quota}MB`);
210+
});
211+
```
212+
213+
## 清除缓存检查清单
214+
215+
部署新版本后:
216+
217+
- [ ] 更新 Service Worker 版本号
218+
- [ ] 更新 version.json
219+
- [ ] 提交并部署
220+
- [ ] 清除 Cloudflare 缓存(如果使用)
221+
- [ ] 测试环境验证
222+
- [ ] 生产环境验证
223+
- [ ] 监控用户反馈
224+
225+
## 紧急清除脚本
226+
227+
如果需要强制所有用户清除缓存:
228+
229+
```javascript
230+
// 在 Service Worker 中添加
231+
self.addEventListener('activate', (event) => {
232+
event.waitUntil(
233+
// 删除所有缓存
234+
caches.keys().then((cacheNames) => {
235+
return Promise.all(
236+
cacheNames.map((cacheName) => {
237+
return caches.delete(cacheName);
238+
})
239+
);
240+
})
241+
);
242+
});
243+
```
244+
245+
## 总结
246+
247+
**用户端**:
248+
- 访问 `/clear-cache.html` 清除缓存
249+
- 或等待 Service Worker 自动更新
250+
251+
**开发者端**:
252+
- 每次更新递增 Service Worker 版本
253+
- 设置合理的缓存策略
254+
- 监控缓存状态
255+
256+
**预防**:
257+
- 使用版本化资源
258+
- 正确的 HTTP 缓存头
259+
- Service Worker 自动更新机制
260+
261+
---
262+
263+
**记住**:缓存是为了性能,但也要确保用户能及时获取更新!

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pnpm deploy
8888
- [快速开始](./.kiro/specs/frontend-navigation-site/QUICKSTART.md) - 5 分钟快速部署
8989
- [部署指南](./.kiro/specs/frontend-navigation-site/DEPLOYMENT.md) - 详细部署说明
9090
- [PWA 使用指南](./.kiro/specs/frontend-navigation-site/PWA_GUIDE.md) - PWA 安装和使用
91+
- [缓存清除指南](./.kiro/specs/frontend-navigation-site/CACHE_CLEAR_GUIDE.md) - 解决缓存问题
9192

9293
**开发文档**
9394
- [需求文档](./.kiro/specs/frontend-navigation-site/requirements.md) - 功能需求

components/navigation/LinkCard.tsx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const IconWithFallback: React.FC<{
2424
}> = ({ src, alt, fallbackUrl, scale = 0.8 }) => {
2525
const [hasError, setHasError] = useState(false);
2626
const [faviconError, setFaviconError] = useState(false);
27+
const [imageLoaded, setImageLoaded] = useState(false);
28+
const [faviconLoaded, setFaviconLoaded] = useState(false);
2729

2830
// 计算图标大小(基础大小 60px)
2931
const iconSize = Math.round(60 * scale);
@@ -46,9 +48,13 @@ const IconWithFallback: React.FC<{
4648
style={{
4749
transform: `scale(${scale})`,
4850
}}
51+
onLoad={() => setFaviconLoaded(true)}
4952
onError={() => {
50-
console.warn(`Favicon 加载失败: ${fallbackUrl}`);
51-
setFaviconError(true);
53+
// 只有在图片未成功加载时才标记为错误
54+
if (!faviconLoaded) {
55+
console.warn(`Favicon 加载失败: ${fallbackUrl}`);
56+
setFaviconError(true);
57+
}
5258
}}
5359
/>
5460
);
@@ -65,9 +71,13 @@ const IconWithFallback: React.FC<{
6571
style={{
6672
transform: `scale(${scale})`,
6773
}}
74+
onLoad={() => setImageLoaded(true)}
6875
onError={() => {
69-
console.warn(`图标加载失败: ${src}`);
70-
setHasError(true);
76+
// 只有在图片未成功加载时才标记为错误
77+
if (!imageLoaded) {
78+
console.warn(`图标加载失败: ${src}`);
79+
setHasError(true);
80+
}
7181
}}
7282
/>
7383
);

public/sw.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Service Worker for PWA
2-
const CACHE_NAME = 'weiz-nav-v3';
3-
const RUNTIME_CACHE = 'weiz-nav-runtime-v3';
4-
const IMAGE_CACHE = 'weiz-nav-images-v3';
2+
const CACHE_NAME = 'weiz-nav-v4';
3+
const RUNTIME_CACHE = 'weiz-nav-runtime-v4';
4+
const IMAGE_CACHE = 'weiz-nav-images-v4';
55

66
// 需要预缓存的静态资源
77
const PRECACHE_URLS = [

public/version.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"version": "1.0.3",
3-
"buildTime": "2025-11-18T10:00:00.000Z",
4-
"cacheVersion": "v3",
2+
"version": "1.0.4",
3+
"buildTime": "2025-11-19T15:26:00.000Z",
4+
"cacheVersion": "v4",
55
"changelog": [
66
"修复 CSP 策略,支持所有 HTTPS 资源",
77
"优化图标缓存策略",

0 commit comments

Comments
 (0)