前言
作为一个重度浏览器用户,你是否想过自己每天在各个网站上花费了多少时间?今天我将分享如何从零开始开发一个Chrome扩展,用于统计网站使用时长。这个项目涵盖了现代Chrome扩展开发的核心技术栈:Manifest V3、Service Worker、Chrome APIs以及现代前端技术。
项目地址
项目概述
我们要开发的扩展具备以下功能:
- ✅ 自动统计各网站的使用时长
- ✅ 智能检测用户活跃状态(空闲时暂停计时)
- ✅ 本地数据存储与历史记录管理
- ✅ 美观的弹窗界面展示统计数据
- ✅ 数据重置与实时刷新功能
技术亮点:
- 使用Manifest V3最新标准
- Service Worker架构设计
- 多脚本协同工作(Background + Content Script)
- 现代CSS设计与响应式布局
1. 项目架构设计
1.1 文件结构规划
website-timer-extension/
├── manifest.json # 扩展配置文件
├── background.js # 后台服务脚本
├── content.js # 内容脚本
├── popup/ # 弹窗界面
│ ├── popup.html # 弹窗HTML
│ ├── popup.js # 弹窗逻辑
│ └── popup.css # 弹窗样式
└── icons/ # 扩展图标
├── icon16.png
├── icon32.png
├── icon48.png
└── icon128.png
1.2 技术架构图
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Content │ │ Background │ │ Popup │
│ Script │────│ Service │────│ Interface │
│ (页面监听) │ │ Worker │ │ (数据展示) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 页面活动 │ │ 时间统计 │ │ 数据可视化 │
│ 状态检测 │ │ 数据存储 │ │ 用户交互 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
2. Manifest V3配置详解
2.1 核心配置解析
首先创建manifest.json,这是扩展的"身份证":
{
"manifest_version": 3,
"name": "网站使用时长统计器",
"version": "1.0",
"description": "统计并显示每日各网站的使用时长",
"permissions": [
"tabs", // 访问标签页信息
"storage", // 本地存储
"idle", // 检测用户空闲状态
"activeTab" // 访问当前活跃标签页
],
"host_permissions": [
"<all_urls>" // 访问所有网站(用于注入content script)
],
"background": {
"service_worker": "background.js" // Manifest V3使用Service Worker
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_start" // 页面开始加载时立即运行
}],
"action": {
"default_popup": "popup/popup.html",
"default_title": "网站使用时长统计"
}
}
2.2 Manifest V2 vs V3 关键差异
| 特性 | Manifest V2 | Manifest V3 |
|---|---|---|
| 后台脚本 | Background Page | Service Worker |
| 权限系统 | 宽泛权限 | 精细化权限控制 |
| API调用 | 同步调用 | Promise-based异步 |
| 安全性 | 较低 | 显著提升 |
3. Service Worker核心逻辑
3.1 设计思路
Service Worker是整个扩展的"大脑",负责:
- 监听标签页切换事件
- 计算并记录使用时长
- 管理数据存储和清理
- 检测用户活跃状态
3.2 WebsiteTimer类设计
class WebsiteTimer {
constructor() {
this.activeTabInfo = null; // 当前活跃标签页信息
this.lastActiveTime = null; // 最后活跃时间戳
this.isUserActive = true; // 用户活跃状态
this.currentDay = this.getTodayKey();
this.initializeEventListeners();
}
// 核心方法概览
handleTabChange() // 处理标签页切换
saveTimeSpent() // 保存时间统计
recordVisit() // 记录访问次数
handleIdleState() // 处理空闲状态
}
3.3 关键技术实现
标签页监听
// 监听标签页激活
chrome.tabs.onActivated.addListener((activeInfo) => {
this.handleTabChange(activeInfo.tabId);
});
// 监听URL变化
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete' && tab.active) {
this.handleTabChange(tabId);
}
});
智能时间统计
async saveTimeSpent() {
if (!this.activeTabInfo || !this.lastActiveTime) return;
const timeSpent = Date.now() - this.lastActiveTime;
// 过滤过短访问(<10秒不统计)
if (timeSpent < 10000) {
console.log(`访问时间过短,跳过统计`);
return;
}
// 更新存储数据
const result = await chrome.storage.local.get([this.currentDay]);
const todayData = result[this.currentDay] || {};
if (!todayData[domain]) {
todayData[domain] = {
timeSpent: 0,
visits: 0,
lastTitle: this.activeTabInfo.title
};
}
todayData[domain].timeSpent += timeSpent;
await chrome.storage.local.set({ [this.currentDay]: todayData });
}
4. Content Script页面监听
4.1 为什么需要Content Script?
虽然Service Worker可以监听标签页切换,但无法检测页面内的用户活跃度。Content Script运行在页面上下文中,能够:
- 监听用户交互事件(点击、滚动、键盘输入)
- 检测页面可见性变化
- 提供更精确的活跃度判断
4.2 PageActivityDetector实现
class PageActivityDetector {
constructor() {
this.lastActivityTime = Date.now();
this.isPageVisible = !document.hidden;
this.activityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll'];
this.setupEventListeners();
}
setupEventListeners() {
// 页面可见性变化
document.addEventListener('visibilitychange', () => {
this.isPageVisible = !document.hidden;
this.reportActivity();
});
// 用户活动事件
this.activityEvents.forEach(eventType => {
document.addEventListener(eventType, () => {
this.handleUserActivity();
}, { passive: true });
});
}
}
5. 弹窗界面开发
5.1 现代CSS设计理念
采用渐变背景和卡片式布局,提升视觉效果:
.header {
background: linear-gradient(135deg, #ff7b4c 0%, #fed9c4 100%);
color: white;
padding: 20px;
text-align: center;
}
.website-item:hover {
background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);
transition: background-color 0.2s ease;
}
5.2 数据渲染优化
renderWebsitesList() {
// 过滤短时访问(<1分钟)
const filteredWebsites = websites.filter(([domain, data]) => {
return data.timeSpent >= 60000;
});
// 按使用时间排序
filteredWebsites.sort((a, b) => b[1].timeSpent - a[1].timeSpent);
// 限制显示数量(最多50个)
const displayWebsites = filteredWebsites.slice(0, 50);
}
5.3 实时数据更新
// 监听存储变化,实时更新界面
chrome.storage.onChanged.addListener((changes, areaName) => {
if (areaName === 'local') {
const today = new Date().toISOString().split('T')[0];
if (changes[today]) {
popupManager.loadAndDisplayData();
}
}
});
6. 数据存储策略
6.1 存储结构设计
// 数据结构示例
{
"2024-03-15": {
"github.com": {
"timeSpent": 3600000, // 毫秒
"visits": 12,
"lastTitle": "GitHub Homepage",
"lastVisit": 1710504000000
},
"stackoverflow.com": {
"timeSpent": 1800000,
"visits": 5,
"lastTitle": "JavaScript Questions"
}
}
}
6.2 数据清理策略
async resetDailyData() {
// 只保留最近7天数据
const sevenDaysAgo = new Date();
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
const cutoffDate = sevenDaysAgo.toISOString().split('T')[0];
const keysToRemove = oldKeys.filter(key => key < cutoffDate);
if (keysToRemove.length > 0) {
await chrome.storage.local.remove(keysToRemove);
}
}
7. 性能优化技巧
7.1 防抖处理
// 定期保存数据(避免频繁写入)
setInterval(() => {
websiteTimer.forceSave();
}, 30000); // 30秒保存一次
7.2 内存管理
// 清理短时访问记录
async cleanupShortVisits() {
const cleanedData = {};
Object.entries(todayData).forEach(([domain, data]) => {
if (data.timeSpent >= 30000) { // 保留>=30秒的记录
cleanedData[domain] = data;
}
});
}
8. 开发调试技巧
8.1 Chrome扩展调试
-
Service Worker调试:
- 访问
chrome://extensions/ - 点击"检查视图 service worker"
- 查看Console日志
- 访问
-
存储数据查看:
- 开发者工具 → Application → Storage → Extension storage
-
权限验证:
// 检查权限是否正确授予 chrome.permissions.contains({ permissions: ['tabs', 'storage'] }, (result) => { console.log('权限状态:', result); });
8.2 常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 时间统计不准确 | 事件监听器未正确绑定 | 检查Chrome APIs权限 |
| 界面数据不更新 | 存储变化监听失效 | 验证storage.onChanged |
| Service Worker崩溃 | 内存泄漏或异常 | 添加错误处理和日志 |
9. 扩展功能建议
基于当前架构,可以轻松扩展以下功能:
9.1 数据可视化
- 使用Chart.js添加使用趋势图表
- 周/月统计报告
- 网站分类标签
9.2 生产力功能
- 设定使用时长目标和提醒
- 网站黑名单/白名单
- 专注模式(屏蔽分散注意力网站)
9.3 数据导出
- 导出CSV/JSON格式数据
- 云端数据同步
- 跨设备数据共享
10. 总结与思考
通过这个项目,我们深入学习了:
- Manifest V3的核心概念和最佳实践
- Service Worker在扩展开发中的应用
- Chrome APIs的高效使用
- 现代前端技术在扩展UI中的运用
10.1 关键收获
- 架构设计的重要性:良好的模块化设计让功能扩展变得简单
- 用户体验细节:智能的时间过滤、美观的界面提升了实用性
- 性能优化意识:合理的数据清理和存储策略保证了长期稳定性