news 2026/9/10 16:05:31

Carbon Trigger 浏览器扩展完全指南:基于 CO2 Signal API 构建碳排放追踪扩展

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Carbon Trigger 浏览器扩展完全指南:基于 CO2 Signal API 构建碳排放追踪扩展

Carbon Trigger 浏览器扩展完全指南:基于 CO2 Signal API 构建碳排放追踪扩展

【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners

本篇导读:Carbon Trigger 是 Web-Dev-For-Beginners 课程中的实战项目,它基于 tmrow 的 CO2 Signal API,将区域电力碳排放数据实时呈现在浏览器扩展图标上。读完本文,你将掌握完整的扩展开发流程:Webpack 打包构建、Edge/Chrome 扩展加载、API 密钥与区域代码配置、localStorage 持久化,以及基于碳强度映射图标颜色的核心算法实现。本文以 翻译版完成代码文档 为骨架,结合仓库内的 完整源码 逐行剖析,保证每一步都可复现、可运行。

Carbon Trigger 扩展:在浏览器工具栏中以彩色圆点实时反映区域电力碳排放强度

项目背景与核心思路

Carbon Trigger 是一款微型网站式浏览器扩展,它的任务是回答一个简单却重要的问题:"我所在区域的电力碳排放现在有多高?"

扩展在安装后,会定期/按需查询 CO2 Signal API,获取指定区域的碳强度(carbon intensity,单位 gCO₂/kWh)化石燃料发电占比(fossil fuel percentage),并通过浏览器扩展栏中一个彩色圆点直观地提示用户当前是否适合执行高耗电活动(例如洗衣服、烘干衣物等)。该"圆点"视觉方案受 Energy Lollipop 扩展(针对加州排放)启发,在仓库的 模块导读 中有明确说明。

整个浏览器扩展模块共三课,与本完成代码对应:

课程主题对应文件
第 1 课浏览器工作原理与扩展安装1-about-browsers/README.md
第 2 课表单、localStorage 与 API 集成2-forms-browsers-local-storage/README.md
第 3 课后台任务、动态图标与性能3-background-tasks-and-performance/README.md

快速开始:安装、构建与加载

关联文档给出了三步上手流程,以下结合 package.json 给出完整说明。

1. 环境要求与依赖安装

前置条件:系统已安装 npm(Node.js 包管理器)。仓库的 package.json 声明了运行环境门槛:

"engines": { "npm": ">=9.0.0", "node": ">=18.0.0" }

将 solution 目录 的代码下载到本地文件夹后,安装依赖:

npm install

该命令会安装两类包(见 package.json):

  • 开发依赖(devDependencies)webpack ^5.105.4webpack-cli ^5.1.4,用于模块打包;
  • 运行依赖(dependencies)axios ^1.15.0,用于发起 CO2 Signal API 请求。

2. Webpack 构建

npm run build

build脚本映射到webpack命令,将 src/index.js 打包为dist目录下的浏览器可加载文件。除此之外 package.json 还提供了开发调试脚本:

"scripts": { "watch": "webpack --watch", "build": "webpack" }
  • npm run watch:监听源码变更并自动重新打包,适合开发期反复调试;
  • npm run build:一次性构建,用于加载和分发。

3. 在 Edge(及 Chromium 内核浏览器)中加载

扩展开发期通过"加载解压缩的扩展"方式安装:

  1. 点击浏览器右上角**"三个点"菜单**,进入"扩展"面板;
  2. 打开**"开发人员模式"**开关;
  3. 选择"加载解压缩的扩展"(Load Unpacked)
  4. 在弹出的文件选择器中打开dist文件夹,扩展即被加载。

在 Edge 的扩展管理页面通过"加载解压缩的扩展"导入 dist 目录

提示:由于新版 Edge 基于 Chromium 内核,扩展 API 与 Chrome 兼容,因此源码中使用的chrome.runtime.*系列 API 在 Edge 中同样有效(这一点在 3-background-tasks-and-performance/README.md 中有明确说明)。Firefox 亦可用于该扩展的开发测试。

