什么是 Chrome 扩展?
Chrome 扩展是用 HTML/CSS/JavaScript 开发的浏览器插件,可以:
- 修改网页内容
- 拦截网络请求
- 存储本地数据
- 与后端 API 通信
Manifest V3 是最新版本,2023 年起强制使用。
项目实战:书签保存插件
我们将开发一个实用的书签保存插件:
- 点击图标弹出界面
- 自动获取当前页面标题和 URL
- 发送到后端 API 保存
- 显示已保存书签列表
步骤 1:创建项目结构
mkdir chrome-bookmark-extension
cd chrome-bookmark-extension
# 项目结构
# ├── manifest.json
# ├── popup.html
# ├── popup.js
# ├── popup.css
# ├── background.js
# ├── content.js
# └── icons/
# ├── icon16.png
# ├── icon48.png
# └── icon128.png
步骤 2:编写 manifest.json
{
"manifest_version": 3,
"name": "Bookmark Saver",
"version": "1.0.0",
"description": "一键保存当前网页到书签管理器",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"default_title": "保存书签"
},
"permissions": [
"activeTab",
"storage",
"scripting"
],
"host_permissions": [
"https://api.yourdomain.com/*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
步骤 3:创建 popup 界面
popup.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bookmark Saver</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container">
<h1>🔖 保存书签</h1>
<div class="form-group">
<label for="title">标题</label>
<input type="text" id="title" placeholder="页面标题">
</div>
<div class="form-group">
<label for="url">URL</label>
<input type="url" id="url" placeholder="页面地址">
</div>
<div class="form-group">
<label for="tags">标签</label>
<input type="text" id="tags" placeholder="用逗号分隔,如:技术,教程">
</div>
<button id="saveBtn" class="btn-primary">保存</button>
<button id="getInfoBtn" class="btn-secondary">获取当前页面信息</button>
<div id="message" class="message"></div>
<hr>
<h2>最近保存</h2>
<ul id="bookmarkList"></ul>
</div>
<script src="popup.js"></script>
</body>
</html>
步骤 4:添加样式
popup.css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 350px;
padding: 16px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 14px;
background: #f5f5f5;
}
.container {
background: white;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
font-size: 18px;
margin-bottom: 16px;
color: #333;
}
h2 {
font-size: 14px;
margin: 16px 0 8px;
color: #666;
}
.form-group {
margin-bottom: 12px;
}
label {
display: block;
margin-bottom: 4px;
color: #555;
font-weight: 500;
}
input {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 13px;
}
input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
}
.btn-primary {
width: 100%;
padding: 10px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
margin-bottom: 8px;
}
.btn-primary:hover {
background: #0056b3;
}
.btn-secondary {
width: 100%;
padding: 8px;
background: #6c757d;
color: white;
border: none;
border-radius: 4px;
font-size: 13px;
cursor: pointer;
}
.btn-secondary:hover {
background: #545b62;
}
.message {
margin-top: 12px;
padding: 8px;
border-radius: 4px;
font-size: 13px;
display: none;
}
.message.success {
display: block;
background: #d4edda;
color: #155724;
}
.message.error {
display: block;
background: #f8d7da;
color: #721c24;
}
hr {
margin: 16px 0;
border: none;
border-top: 1px solid #eee;
}
#bookmarkList {
list-style: none;
max-height: 200px;
overflow-y: auto;
}
#bookmarkList li {
padding: 8px;
border-bottom: 1px solid #eee;
font-size: 12px;
}
#bookmarkList li:last-child {
border-bottom: none;
}
#bookmarkList a {
color: #007bff;
text-decoration: none;
word-break: break-all;
}
#bookmarkList a:hover {
text-decoration: underline;
}
步骤 5:编写 popup 逻辑
popup.js:
const API_URL = 'https://api.yourdomain.com';
const API_TOKEN = 'your-secret-token';
document.addEventListener('DOMContentLoaded', () => {
const saveBtn = document.getElementById('saveBtn');
const getInfoBtn = document.getElementById('getInfoBtn');
const titleInput = document.getElementById('title');
const urlInput = document.getElementById('url');
const tagsInput = document.getElementById('tags');
const messageDiv = document.getElementById('message');
const bookmarkList = document.getElementById('bookmarkList');
// 获取当前页面信息
async function getCurrentTabInfo() {
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
titleInput.value = tab.title;
urlInput.value = tab.url;
} catch (error) {
showMessage('获取页面信息失败:' + error.message, 'error');
}
}
// 保存书签
async function saveBookmark() {
const title = titleInput.value.trim();
const url = urlInput.value.trim();
const tags = tagsInput.value.split(',').map(t => t.trim()).filter(t => t);
if (!title || !url) {
showMessage('请填写标题和 URL', 'error');
return;
}
try {
const response = await fetch(`${API_URL}/bookmarks`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_TOKEN}`
},
body: JSON.stringify({ title, url, tags })
});
const data = await response.json();
if (response.ok) {
showMessage('保存成功!', 'success');
loadBookmarks();
// 清空表单
titleInput.value = '';
urlInput.value = '';
tagsInput.value = '';
} else {
showMessage('保存失败:' + data.error, 'error');
}
} catch (error) {
showMessage('网络错误:' + error.message, 'error');
}
}
// 加载书签列表
async function loadBookmarks() {
try {
const response = await fetch(`${API_URL}/bookmarks`);
const data = await response.json();
bookmarkList.innerHTML = '';
const bookmarks = data.bookmarks || [];
bookmarks.slice(0, 10).forEach(bookmark => {
const li = document.createElement('li');
li.innerHTML = `
<a href="${bookmark.url}" target="_blank">${bookmark.title}</a>
<br><small>${new Date(bookmark.createdAt).toLocaleDateString()}</small>
`;
bookmarkList.appendChild(li);
});
} catch (error) {
console.error('加载书签失败:', error);
}
}
// 显示消息
function showMessage(text, type) {
messageDiv.textContent = text;
messageDiv.className = `message ${type}`;
setTimeout(() => {
messageDiv.className = 'message';
}, 3000);
}
// 绑定事件
getInfoBtn.addEventListener('click', getCurrentTabInfo);
saveBtn.addEventListener('click', saveBookmark);
// 初始化加载书签
loadBookmarks();
});
步骤 6:Background Service Worker
background.js:
// 监听扩展图标点击(可选)
chrome.action.onClicked.addListener((tab) => {
console.log('Extension icon clicked');
});
// 监听安装事件
chrome.runtime.onInstalled.addListener((details) => {
console.log('Extension installed:', details.reason);
// 初始化存储
chrome.storage.local.set({
installedAt: new Date().toISOString()
});
});
// 消息处理(可选)
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'getCurrentTab') {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
sendResponse({ tab: tabs[0] });
});
return true; // 保持消息通道开放
}
});
步骤 7:Content Script(可选)
content.js:
// 在网页中运行的脚本
console.log('Bookmark Saver content script loaded');
// 可以添加页面内功能,比如浮动按钮
function addFloatingButton() {
const button = document.createElement('button');
button.textContent = '🔖 保存';
button.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
padding: 10px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
z-index: 9999;
`;
button.addEventListener('click', () => {
chrome.runtime.sendMessage({ action: 'saveCurrentPage' });
});
document.body.appendChild(button);
}
// 页面加载完成后添加按钮
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', addFloatingButton);
} else {
addFloatingButton();
}
步骤 8:准备图标
创建 icons/ 文件夹,准备三个尺寸的 PNG 图标:
icon16.png(16x16)icon48.png(48x48)icon128.png(128x128)
步骤 9:本地测试
- 打开 Chrome 浏览器
- 访问
chrome://extensions/ - 开启右上角 “开发者模式”
- 点击 “加载已解压的扩展程序”
- 选择你的项目文件夹
测试功能:
- 点击扩展图标
- 点击 “获取当前页面信息”
- 填写标签并保存
- 检查是否成功
步骤 10:发布到 Chrome Web Store
打包扩展
- 在
chrome://extensions/页面 - 点击 “打包扩展程序”
- 选择项目目录
- 生成
.crx和.pem文件
提交审核
- 访问 Chrome Web Store Developer Dashboard
- 支付一次性费用 $5
- 创建新应用
- 上传
.crx文件 - 填写应用信息(标题、描述、截图等)
- 提交审核(通常 1-3 天)
常见问题 FAQ
Q1: Manifest V2 和 V3 有什么区别?
V3 主要变化:
- Background page → Service Worker
- 移除部分权限
- 更严格的 CSP 策略
Q2: 如何调试扩展?
- Popup: 右键扩展图标 → “检查弹出内容”
- Background:
chrome://extensions/→ 查看 “Service Worker” - Content Script: 在网页中按 F12
Q3: 如何存储数据?
// 本地存储
chrome.storage.local.set({ key: 'value' });
chrome.storage.local.get(['key'], (result) => {
console.log(result.key);
});
// 同步存储(跨设备)
chrome.storage.sync.set({ key: 'value' });
Q4: 如何请求更多权限?
在 manifest.json 中添加:
"permissions": [
"tabs",
"bookmarks",
"cookies",
"webRequest"
]
Q5: 扩展不工作怎么办?
检查:
- manifest.json 格式是否正确
- 文件路径是否正确
- Chrome 版本是否支持 Manifest V3
- 查看控制台错误信息
进阶功能
| 功能 | API |
|---|---|
| 标签管理 | chrome.tabs |
| 书签管理 | chrome.bookmarks |
| 网络请求拦截 | chrome.webRequest |
| 上下文菜单 | chrome.contextMenus |
| 通知 | chrome.notifications |
| 快捷键 | chrome.commands |
总结
你现在拥有:
✅ 完整的 Chrome 扩展 ✅ Popup 界面 ✅ Background Service Worker ✅ Content Script ✅ 后端 API 集成
下一步:
- 添加更多功能(搜索、分类、编辑)
- 优化 UI/UX
- 发布到 Chrome Web Store
💼 需要定制扩展开发?
我提供 Chrome 扩展开发服务:
| 服务 | 价格 |
|---|---|
| 简单扩展 | $100+ |
| 中等复杂度 | $300+ |
| 完整 SaaS 扩展 | $500+ |
📧 联系:[email protected]