首页
/ Carbon Trigger 浏览器扩展完整实现解析:基于 CO2 Signal API 的碳足迹提醒工具

Carbon Trigger 浏览器扩展完整实现解析:基于 CO2 Signal API 的碳足迹提醒工具

2026-09-07 11:52:55作者:何将鹤

Carbon Trigger 是 Web-Dev-For-Beginners 开源课程第 5 模块「浏览器扩展」的收官实战项目:利用 tmrow 提供的 CO2 Signal API 实时查询某个地区的电力碳排放强度,并把结果以「彩色圆点」图标的形式直接呈现在浏览器工具栏中,提醒你在电网碳排较低时再安排洗衣机、烘干机等高耗电活动。本文以 solution 完整代码说明(即本仓库 translations/ar/5-browser-extension/solution/translation/README.fr.md 对应的阿拉伯语译本源文档)为骨架,结合 5-browser-extension/solution/src/index.js5-browser-extension/solution/package.json 等源码实现,带你走通「环境准备 → 构建打包 → 浏览器加载 → API 配置 → 源码级原理」的完整链路。

Carbon Trigger 扩展运行截图

扩展要解决什么问题

电力供应商无法区分同一电网下电流的来源是煤、天然气还是风能、太阳能,因此「现在用电是否环保」对普通用户是不可见的。Carbon Trigger 的思路是把这一信息可视化:在浏览器扩展栏显示一个随区域碳排放强度实时变色的圆点,让用户在看到数据后自行判断当下是否适合进行能耗较高的活动。

该扩展即用即查(ad hoc):用户只需在弹窗表单中输入 CO2 Signal 的 API Key 与地区代码,即可获得本地电力碳排放强度读数,并以此为参考安排用电活动。例如区域电网负载较高时,可以推迟使用烘干机这类高碳排活动。其「彩色圆点」图标方案借鉴了面向加州碳排放的 Energy Lollipop 扩展的设计理念,这一概念来源在 5-browser-extension/README.md 的 Credits 部分有明确说明。

在课程体系中,本扩展配套三节前置课程:浏览器工作原理与扩展部署表单与本地存储后台任务与性能优化。模块总体面向 Edge、Chrome、Firefox 设计,教程以 Edge 为演示环境。

环境准备与代码结构

开始前需要一台装有 npm 的电脑,并下载课程代码副本。以本仓库的 solution 目录为基准,其关键文件如下:

文件 作用
5-browser-extension/solution/package.json 项目依赖与构建脚本定义
5-browser-extension/solution/src/index.js 扩展弹窗(popup)全部业务逻辑
5-browser-extension/start/src/index.js 初学者脚手架,仅含 6 步注释占位
5-browser-extension/solution/README.md 完成版代码的使用说明

package.json 可见运行时约束与依赖细节:

  • 运行时要求engines 字段声明 node >= 18.0.0npm >= 9.0.0,低于该版本可能出现安装或构建异常;
  • 依赖(dependencies)axios ^1.15.0,用于发起 CO2 Signal API 请求;
  • 开发依赖(devDependencies)webpack ^5.105.4webpack-cli ^5.1.4,负责把 src/index.js 打包输出到 dist 目录;
  • 构建脚本buildwebpack,另有 watchwebpack --watch)便于开发期增量打包;
  • 元信息:关键词 chrome extension / edge extension / carbon usage tracker,许可 MIT。

初学者可对照 start 脚手架 学习——它把整个扩展逻辑拆成了带编号的 6 个步骤注释(表单字段、结果区、API 调用、用户凭据设置、表单提交处理、初始化检查、事件监听与启动),自上而下理解 solution 源码会轻松很多。

安装依赖并构建扩展

在 solution 目录下依次执行两条命令即可完成构建。先安装全部依赖包:

npm install

再通过 webpack 构建扩展:

npm run build

构建完成后会在目录中生成 dist 文件夹,其中就是可被浏览器以「未打包扩展」方式加载的产物。

在浏览器中加载扩展