4. 获取两个必要配置

扩展真正工作前,需要用户提供两项输入:

配置项获取方式示例
CO2 Signal API Key在 co2signal.com 页面输入邮箱免费申请形如xxxxx-xxxxx的令牌
区域代码(Region Code)依据 Electricity Map 地图对照区域代码表查询波士顿地区使用US-NEISO

区域代码与 Electricity Map 上的电网分区一一对应,中国大陆地区可在地图上查询对应的电网分区编码。填写完成后,扩展栏中的彩色圆点会随区域碳排放强度实时变色。

源码级剖析:扩展是如何工作的

关联文档描述了"输入 API Key 和区域后圆点变色"的最终效果,其背后的完整实现位于 solution/src/index.js。下面按数据流顺序逐段拆解。

DOM 引用捕获

扩展启动时首先通过document.querySelector()捕获所有需要操作的界面元素,分为表单字段结果展示两组:

// form fields const form = document.querySelector('.form-data'); const region = document.querySelector('.region-name'); const apiKey = document.querySelector('.api-key'); // results const errors = document.querySelector('.errors'); const loading = document.querySelector('.loading'); const results = document.querySelector('.result-container'); const usage = document.querySelector('.carbon-usage'); const fossilfuel = document.querySelector('.fossil-fuel'); const myregion = document.querySelector('.my-region'); const clearBtn = document.querySelector('.clear-btn');

这些 CSS 类名与 第 1 课文档 中定义的 HTML 结构一一对应:.region-name.api-key是配置表单的输入框,.carbon-usage.fossil-fuel.my-region是结果区域的数据展示位,.loading.errors负责加载中和报错状态,.clear-btn是"更改区域"按钮。

表单提交与用户配置持久化

扩展在页面底部完成事件绑定并立即初始化:

form.addEventListener('submit', (e) => handleSubmit(e)); clearBtn.addEventListener('click', (e) => reset(e)); //start app init();

handleSubmit首先调用e.preventDefault()阻止浏览器默认的表单刷新行为,随后把输入值交给setUpUser

