Web-Dev-For-Beginners 实战:构建 Carbon Trigger 碳排放浏览器扩展(CO2 Signal API + Manifest V3) Web-Dev-For-Beginners 实战构建 Carbon Trigger 碳排放浏览器扩展CO2 Signal API Manifest V3【免费下载链接】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 教程第 5 模块的最终成品一个运行在 Edge、Chrome 等 Chromium 浏览器上的扩展通过 tmrow 的 CO2 Signal API 实时查询你所在区域的电力碳排放强度并在浏览器工具栏上用彩色圆点直观提示现在是否适合做高耗电的事。读完本文你将掌握如何获取 API Key、安装依赖、用 Webpack 构建、在 Edge 中加载未打包扩展并深入理解表单交互、localStorage 持久化、异步 API 调用与后台图标更新Manifest V3的完整实现原理。一、扩展是什么让用电时机可视化现代电网的碳排放强度随时间和地区不断波动——同一台烘干机在高峰时段运行产生的碳足迹可能远高于低峰时段。Carbon Trigger 的核心思路是把我这一地区现在的电有多脏压缩成一个直观的信号用户在扩展表单中填入 CO2 Signal 的 API Key 和所在区域的代码后扩展调用 CO2 Signal API 获取实时数据并展示当前区域的碳排放强度每千瓦时排放的二氧化碳克数发电中化石燃料所占的百分比。随后扩展把碳排放数值映射到一组颜色并通过浏览器扩展栏上的彩色圆点给出即时反馈绿色代表当前电力较清洁、适合进行耗电活动黄色与红色则提示现在不是好时机。这套圆点交互概念源自 Energy Lollipop 扩展对加州排放的呈现方式见 5-browser-extension/README.md 的 Credits 说明。Carbon Trigger 扩展界面填写区域代码与 API Key 后返回碳排放强度与化石燃料占比。二、代码仓库结构从骨架到完成版整个模块按课程学习 分步练习 最终方案组织与本扩展直接相关的目录如下路径作用5-browser-extension/start/src/index.js练习起点仅含标注了编号1~6的空函数骨架供学习者逐步填充5-browser-extension/solution/src/index.js完成版主逻辑DOM 引用、表单处理、localStorage、API 调用、颜色计算5-browser-extension/solution/dist/manifest.jsonManifest V3 扩展清单5-browser-extension/solution/dist/background.js后台 Service Worker监听消息并动态绘制图标5-browser-extension/solution/dist/index.html扩展弹出层popup页面结构5-browser-extension/solution/dist/styles.css弹出层样式基于 Basic.css5-browser-extension/solution/package.json依赖与构建脚本Webpack axios5-browser-extension/2-forms-browsers-local-storage/README.md配套课程表单、localStorage 与 API 集成5-browser-extension/3-background-tasks-and-performance/README.md配套课程后台任务、动态图标与性能分析练习起点 start/src/index.js 中只有 6 个编号注释//1到//6对应课程中依次需要完成的DOM 引用、事件监听、初始化检查、表单提交、用户设置、API 调用。完成版代码则把这 6 步全部落地是理解整个扩展的最佳参照。三、扩展清单Manifest V3 与弹出层结构完成版的扩展清单 manifest.json 采用 Manifest V3 规范{ manifest_version: 3, name: My Carbon Trigger, version: 0.1.0, host_permissions: [all_urls], background: { service_worker: background.js }, action: { default_popup: index.html } }关键字段说明manifest_version: 3Manifest V3后台脚本改用 Service Worker即background.js取代旧版常驻后台页面资源占用更低host_permissions: [all_urls]声明可向任意域名发起网络请求CO2 Signal API 的跨域调用依赖此项background.service_worker指定后台脚本用于监听chrome.runtime.onMessage并更新扩展图标action.default_popup点击工具栏图标时打开的弹出页面index.html即用户填写 API Key 与区域代码的界面。弹出层页面 index.html 包含两部分 UI配置表单.form-data两个必填输入框#region区域名、#apiAPI Key均带required属性由浏览器自动完成校验与 Submit 按钮结果区.resultloading 提示、错误信息容器、结果容器区域、碳排放强度、化石燃料百分比以及 Change region 重置按钮。配套样式 styles.css 基于 Basic.css定义了--c1: #0074d9主色、圆角--rc: 8px等 CSS 变量并通过media (prefers-color-scheme: dark)支持深色模式保证扩展在不同系统主题下都有可读性。四、运行前置准备npm 与 API Key4.1 环境要求根据 package.json 中的engines字段运行构建需要node 18.0.0npm 9.0.0依赖方面构建工具为webpack^5.105.4与webpack-cli^5.1.4位于devDependencies运行时依赖仅axios^1.15.0用于向 CO2 Signal API 发起 HTTP 请求。4.2 获取 CO2 Signal API Key扩展运行时需要一个有效的 API Key 才能从 CO2 Signal 获取数据。获取方式为在 CO2 Signal 官网页面中通过邮箱订阅获取该服务同时提供免费档位。API Key 在代码中以auth-token请求头发送见下文源码解析。4.3 确定区域代码区域代码对应 Electricity Map 的电力分区例如美国波士顿地区使用US-NEISO新英格兰 ISO。不同国家/地区有不同的代码格式填写错误时扩展会显示错误提示见源码中的异常分支。这些代码可从 Electricity Map 的 zones 列表中查询。五、构建与安装三步跑通5.1 安装依赖将solution目录复制到本地后在目录内执行npm install该命令会依据 package-lock.json 安装 Webpack、Webpack CLI 与 axios 等全部依赖。5.2 构建扩展npm run buildbuild脚本对应webpackWebpack 会把 src/index.js 及其依赖打包为dist/main.js与dist/index.html、dist/styles.css、dist/background.js、dist/manifest.json一起构成可直接加载的扩展包。开发过程中也可使用npm run watch对应webpack --watch监听文件变更并自动重新构建。5.3 在 Edge 中加载点击浏览器右上角三点菜单进入扩展Extensions面板打开开发人员模式开关选择Load unpacked加载解压缩的扩展在弹出的文件选择器中指向构建产物所在的dist文件夹。通过 Edge 扩展面板的 Load unpacked 加载dist目录。加载完成后在扩展界面中输入 API Key 与区域代码并提交工具栏上的彩色圆点就会随该区域实时碳排放情况变化。六、源码级拆解扩展是如何工作的完成版主逻辑集中在 solution/src/index.js可以按数据流分为四个环节。6.1 捕获 DOM 引用对应骨架//1const form document.querySelector(.form-data); const region document.querySelector(.region-name); const apiKey document.querySelector(.api-key); 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);全部元素引用都通过document.querySelector()按 CSS 类选择器获取并存入const变量供后续函数复用。这与课程 2-forms-browsers-local-storage/README.md 中先建立 DOM 引用再操作界面的教学顺序一致。6.2 表单提交与用户设置对应骨架//4//5const 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; displayCarbonUsage(apiKey, region); };handleSubmit首先调用e.preventDefault()阻止表单默认的整页刷新行为然后取出两个输入框的值setUpUser把 API Key 与区域代码写入localStorage实现跨会话持久化——下次打开扩展无需重新输入同时切换 UI 状态显示 loading、清空错误信息、显示 Change region 按钮并立即发起首次数据请求。配套课程中特别提醒由于扩展拥有与普通网页相互隔离的独立 localStorage存储的凭据不会与其他站点冲突但 localStorage 中的敏感信息如 API Key可被同一上下文中的 JavaScript 读取生产环境应改用安全的服务端存储方案。6.3 调用 CO2 Signal API对应骨架//6const 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; 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.; } };请求细节项值说明HTTP 方法GET查询最新碳数据接口地址https://api.co2signal.com/v1/latestCO2 Signal 最新数据端点查询参数countryCode: region传入用户填写的区域代码请求头auth-token: apiKey以自定义头携带 API Key 完成鉴权响应处理要点使用response?.data?.data可选链安全取值并在使用前显式校验carbonIntensity与fossilFuelPercentage是否为空避免渲染时崩溃碳排放强度向下取整后传给calculateColor同时在界面上显示四舍五入后的数值单位克/千瓦时化石燃料百分比用toFixed(2)保留两位小数try/catch兜底请求失败时隐藏 loading 与结果区在.errors容器显示该区域数据不可用的友好提示并把失败原因记录到控制台。6.4 初始化与重置对应骨架//2//3const init async () { const storedApiKey localStorage.getItem(apiKey); const storedRegion localStorage.getItem(region); 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; } }; const reset async (e) { e.preventDefault(); localStorage.removeItem(region); init(); };init是应用入口文件末尾调用负责恢复现场若 localStorage 中已有凭据则跳过表单直接展示上次区域的数据否则展示配置表单初始状态把图标设为通用绿色作为占位reset只清除region保留 API Key随后重新执行init让用户更换区域form.addEventListener(submit, ...)与clearBtn.addEventListener(click, ...)在文件末尾完成事件绑定。七、彩色圆点碳排放数值到颜色的映射完成版代码中的calculateColor实现了数值 → 颜色的分段映射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 } }); };映射逻辑把当前碳排放值依次与[0, 150, 600, 750, 800]五个阈值比较取最接近的档位下标再对应到[#2AA364, #F5EB4D, #9E4229, #381D02, #381D02]五个颜色阈值区间g/kWh颜色语义≤ 150 附近#2AA364绿电力较清洁适合耗电活动~150–600#F5EB4D黄中度碳强度留意用电~600–750#9E4229棕红高碳强度建议推迟耗电活动750–800#381D02深棕极高碳强度避免高耗电颜色值通过chrome.runtime.sendMessage发送到后台脚本课程第 3 节 3-background-tasks-and-performance/README.md 的讲解对象。八、后台 Service Worker动态绘制图标background.js 是 Manifest V3 的后台脚本监听主逻辑发来的消息并重绘工具栏图标chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) { if (msg.action updateIcon) { chrome.action.setIcon({ imageData: drawIcon(msg.value) }); } }); function drawIcon(value) { let canvas new OffscreenCanvas(200, 200); let context canvas.getContext(2d); context.beginPath(); context.fillStyle value.color; context.arc(100, 100, 50, 0, 2 * Math.PI); context.fill(); return context.getImageData(50, 50, 100, 100); }实现要点消息传递前台通过chrome.runtime.sendMessage({ action: updateIcon, value: { color } })与后台通信后台以onMessage监听并匹配action离屏绘制用OffscreenCanvas200×200在后台线程绘制一个指定颜色的实心圆圆心 100,100、半径 50再通过getImageData(50, 50, 100, 100)截取中央 100×100 区域作为图标位图动态更新chrome.action.setIcon接受imageData从而无需为每种颜色准备静态 PNG图标颜色完全由代码实时生成——这正是圆点随碳强度变色的底层机制。该画法源自 Energy Lollipop 扩展的图标思路。九、性能与体验细节课程 3-background-tasks-and-performance/README.md 围绕本扩展延伸了性能主题值得注意的实践点后台任务轻量化Manifest V3 的 Service Worker 按需唤醒background.js仅保留消息监听与图标绘制两件事避免常驻开销避免不必要的重绘DOM 更新集中在displayCarbonUsage的响应回调中一次请求对应一轮界面刷新loading / errors / results 的显隐切换style.display保持界面状态清晰用 DevTools Performance 面板验证打开浏览器开发者工具Edge 中CtrlShiftI/OptionCommandI切到 Performance 标签录制操作检查是否存在超过 15ms 的长任务、分析脚本执行与渲染/绘制阶段是定位扩展卡顿的标准流程数据校验前置对 API 响应做空值校验、对数值做Math.floor/Math.round/toFixed(2)格式化保证 UI 展示的数据稳定、可读。十、常见问题与排查建议现象可能原因处理方式提交后一直显示 loadingAPI Key 无效或区域代码错误检查auth-token与countryCode在 DevTools Console 查看Data fetch failed的具体报错提示 Sorry, data unavailable for the selected region.该区域代码在 CO2 Signal 无数据或网络请求失败对照 zones 列表更换区域代码确认网络可达api.co2signal.com图标颜色不变化后台 Service Worker 未加载或消息未送达确认manifest.json的background.service_worker路径正确重新加载扩展重新打开扩展仍需填写表单localStorage 被清空或使用reset清除了 region确认apiKey、region两个键均已写入DevTools → Application → Local Storage 可查看构建报错Node/npm 版本过低满足node 18、npm 9后重新npm install十一、总结Carbon Trigger 是一个麻雀虽小、五脏俱全的浏览器扩展范例它串起了Manifest V3 清单、弹出层 HTML/CSS、Webpack 构建、表单与 localStorage、基于 axios 的异步 API 调用、后台 Service Worker 消息机制与动态图标绘制这一整条 Web 前端技术链路。通过 solution/src/index.js、background.js 和 manifest.json 的源码对照再结合 2-forms-browsers-local-storage/README.md 与 3-background-tasks-and-performance/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),仅供参考