以 Edge 为例(该流程对同为 Chromium 内核的 Chrome 同样适用),加载步骤如下:

  1. 点击浏览器右上角「三点」菜单,进入「扩展」(Extensions)面板;
  2. 开启「开发人员模式」;
  3. 选择「加载解压缩的扩展」(Load Unpacked)以加载新扩展;
  4. 在弹出对话框中选择之前构建生成的 dist 文件夹,扩展即被加载。

在 Edge 中加载未打包扩展

需要强调的是:在 Edge 中开发时使用的是 chrome.* 系列 API(详见后文),因为新版 Edge 基于 Chromium 浏览器引擎构建,可以直接复用这些工具——这一兼容性说明同样出现在 第 3 课 README 中。

获取 API Key 与地区代码

扩展只有在拿到两类凭据后才能真正工作:

  1. CO2 Signal API Key:前往 co2signal.com 官网,在页面输入邮箱即可通过邮件获取;
  2. 地区代码(Zone Code):对应 Electricity Map 地图上各区域的标识符,例如波士顿使用 US-NEISO,可在 electricitymap.org/map 对照地图查找(教程给出的查询入口为 http://api.electricitymap.org/v3/zones)。

把 API Key 与地区代码输入扩展弹窗界面后,浏览器扩展栏中的彩色圆点会变为对应当前区域能耗的颜色,从而提示哪些高能耗活动适合此刻进行。

源码级解析:从表单输入到结果展示

solution 的全部弹窗逻辑集中在 5-browser-extension/solution/src/index.js,核心调用链如下。

1. DOM 元素绑定

脚本顶部一次性取得表单字段与结果显示区两类 DOM 引用(表单字段为 .form-data 下的 .region-name.api-key;结果区包括 .errors.loading.result-container.carbon-usage.fossil-fuel.my-region.clear-btn),后续所有读写都通过这些引用完成。

2. 发起 API 请求与数据校验

displayCarbonUsage 函数 负责真正调用 CO2 Signal 接口:

axios
	.get('https://api.co2signal.com/v1/latest', {
		params: { countryCode: region },
		headers: { 'auth-token': apiKey },
	})

值得注意的请求细节:API Key 通过名为 auth-token 的请求头发送;地区代码通过 countryCode 查询参数传递;接口端点固定为 /v1/latest。收到响应后先对数据做存在性校验(data.carbonIntensitydata.fossilFuelPercentage 缺一即抛错),随后:

  • Math.floor 取出碳强度整数值并交给 calculateColor 换算图标颜色;
  • 隐藏 loading 与表单,显示结果区;
  • 写入三个文本项:区域代码、carbonIntensity(保留格式「xx grams (grams C02 emitted per kilowatt hour)」)、fossilFuelPercentage.toFixed(2)(化石燃料发电占比百分比);
  • 任一环节失败则进入 catch 分支:隐藏加载态与结果区,错误栏显示「Sorry, data unavailable for the selected region.」提示,并用 console.warn 输出具体失败原因。

3. 碳强度到颜色的映射算法

calculateColor 是整个「圆点」系统的视觉核心。代码里预置了两组等长数组:

碳强度刻度(gCO2/kWh) 对应颜色 语义
0 #2AA364(绿) 清洁电网
150 #F5EB4D(黄) 中度
600 #9E4229(橙棕) 高碳排
750 #381D02(深棕) 很高
800 #381D02(深棕) 很高

算法分三步:先用「与输入值绝对差最小」的排序找到最接近的刻度点;再通过 co2Scale.findIndex(num) 找到第一个大于该刻度点的下标(num = (element) => element > closestNum);最后用该下标在颜色数组中取出对应颜色。若当前取到的 CO2 值位于两个刻度之间(例如介于 0 与 150 之间),会命中绿色——因此绿色并非仅在刻度 0 上出现,凡是落到「距离绿刻度最近」区间的值都会显示为绿色,实现近似分段连续的颜色反馈。

取色完成后通过消息机制通知浏览器更新图标:

chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: closestColor } });

chrome.runtime API 相当于扩展的「神经系统」:它负责扩展各脚本间的消息通信、生命周期事件管理以及 URL 相对路径到绝对路径的转换。

