Chrome 扩展开发完全指南:从零打造个性新标签页
本文不仅会系统讲解 Chrome 扩展的核心概念,还会通过一个完整的实战项目——自定义新标签页,带你一步步掌握扩展开发的完整流程。无论你是前端新手还是想拓展技术栈的开发者,都能从中受益。
一、Chrome 扩展基础
Chrome 扩展本质上是 HTML、CSS、JavaScript 文件的集合,可以增强浏览器功能、修改网页行为、提供自定义界面等。它由几个关键组件构成,下面我们逐一介绍。
1. 核心文件:manifest.json
每个扩展都必须有一个 manifest.json 文件,它就像应用的“身份证”,声明了扩展的名称、版本、权限以及各功能模块的入口。
最小示例:
json
{
"manifest_version": 2,
"name": "我的第一个扩展",
"version": "1.0",
"description": "一个简单的Chrome扩展",
"browser_action": {
"default_popup": "popup.html"
},
"permissions": ["activeTab"]
}
manifest_version:当前必须为 2(或 3,但本文基于 V2)。browser_action:定义工具栏图标及点击后弹出的页面(default_popup)。permissions:声明需要访问的 Chrome API 或网站权限。
2. 扩展的主要组件
- 背景脚本(Background Script) :运行在后台,处理事件、管理状态。在 V2 中可以是持久页面或事件页面。
- 内容脚本(Content Script) :注入到网页中,可以读取/修改 DOM,但受同源策略限制。
- 弹出页面(Popup) :点击工具栏图标时显示的小窗口,通常用于快速交互。
- 选项页面(Options Page) :用户自定义扩展设置的页面。
- 覆盖页面(Override Pages) :可以覆盖浏览器的默认页面,如新标签页、历史记录页等。
3. 调试与安装
- 打开
chrome://extensions,开启“开发者模式”。 - 点击“加载已解压的扩展程序”,选择你的项目文件夹即可安装。
- 扩展的代码修改后,点击刷新按钮即可重新加载。
二、实战项目:chrome-theme —— 自定义新标签页
本项目是一个功能完整的新标签页替换扩展,支持:
- 动态显示时间(年月日、星期、时分秒)
- 每日一句“彩虹屁”
- 可切换的搜索引擎(百度、必应、谷歌)
- 本地/网络图片作为背景,并自动提取主色调整文字颜色
- 最近访问历史记录
- 实时天气信息(基于IP定位)
📸 效果预览
安装扩展后,新标签页将呈现如下样式(实际运行截图):
项目结构
.
├── README.md
├── asset/font # 自定义字体文件
├── background.html # 新标签页的HTML结构
├── css/background.css # 样式文件
├── img/ # 扩展图标
├── inject/index.js # 注入所有页面的脚本(本项目中为空)
├── js/
│ ├── background.js # 主逻辑:页面初始化、事件绑定
│ ├── chrome_runtime.js # Chrome特定功能(历史记录)
│ ├── comm_js.js # 公共辅助函数
│ ├── localstorage.js # 本地存储初始化
│ ├── search_engine.js # 搜索引擎配置
│ └── weather.js # 天气功能
└── manifest.json
1. manifest.json 详解
{
"name": "wangfpp-theme",
"version": "0.1.0",
"description": "自定义Chrome主题",
"manifest_version": 2,
"browser_action": {
"default_icon": "img/64.png"
},
"background": {
"scripts": [ "js/background.js" ],
"css": [ "css/background.css" ]
},
"chrome_url_overrides": {
"newtab": "background.html"
},
"content_scripts": [
{
"all_frames": true,
"js": [ "inject/index.js" ],
"match_about_blank": true,
"matches": [ "<all_urls>" ],
"run_at": "document_start"
}
],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"permissions": [ "fontSettings", "<all_urls>", "tabs", "storage", "unlimitedStorage", "topSites", "contextMenus", "history", "fileBrowserHandler" ]
}
重点解读:
chrome_url_overrides:指定覆盖的页面,"newtab": "background.html"表示每次新建标签页都会加载background.html。background:声明后台脚本和样式。这里scripts和css会构成一个后台页面,后台脚本可以一直运行(V2 特性)。content_scripts:向所有页面注入脚本(本项目中为空),可用于实现全局样式修改。permissions:请求了多项权限,包括history(读取历史记录)、storage(本地存储)、<all_urls>(访问所有网站)等,这些都是实现功能所必需的。
2. 新标签页页面 background.html
这个文件定义了新标签页的布局。为了简洁,我们只展示关键部分:
<div class="date"></div>
<input id="search" type="text" placeholder="搜索一下...">
<div id="chp"></div>
<div class="weather"></div>
<div id="history_container"></div>
<div id="set_btn">⚙️</div>
<div id="menu" class="hidemenu">
<!-- 搜索引擎切换、背景设置等 -->
</div>
样式写在 css/background.css 中,你可以自由调整布局、字体和配色。
3. 核心功能实现
3.1 时间实时更新(background.js)
window.onload = e => {
let date_node = document.querySelector('.date');
if (date_node) {
date_node.innerHTML = formatDateString();
setInterval(() => {
if (date_node) {
date_node.innerHTML = formatDateString();
}
}, 1000);
}
}
formatDateString 定义在 comm_js.js 中,返回包含时、分、秒和年月日的 HTML 字符串。
3.2 搜索引擎切换
配置文件 search_engine.js 定义了搜索引擎字典:
const search_gine_dict = {
"baidu": {
text: "百度",
create_url: val => `https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=${val}`
},
"biying": {
text: "必应",
create_url: val => `https://www.bing.com/search?q=${val}`
},
"google": {
text: "谷歌",
create_url: val => `http://www.google.cn/search?q=${val}&hl=zh-CN&client=aff- 360daohang&hs=yhE&affdom=360.cn&newwindow=1&start=10& amp;sa=N`
}
}
在 background.js 中,监听搜索框回车事件:
input_node.onkeydown = function (e) {
let { keyCode, target } = e;
let { value } = target;
if (keyCode === 13 && value) {
let engine = window.localStorage.getItem("search_engine") || search_gine_list[0];
let url = search_gine_dict[engine].create_url(value);
window.location.href = url;
target.value = "";
}
}
菜单中的单选框用于修改本地存储的搜索引擎值。
3.3 背景图片与动态取色(亮点功能)
用户可以上传本地图片或输入网络图片 URL 作为背景,扩展会分析图片中特定区域(日期区域、天气区域、彩虹屁区域)的主色,并设置文字颜色为反色,以保证对比度。
关键代码在 background.js 的 setRootBG 函数中:
function setRootBG(url) {
if (root_node) {
root_node.setAttribute("style", `background: url(${url});background-size: cover`);
let image = new Image();
image.onload = function(e) {
if (storage.getItem("color_width_img") == "1") {
// 获取各区域的位置和大小
let { offsetTop, offsetLeft, offsetWidth, offsetHeight } = chp_node;
let { width, height } = e.target;
if (!(width >= 2000 || height >= 2000)) { // 避免大图性能问题
let pixel = getImagePix(image); // 获取像素矩阵
let _date_color = areaPixAverage(pixel, [0, 166], [0, 53]); // 日期区域
let weather_color = areaPixAverage(pixel, [width-188, width], [0, 60]); // 天气区域
let chp_color = areaPixAverage(pixel, [offsetLeft, offsetLeft + offsetWidth], [offsetTop, offsetTop + offsetHeight]); // 彩虹屁区域
setSearchBg(input_node, pixel);
// 通过CSS变量传递颜色
root_node.style.setProperty("--date_color", _date_color);
root_node.style.setProperty("--weather-color", weather_color);
root_node.style.setProperty("--chp_color", chp_color);
}
}
}
image.src = url;
}
}
getImagePix:将图片绘制到 canvas,提取每个像素的 RGBA 值,生成二维数组。areaPixAverage:计算指定矩形区域的平均 RGB,并返回其反色。- 搜索框的背景色也会根据区域亮度动态调整(深色背景配浅色文字,反之亦然)。
3.4 彩虹屁 API
function createChp(node) {
fetch('https://chp.shadiao.app/api.php?').then(res => res.text())
.then(res => {
if (res && node) node.innerHTML = res;
});
}
这个 API 返回纯文本,直接插入即可。
3.5 天气功能(weather.js)
流程:
- 通过
ip-api.com获取当前 IP 的经纬度(免费,无需密钥)。 - 将经纬度 POST 给
data.cma.cn(中国气象局数据接口)获取实时天气。 - 更新 DOM,展示城市、天气状况、温度、风力等。
- 每 3 小时自动刷新。
fetch(`http://ip-api.com/json/?lang=zh-CN`).then(res => res.json())
.then(res => {
let { lat, lon } = res;
fetch("http://data.cma.cn/kbweb/home/live", {
method: "POST",
body: JSON.stringify({ lat, lon, type: "1" }),
headers: { "Content-type": "application/json" }
}).then(res => res.json())
.then(res => {
// 解析并渲染天气数据
});
});
注意:由于 API 可能变更,实际使用时建议替换为更稳定的天气服务(如和风天气、OpenWeatherMap),并处理好跨域问题(可在后台脚本中请求)。
3.6 历史记录显示(chrome_runtime.js)
利用 Chrome 的 chrome.history.search API 获取最近 10 条记录:
if (window.localStorage.getItem("show_history") == "1") {
chrome.history.search({text: '', maxResults: 10}, function(data) {
let history_item = "";
data.forEach(function(page) {
history_item += `
<div class="history_item">
<a href="${page.url}">
<img src="chrome://favicon/size/20@2x/${page.url}" alt="icon"/>
<p class="title">${page.title}</p>
</a>
</div>
`;
});
history_container.innerHTML = history_item;
});
} else {
history_container.style.display = "none";
}
注意:需要在 manifest 中申请 "history" 权限。
4. 本地存储初始化(localstorage.js)
在扩展首次运行时,设置默认值:
localStorage.getItem("search_engine") || localStorage.setItem("search_engine", "baidu");
localStorage.getItem("screen_bg") || localStorage.setItem("screen_bg", "https://images.pexels.com/photos/417074/pexels-photo-417074.jpeg");
localStorage.getItem("color_width_img") || localStorage.setItem("color_width_img", "0");
localStorage.getItem("show_history") || localStorage.setItem("show_history", "0");
5. 辅助函数(comm_js.js)
提供了常用的 DOM 操作和格式化函数,如 addClass、removeClass、doubleNum、weekParse 等,方便复用。
三、打包与发布
- 在
chrome://extensions中,点击“打包扩展程序”。 - 选择项目根目录,Chrome 会自动生成
.crx和.pem文件(私钥请妥善保管)。 - 如果你想发布到 Chrome 网上应用店,需要注册开发者账号(一次性费用),上传包含所有文件的 zip 包,等待审核。
四、扩展与优化建议
- 性能优化:背景取色时对过大图片做了限制,你也可以考虑使用
createImageBitmap或 Web Worker 处理像素数据。 - 天气 API 替换:现有 API 可能不稳定,建议改用免费且稳定的接口,如和风天气(需注册)、OpenWeatherMap(需 API Key)。
- 添加更多小部件:你可以在
background.html中自由添加模块,比如名言警句、待办事项等。 - 适配 Manifest V3:Chrome 即将全面转向 V3,迁移时需要将后台脚本改为 Service Worker,并调整权限声明。可参考官方迁移指南。
五、结语
通过这个项目,我们不仅掌握了 Chrome 扩展的基本开发流程,还深入实践了图片处理、API 调用、Chrome 特有 API 的使用。希望你能在此基础上发挥创意,打造出属于自己的个性化浏览器工具。
如果你在开发过程中遇到问题,欢迎在评论区交流,也欢迎给项目点个 star 支持一下~
项目完整代码:[GitHub 仓库地址](github.com/wangfpp/chr…