docs: update storage cleaner design with code review feedback
- Add routing implementation details - Add restricted page detection - Add complete executeScript examples - Add error handling for IndexedDB.databases - Add Service Workers multiple registrations handling - Add popup lifecycle notes - Improve TypeScript types with error handling Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,41 @@ entrypoints/popup/pages/
|
|||||||
|
|
||||||
在弹窗中添加标签页切换功能,用户可以在时间戳转换和存储清理之间切换。
|
在弹窗中添加标签页切换功能,用户可以在时间戳转换和存储清理之间切换。
|
||||||
|
|
||||||
|
**路由实现方案:**
|
||||||
|
|
||||||
|
使用简单的状态管理进行页面切换:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// App.tsx
|
||||||
|
type PageType = 'timestamp' | 'storageCleaner';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [currentPage, setCurrentPage] = useState<PageType>('timestamp');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
<Box sx={{ display: 'flex', justifyContent: 'center', mb: 2 }}>
|
||||||
|
<Button
|
||||||
|
variant={currentPage === 'timestamp' ? 'contained' : 'outlined'}
|
||||||
|
onClick={() => setCurrentPage('timestamp')}
|
||||||
|
>
|
||||||
|
时间戳
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={currentPage === 'storageCleaner' ? 'contained' : 'outlined'}
|
||||||
|
onClick={() => setCurrentPage('storageCleaner')}
|
||||||
|
sx={{ ml: 1 }}
|
||||||
|
>
|
||||||
|
存储清理
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
{currentPage === 'timestamp' && <TimestampPage />}
|
||||||
|
{currentPage === 'storageCleaner' && <StorageCleanerPage />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 用户界面设计
|
## 用户界面设计
|
||||||
|
|
||||||
### 页面组成
|
### 页面组成
|
||||||
@@ -56,13 +91,18 @@ entrypoints/popup/pages/
|
|||||||
|
|
||||||
### 获取当前标签页域名
|
### 获取当前标签页域名
|
||||||
|
|
||||||
使用 Chrome Tabs API 获取当前活动标签页:
|
使用 Chrome Tabs API 获取当前活动标签页,并过滤受限页面:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||||
if (!tab?.url) {
|
|
||||||
throw new Error('无法获取当前标签页 URL');
|
// 检查受限页面
|
||||||
|
const restrictedProtocols = ['chrome:', 'chrome-extension:', 'about:', 'edge:', 'view-source:'];
|
||||||
|
|
||||||
|
if (!tab?.url || restrictedProtocols.some((p) => tab.url!.startsWith(p))) {
|
||||||
|
throw new Error('存储清理功能不支持此页面');
|
||||||
}
|
}
|
||||||
|
|
||||||
const domain = new URL(tab.url).hostname;
|
const domain = new URL(tab.url).hostname;
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -85,6 +125,17 @@ for (const cookie of cookies) {
|
|||||||
|
|
||||||
### 注入脚本清理其他存储
|
### 注入脚本清理其他存储
|
||||||
|
|
||||||
|
使用 `chrome.scripting.executeScript` 注入清理脚本:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const result = await chrome.scripting.executeScript({
|
||||||
|
target: { tabId: tab.id },
|
||||||
|
func: () => {
|
||||||
|
// 清理逻辑在页面上下文中执行
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
需要注入到页面执行的存储清理逻辑:
|
需要注入到页面执行的存储清理逻辑:
|
||||||
|
|
||||||
#### 清理 localStorage
|
#### 清理 localStorage
|
||||||
@@ -106,58 +157,73 @@ return count;
|
|||||||
#### 清理 IndexedDB
|
#### 清理 IndexedDB
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const databases = await indexedDB.databases();
|
// 检查 databases indexedDB 方法是否可用
|
||||||
let count = 0;
|
if (typeof indexedDB.databases === 'function') {
|
||||||
for (const db of databases) {
|
const databases = await indexedDB.databases();
|
||||||
const deleteReq = indexedDB.deleteDatabase(db.name);
|
let count = 0;
|
||||||
deleteReq.onblocked = () => {
|
for (const db of databases) {
|
||||||
console.warn('IndexedDB delete blocked:', db.name);
|
const deleteReq = indexedDB.databases(db.name);
|
||||||
};
|
deleteReq.onblocked = () => {
|
||||||
await new Promise((resolve, reject) => {
|
console.warn('IndexedDB delete blocked:', db.name);
|
||||||
deleteReq.onsuccess = resolve;
|
};
|
||||||
deleteReq.onerror = reject;
|
await new Promise((resolve, reject) => {
|
||||||
});
|
deleteReq.onsuccess = resolve;
|
||||||
count++;
|
deleteReq.onerror = reject;
|
||||||
|
});
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
// 降级方案:使用传统方法
|
||||||
|
let count = 0;
|
||||||
|
// 尝试遍历已知数据库或提示用户手动清除
|
||||||
return count;
|
return count;
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 清理 Cache Storage
|
#### 清理 Cache Storage
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const cacheNames = await caches.keys();
|
if ('caches' in window) {
|
||||||
for (const name of cacheNames) {
|
const cacheNames = await caches.keys();
|
||||||
await caches.delete(name);
|
for (const name of cacheNames) {
|
||||||
|
await caches.delete(name);
|
||||||
|
}
|
||||||
|
return cacheNames.length;
|
||||||
}
|
}
|
||||||
return cacheNames.length;
|
return 0;
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 注销 Service Workers
|
#### 注销 Service Workers
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
const registration = await navigator.serviceWorker.getRegistration();
|
const registrations = await navigator.serviceWorker.getRegistrations();
|
||||||
if (registration) {
|
let count = 0;
|
||||||
|
for (const registration of registrations) {
|
||||||
await registration.unregister();
|
await registration.unregister();
|
||||||
return true;
|
count++;
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
return false;
|
return 0;
|
||||||
```
|
```
|
||||||
|
|
||||||
### 数据流
|
### 数据流
|
||||||
|
|
||||||
1. 页面加载时获取当前标签页 URL 并显示域名
|
1. 页面加载时获取当前标签页 URL 并显示域名
|
||||||
2. 用户勾选要清理的存储类型
|
2. 检查是否为受限页面(chrome://, about:// 等),如果是则显示错误提示
|
||||||
3. 用户选择是否自动刷新页面
|
3. 用户勾选要清理的存储类型
|
||||||
4. 用户点击清理按钮
|
4. 用户选择是否自动刷新页面
|
||||||
5. 弹出确认对话框询问用户确认
|
5. 用户点击清理按钮
|
||||||
6. 确认后执行清理:
|
6. 弹出确认对话框询问用户确认
|
||||||
|
7. 确认后执行清理:
|
||||||
- 如果选择 Cookies:直接使用 chrome.cookies API 删除
|
- 如果选择 Cookies:直接使用 chrome.cookies API 删除
|
||||||
- 其他存储类型:向页面注入清理脚本
|
- 其他存储类型:向页面注入清理脚本
|
||||||
7. 收集所有清理结果并统计
|
8. 收集所有清理结果并统计
|
||||||
8. 显示清理结果
|
9. 显示清理结果
|
||||||
9. 如果勾选"自动刷新"或用户点击"刷新页面"按钮,执行页面刷新
|
10. 如果勾选"自动刷新"或用户点击"刷新页面"按钮,执行页面刷新
|
||||||
|
|
||||||
|
**注意:** 当触发页面刷新时,popup 会自动关闭。需要在刷新前显示提示信息。
|
||||||
|
|
||||||
### 页面刷新
|
### 页面刷新
|
||||||
|
|
||||||
@@ -167,14 +233,29 @@ await chrome.tabs.reload(tab.id);
|
|||||||
|
|
||||||
## 错误处理
|
## 错误处理
|
||||||
|
|
||||||
| 错误场景 | 处理方式 |
|
| 错误场景 | 处理方式 |
|
||||||
| ------------------- | ---------------------------------- |
|
| ------------------------------- | ---------------------------------------- |
|
||||||
| 无法获取当前标签页 | 显示错误提示:"无法获取当前标签页" |
|
| 无法获取当前标签页 | 显示错误提示:"无法获取当前标签页" |
|
||||||
| 无法访问页面 URL | 显示错误提示:"无法访问此页面" |
|
| 受限页面(chrome://, about://) | 显示错误提示:"存储清理功能不支持此页面" |
|
||||||
| IndexedDB onblocked | 显示警告但继续执行其他清理 |
|
| 无法访问页面 URL | 显示错误提示:"无法访问此页面" |
|
||||||
| 清理失败 | 显示具体错误信息 |
|
| IndexedDB onblocked | 显示警告但继续执行其他清理 |
|
||||||
| Cookies 删除失败 | 记录错误,显示清理失败提示 |
|
| IndexedDB.databases 不可用 | 使用降级方案或提示用户手动清除 |
|
||||||
| 无权限 | 提示用户刷新扩展或检查权限 |
|
| 清理失败 | 显示具体错误信息 |
|
||||||
|
| Cookies 删除失败 | 记录错误,显示清理失败提示 |
|
||||||
|
| 无权限 | 提示用户刷新扩展或检查权限 |
|
||||||
|
| 脚本注入失败 | 显示错误提示:"无法注入清理脚本" |
|
||||||
|
|
||||||
|
**Popup 生命周期说明:**
|
||||||
|
|
||||||
|
- Popup 在页面失去焦点时会关闭
|
||||||
|
- 刷新页面后 Popup 会自动关闭
|
||||||
|
- 需要在刷新前显示提示:"页面即将刷新,Popup 将关闭"
|
||||||
|
|
||||||
|
**Popup 生命周期说明:**
|
||||||
|
|
||||||
|
- Popup 在页面失去焦点时会关闭
|
||||||
|
- 刷新页面后 Popup 会自动关闭
|
||||||
|
- 需要在刷新前显示提示:"页面即将刷新,Popup 将关闭"
|
||||||
|
|
||||||
## 权限需求
|
## 权限需求
|
||||||
|
|
||||||
@@ -207,13 +288,25 @@ export interface StorageCleanerOptions {
|
|||||||
serviceWorkers: boolean;
|
serviceWorkers: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type StorageCleanResult =
|
||||||
|
| {
|
||||||
|
success: true;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
success: false;
|
||||||
|
error: string;
|
||||||
|
};
|
||||||
|
|
||||||
export interface CleaningResult {
|
export interface CleaningResult {
|
||||||
localStorage?: number;
|
success: boolean;
|
||||||
sessionStorage?: number;
|
error?: string;
|
||||||
indexedDB?: number;
|
localStorage?: StorageCleanResult;
|
||||||
cookies?: number;
|
sessionStorage?: StorageCleanResult;
|
||||||
cacheStorage?: number;
|
indexedDB?: StorageCleanResult;
|
||||||
serviceWorkers?: boolean;
|
cookies?: StorageCleanResult;
|
||||||
|
cacheStorage?: StorageCleanResult;
|
||||||
|
serviceWorkers?: StorageCleanResult;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user