|
| 1 | +# 图标加载失败处理演示 |
| 2 | + |
| 3 | +## 快速测试方法 |
| 4 | + |
| 5 | +### 方法 1:使用浏览器开发者工具 |
| 6 | + |
| 7 | +1. 打开网站 |
| 8 | +2. 按 F12 打开开发者工具 |
| 9 | +3. 切换到 Console 标签 |
| 10 | +4. 运行以下代码添加测试链接: |
| 11 | + |
| 12 | +```javascript |
| 13 | +// 测试 1:无效的自定义图标 URL |
| 14 | +const testLink1 = { |
| 15 | + id: 'test-1', |
| 16 | + name: '测试:无效图标', |
| 17 | + url: 'https://github.com', |
| 18 | + description: '这个链接使用了无效的图标URL', |
| 19 | + category: '主页', |
| 20 | + icon: 'https://invalid-domain-12345.com/icon.png', |
| 21 | + backgroundColor: '#1890ff', |
| 22 | + iconScale: 0.7, |
| 23 | + tags: [], |
| 24 | + order: 0, |
| 25 | + createdAt: Date.now(), |
| 26 | + updatedAt: Date.now() |
| 27 | +}; |
| 28 | + |
| 29 | +// 测试 2:无效的域名(favicon 也会失败) |
| 30 | +const testLink2 = { |
| 31 | + id: 'test-2', |
| 32 | + name: '测试:完全失败', |
| 33 | + url: 'https://invalid-domain-99999.com', |
| 34 | + description: '这个链接的图标和favicon都会失败', |
| 35 | + category: '主页', |
| 36 | + icon: 'https://invalid-domain-12345.com/icon.png', |
| 37 | + backgroundColor: '#52c41a', |
| 38 | + iconScale: 0.7, |
| 39 | + tags: [], |
| 40 | + order: 0, |
| 41 | + createdAt: Date.now(), |
| 42 | + updatedAt: Date.now() |
| 43 | +}; |
| 44 | + |
| 45 | +// 测试 3:只依赖 favicon(应该成功) |
| 46 | +const testLink3 = { |
| 47 | + id: 'test-3', |
| 48 | + name: '测试:Favicon回退', |
| 49 | + url: 'https://www.google.com', |
| 50 | + description: '这个链接没有自定义图标,应该显示Google的favicon', |
| 51 | + category: '主页', |
| 52 | + backgroundColor: '#4285f4', |
| 53 | + iconScale: 0.7, |
| 54 | + tags: [], |
| 55 | + order: 0, |
| 56 | + createdAt: Date.now(), |
| 57 | + updatedAt: Date.now() |
| 58 | +}; |
| 59 | + |
| 60 | +// 添加到 localStorage |
| 61 | +const existingLinks = JSON.parse(localStorage.getItem('navigation-links') || '[]'); |
| 62 | +existingLinks.push(testLink1, testLink2, testLink3); |
| 63 | +localStorage.setItem('navigation-links', JSON.stringify(existingLinks)); |
| 64 | + |
| 65 | +// 刷新页面 |
| 66 | +location.reload(); |
| 67 | +``` |
| 68 | + |
| 69 | +### 方法 2:通过 UI 手动添加 |
| 70 | + |
| 71 | +1. 点击页面上的"添加链接"按钮 |
| 72 | +2. 填写以下信息: |
| 73 | + |
| 74 | +**测试链接 1:无效图标** |
| 75 | +- 名称:测试:无效图标 |
| 76 | +- 地址:https://github.com |
| 77 | +- 描述:这个链接使用了无效的图标URL |
| 78 | +- 图标:https://invalid-domain-12345.com/icon.png |
| 79 | +- 背景色:#1890ff |
| 80 | + |
| 81 | +**测试链接 2:完全失败** |
| 82 | +- 名称:测试:完全失败 |
| 83 | +- 地址:https://invalid-domain-99999.com |
| 84 | +- 描述:这个链接的图标和favicon都会失败 |
| 85 | +- 图标:https://invalid-domain-12345.com/icon.png |
| 86 | +- 背景色:#52c41a |
| 87 | + |
| 88 | +**测试链接 3:Favicon回退** |
| 89 | +- 名称:测试:Favicon回退 |
| 90 | +- 地址:https://www.google.com |
| 91 | +- 描述:这个链接没有自定义图标,应该显示Google的favicon |
| 92 | +- 图标:(留空) |
| 93 | +- 背景色:#4285f4 |
| 94 | + |
| 95 | +## 预期结果 |
| 96 | + |
| 97 | +### 测试链接 1(无效图标) |
| 98 | +- ✅ 不显示破损的图片图标 |
| 99 | +- ✅ 自动回退到 GitHub 的 favicon |
| 100 | +- ✅ 控制台显示:`图标加载失败: https://invalid-domain-12345.com/icon.png` |
| 101 | + |
| 102 | +### 测试链接 2(完全失败) |
| 103 | +- ✅ 不显示破损的图片图标 |
| 104 | +- ✅ 显示默认的链接图标(LinkOutlined) |
| 105 | +- ✅ 控制台显示两条警告: |
| 106 | + - `图标加载失败: https://invalid-domain-12345.com/icon.png` |
| 107 | + - `Favicon 加载失败: [favicon URL]` |
| 108 | + |
| 109 | +### 测试链接 3(Favicon回退) |
| 110 | +- ✅ 显示 Google 的 favicon |
| 111 | +- ✅ 图标清晰,没有破损 |
| 112 | + |
| 113 | +## 清理测试数据 |
| 114 | + |
| 115 | +测试完成后,可以通过以下方式清理测试数据: |
| 116 | + |
| 117 | +### 方法 1:通过 UI 删除 |
| 118 | +右键点击测试链接卡片,选择"删除" |
| 119 | + |
| 120 | +### 方法 2:通过控制台清理 |
| 121 | +```javascript |
| 122 | +// 删除所有测试链接 |
| 123 | +const links = JSON.parse(localStorage.getItem('navigation-links') || '[]'); |
| 124 | +const cleanedLinks = links.filter(link => !link.name.startsWith('测试:')); |
| 125 | +localStorage.setItem('navigation-links', JSON.stringify(cleanedLinks)); |
| 126 | +location.reload(); |
| 127 | +``` |
| 128 | + |
| 129 | +## 技术说明 |
| 130 | + |
| 131 | +### 修复前的问题 |
| 132 | +```typescript |
| 133 | +// 问题代码:使用 display: 'none' 隐藏 |
| 134 | +<img |
| 135 | + src={src} |
| 136 | + style={{ display: hasError ? 'none' : 'block' }} |
| 137 | + onError={() => setHasError(true)} |
| 138 | +/> |
| 139 | +``` |
| 140 | + |
| 141 | +浏览器可能在设置 `display: 'none'` 之前短暂显示破损图标。 |
| 142 | + |
| 143 | +### 修复后的方案 |
| 144 | +```typescript |
| 145 | +// 解决方案:条件渲染,完全不渲染失败的元素 |
| 146 | +if (hasError && (faviconError || !fallbackUrl)) { |
| 147 | + return <DefaultIcon />; |
| 148 | +} |
| 149 | + |
| 150 | +if (hasError && fallbackUrl && !faviconError) { |
| 151 | + return <img src={fallbackUrl} onError={() => setFaviconError(true)} />; |
| 152 | +} |
| 153 | + |
| 154 | +return <img src={src} onError={() => setHasError(true)} />; |
| 155 | +``` |
| 156 | + |
| 157 | +这样可以确保失败的 `<img>` 元素完全不会被渲染到 DOM 中。 |
0 commit comments