4. 本地存储与状态初始化

setUpUserinit 共同实现「记住用户」的能力:

  • 表单提交后,setUpUserapiKeyregion 写入 localStorage,立即显示加载动画并触发首次数据请求;
  • 扩展每次打开时执行 init():先发送默认绿色图标的 updateIcon 消息,让用户从加载起就看到「扩展在正常工作」的可视反馈;随后检查 localStorage——若无已存凭据则展示表单,若有则跳过表单直接请求数据并显示清除按钮;
  • reset 函数 只移除 region 一项(localStorage.removeItem('region'))后重新 init(),这也是「清除当前地区数据」按钮的行为——注意实现上故意保留了 API Key,便于用户下次只需重选地区。

事件绑定位于文件末尾:formsubmit 触发 handleSubmitclearBtnclick 触发 reset,最后调用一次 init() 启动应用。

消息传递与后台图标绘制(背景任务原理)

从代码结构看,src/index.js 只负责「计算颜色并发出 updateIcon 消息」,真正的图标绘制发生在后台脚本中。按照 第 3 课 README 的讲解,需要为构建产物 dist 中的 background.js 注册消息监听:

// Listen for messages from the content script
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
	if (msg.action === 'updateIcon') {
		chrome.action.setIcon({ imageData: drawIcon(msg.value) });
	}
});

// Draw dynamic icon using Canvas API
// Borrowed from energy lollipop extension - nice feature!
function drawIcon(value) {
	// Create an offscreen canvas for better performance
	const canvas = new OffscreenCanvas(200, 200);
	const context = canvas.getContext('2d');

	// Draw a colored circle representing carbon intensity
	context.beginPath();
	context.fillStyle = value.color;
	context.arc(100, 100, 50, 0, 2 * Math.PI);
	context.fill();

	// Return the image data for the browser icon
	return context.getImageData(50, 50, 100, 100);
}

其工作流程可概括为一条消息链:calculateColorchrome.runtime.sendMessage({action:'updateIcon', ...}) → 后台脚本 onMessage 监听 → drawIconOffscreenCanvas 绘制彩色圆形 → chrome.action.setIcon 更新工具栏图标。这里有两个值得学习的性能点:

  • OffscreenCanvas 离屏绘制:不阻塞主界面线程,保证弹窗 UI 流畅,符合课程强调的「高效渲染不阻塞 UI」原则;
  • 消息驱动的职责分离:数据抓取、颜色换算、图标渲染分属不同脚本上下文,通过消息传递解耦,与课程的 SPA/渲染管线(Parse HTML → DOM Tree → Render Tree → Layout → Paint → Composite)优化思想一脉相承。

关于 chrome.action.setIconchrome.browserAction 的版本差异,具体取决于扩展 manifest 中声明的 manifest version,实际使用请以构建产物所在 dist 目录内的 manifest 配置为准。若希望独立剖析扩展性能,第 3 课还建议直接在扩展自身(它本身就是独立的浏览器实例)内启动 DevTools,进入 Performance 面板录制、分析时间线与事件日志,观察是否存在超过 15ms 的长任务。

把扩展用起来与课程延伸

配置完成后,扩展栏圆点的颜色会随区域实时碳排数据变化:绿色代表当下适合运行高耗电任务,深棕则提示电网正处于高碳状态。这个「随用随查」的提醒工具完整展示了浏览器扩展开发中的几个核心技能组合:表单交互、异步 API 调用、localStorage 持久化、chrome.runtime 消息传递、Canvas 动态图标绘制,以及后台任务与性能意识。

如果你想从零练习,可对照 start 脚手架 的编号占位逐步补全逻辑;若想深入原理,可继续阅读第 1 课了解浏览器扩展架构(扩展即「为特定任务量身定制的小型网站」),第 2 课深入表单校验与本地存储,第 3 课了解渲染管线、资源优化与性能剖析工具。完成后用 npm run build 重新构建、在浏览器「扩展」页点击刷新重载扩展(不要漏掉这步),即可观察图标随全球各地真实碳数据的变化。

登录后查看全文
热门项目推荐
相关项目推荐