const handleSubmit = async (e) => { e.preventDefault(); setUpUser(apiKey.value, region.value); }; const setUpUser = async (apiKey, region) => { localStorage.setItem('apiKey', apiKey); localStorage.setItem('region', region); loading.style.display = 'block'; errors.textContent = ''; clearBtn.style.display = 'block'; //make initial call displayCarbonUsage(apiKey, region); };

关键设计点:

  • localStorage 持久化:API Key 与区域代码以键值对形式写入浏览器本地存储,下次打开扩展时无需重新输入;
  • UI 状态切换:保存后立即显示加载指示器、清空历史错误、展示"清除"按钮;
  • 立即发起首次请求:保存配置后马上调用displayCarbonUsage拉取数据。

初始化与重置:记忆用户身份

init()是扩展的状态分派中心,负责判断"老用户还是新用户":

const init = async () => { const storedApiKey = localStorage.getItem('apiKey'); const storedRegion = localStorage.getItem('region'); //set icon to be generic green chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: 'green' }, }); if (storedApiKey === null || storedRegion === null) { // 新用户:展示配置表单 form.style.display = 'block'; results.style.display = 'none'; loading.style.display = 'none'; clearBtn.style.display = 'none'; errors.textContent = ''; } else { // 老用户:直接加载已保存的数据 results.style.display = 'none'; form.style.display = 'none'; displayCarbonUsage(storedApiKey, storedRegion); clearBtn.style.display = 'block'; } };

reset()则让用户更换区域:

const reset = async (e) => { e.preventDefault(); //clear local storage for region only localStorage.removeItem('region'); init(); };

注意这里只清除region而保留apiKey——API Key 无需重复输入,设计细节上保持了较好的用户体验。浏览器扩展的 localStorage 与普通网页隔离,可通过 DevTools 的 Application 面板查看(详见 第 2 课文档)。

API 调用:CO2 Signal 数据获取

displayCarbonUsage是整个扩展的数据引擎,使用 axios 向 CO2 Signal API 发起 GET 请求:

const displayCarbonUsage = async (apiKey, region) => { try { await axios .get('https://api.co2signal.com/v1/latest', { params: { countryCode: region }, headers: { 'auth-token': apiKey }, }) .then((response) => { const data = response?.data?.data; // ✅ Validate required data before using if (data?.carbonIntensity == null || data?.fossilFuelPercentage == null) { throw new Error('Missing carbon intensity or fossil fuel data'); } let CO2 = Math.floor(data.carbonIntensity); calculateColor(CO2); loading.style.display = 'none'; form.style.display = 'none'; myregion.textContent = region; usage.textContent = Math.round(data.carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)'; fossilfuel.textContent = data.fossilFuelPercentage.toFixed(2) + '% (percentage of fossil fuels used to generate electricity)'; results.style.display = 'block'; }); } catch (error) { console.warn('Data fetch failed:', error.message); loading.style.display = 'none'; results.style.display = 'none'; errors.textContent = 'Sorry, data unavailable for the selected region.'; } };

请求细节拆解:

要素说明
端点https://api.co2signal.com/v1/latestCO2 Signal 的实时数据接口
认证Headerauth-token: <apiKey>通过请求头携带 API Key,而非 URL 参数
查询参数countryCode: <region>传入区域代码,如US-NEISO
返回数据data.carbonIntensity碳强度(gCO₂/kWh),用于圆点配色
返回数据data.fossilFuelPercentage化石燃料发电占比(%),展示给用户

健壮性处理(可对照 第 2 课文档 的 fetch 版本理解演进):

  • 可选链 + 数据校验response?.data?.data避免空引用崩溃;carbonIntensityfossilFuelPercentage缺失时主动抛出异常;
  • try/catch 兜底:网络错误或数据不可用时,隐藏 loading 与结果区,在.errors中展示友好提示 "Sorry, data unavailable for the selected region.";
  • UI 联动:数据就绪后隐藏表单、填入区域名、碳强度(克/千瓦时)与化石燃料占比(保留两位小数),再显示结果容器。

颜色计算算法:数据 → 圆点颜色

这是本扩展最有特色的部分,将数值碳强度映射为五种视觉颜色。注意:源码头部的calculateColor是隐式全局函数(未用const声明),这是为了兼容后续课程逐步添加代码的教学节奏,其算法逻辑与 第 3 课文档 完全一致:

calculateColor = async (value) => { let co2Scale = [0, 150, 600, 750, 800]; let colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02']; let closestNum = co2Scale.sort((a, b) => { return Math.abs(a - value) - Math.abs(b - value); })[0]; let num = (element) => element > closestNum; let scaleIndex = co2Scale.findIndex(num); let closestColor = colors[scaleIndex]; chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: closestColor } }); };

算法执行流程

  1. 定义色阶co2Scale = [0, 150, 600, 750, 800]表示碳强度阈值(gCO₂/kWh),colors数组与之对应——绿色(清洁)、黄色(中等)、橙色(偏高)、深棕(很高);
  2. 寻找最近阈值:通过对数组按"与输入值的绝对差"排序取第一项,得到最近的档位;
  3. 定位色标索引:用findIndex找出第一个大于最近阈值的元素下标,映射到对应颜色;
  4. 通知后台更新图标:通过chrome.runtime.sendMessage({ action: 'updateIcon', ... })将颜色发给扩展后台脚本,后台再调用chrome.action.setIcon用 OffscreenCanvas 绘制圆形图标(此部分详见 3-background-tasks-and-performance/README.md 的drawIcon实现)。

注意:co2Scale.sort()原地修改数组。虽然示例代码中排序后立即使用不影响本次结果,但生产代码应使用[...co2Scale].sort()拷贝排序,避免污染原始色阶数组。

数据流全景:从表单到图标

综合以上实现,Carbon Trigger 的完整调用链为:

用户输入 API Key + 区域代码 │ 提交表单 (submit 事件) ▼ handleSubmit() ──► setUpUser() │ ├─ localStorage.setItem('apiKey'/'region') 持久化 │ └─ displayCarbonUsage() 首次拉取 ▼ displayCarbonUsage() ──► axios GET api.co2signal.com/v1/latest │ ├─ header: auth-token │ └─ params: countryCode ▼ 响应数据校验 ──► calculateColor(carbonIntensity) │ └─ chrome.runtime.sendMessage({action:'updateIcon'}) ▼ 后台脚本 chrome.action.setIcon ──► 工具栏彩色圆点更新

扩展启动时init()会先读取 localStorage:若存在历史配置,直接进入数据展示路径;否则展示配置表单。这个"记忆-恢复"闭环正是第 2 课 LocalStorage 与第 3 课后台消息机制的实战融合。

常见问题排查

现象原因处理方式
提示 "data unavailable for the selected region"API Key 无效、区域代码格式错误或网络异常核对auth-tokencountryCode取值,检查控制台console.warn输出
扩展图标不出现/不变色后台脚本未监听updateIcon消息确认dist中后台脚本包含chrome.runtime.onMessage监听与drawIcon函数
修改源码后无变化未重新构建运行npm run build,并在扩展管理页点击"重新加载"
表单反复出现localStorage 被清除重新输入 API Key 与区域代码,或检查浏览器是否清理了扩展存储

深入阅读

  • 完整实现源码:solution/src/index.js
  • 依赖与构建脚本:solution/package.json
  • 第 1 课(浏览器基础与扩展安装):1-about-browsers/README.md
  • 第 2 课(表单、localStorage 与 API):2-forms-browsers-local-storage/README.md
  • 第 3 课(后台任务、动态图标与性能剖析):3-background-tasks-and-performance/README.md
  • 入门脚手架代码(对照学习):start/README.md

【免费下载链接】Web-Dev-For-Beginners24 Lessons, 12 Weeks, Get Started as a Web Developer项目地址: https://gitcode.com/GitHub_Trending/we/Web-Dev-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 16:03:03

武汉洗衣机维修服务推荐,欧米到家专业团队解决家庭洗衣机各种故障和使用难题

前言洗衣机是现代家庭使用频率较高的家电之一&#xff0c;长期运行后容易出现不脱水、不排水、不进水、漏水、异响、无法启动、显示故障代码等问题。尤其武汉地区家庭使用洗衣机频率较高&#xff0c;面对设备突然故障时&#xff0c;选择专业、规范的维修服务非常重要。欧米到家…

作者头像 李华
网站建设 2026/9/10 16:01:10

Calibre 格式转换教程:30 秒把 PDF 变成手机 EPUB

Calibre 格式转换教程&#xff1a;30 秒把 PDF 变成手机 EPUB 【免费下载链接】calibre The official source code repository for the calibre ebook manager 项目地址: https://gitcode.com/GitHub_Trending/ca/calibre 手机上翻扫描版 PDF&#xff0c;每页都要捏合缩…

作者头像 李华
网站建设 2026/9/10 16:00:42

Wayland + NVIDIA 环境下 CC Switch 主界面点击无响应怎么解决?

Wayland NVIDIA 环境下 CC Switch 主界面点击无响应怎么解决&#xff1f; 【免费下载链接】cc-switch A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io 项…

作者头像 李华
网站建设 2026/9/10 15:58:28

无人机分布式监控系统设计与Matlab实现

1. 项目概述无人机搭载相机网络的交互式监控系统正在成为安防、农业巡检、灾害监测等领域的重要技术手段。这种分布式监控方案通过多无人机协同作业&#xff0c;能够覆盖更广的监控区域&#xff0c;实现动态目标跟踪和多角度观测。我在实际项目中发现&#xff0c;传统集中式监控…

作者头像 李华