)
教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载导读本文以《Programming with Text》课程第 11 章“Chrome Extensions”专题中的Pop-ups一课为骨架系统讲解 Chrome 扩展“弹窗”机制什么是 pop-up 扩展、如何通过browser_action注册点击弹窗、如何在弹窗页HTMLJavaScript中与 background script、content script 进行双向消息通信并以本仓库 session11/11-06_Pop-ups_Messaging 的完整示例与 CC_084_Word_Definition_Extension 实战项目为源码佐证。读完本文你将能够独立构建一个“点击工具栏图标 → 弹出交互面板 → 修改当前网页内容”的完整 Chrome 扩展。一、什么是 Pop-up 扩展在 Chrome 扩展体系中pop-up弹窗是一类特殊的扩展页面它是一张以独立小窗口/覆盖层形式悬浮在当前标签页之上的网页最常见的触发方式是用户点击工具栏上的扩展图标按钮即 browser action时弹出。原文档 11.5-pop-ups.md 给出的定义可以概括为A Pop-up extension is a webpage that opens as a separate window/overlay on top of the current tab. It is typically opened when the extension button is pressed (a browser action).与同系列其他扩展形态相比pop-up 的定位非常明确扩展组件运行位置典型用途对应课程章节Pop-up点击工具栏图标时弹出的独立小页面提供交互面板、输入框、按钮或展示当前页面信息本文11.5Background script浏览器启动即运行的后台 JS监听全局事件菜单、地址栏、扩展按钮等11.4-background-scripts.mdContent script注入到当前网页的 JS读取、修改页面 DOM11.3-content-scripts.mdNew Tab Override替换新建标签页定制新标签页内容11.7-new-tab-override.md需要特别说明的是pop-up 虽然是一张“网页”但它不是普通标签页它在点击图标时出现、在用户点击页面其他位置时自动关闭生命周期短暂。这也决定了它通常作为“入口/控制台”存在——真正持久的数据与逻辑放在 background script 中真正操作页面 DOM 的工作交给 content scriptpop-up 负责把它们串起来。这正是本课与下一课 11.6-pop-ups-messaging.md 的核心议题。二、用 browser_action 注册 pop-upmanifest.json 详解要让扩展图标被点击时弹出页面需要在扩展清单manifest.json中声明browser_action并指定default_popup指向弹窗 HTML 文件。仓库中 11-06_Pop-ups_Messaging/manifest.json 给出了一个完整可用的配置{ manifest_version: 2, name: Coding Train Pop Up, version: 0.1, content_scripts: [ { matches: [all_urls], js: [content.js] } ], content_security_policy: script-src self https://cdn.jsdelivr.net/npm/p51.1.4/lib/p5.min.js; object-src self, permissions: [tabs], browser_action: { default_icon: ct.png, default_popup: sketch/index.html, default_title: Generate a maze! } }各字段的含义与作用如下browser_action.default_popup弹窗页面路径相对manifest.json所在目录。这里指向sketch/index.html即 pop-up 就是一个普通的 HTML 页面里面照常引用 CSS 与 JavaScript。browser_action.default_icon工具栏图标文件示例为ct.png。browser_action.default_title鼠标悬停在图标上时显示的提示文字。content_security_policy弹窗页同普通扩展页一样受 CSP 约束。示例中允许从https://cdn.jsdelivr.net/npm/p51.1.4/lib/p5.min.js加载 p5.js说明弹窗页面可以完整使用 p5.js 等库这是本课程大量使用 p5.js 做可视化/交互界面如迷宫生成、查词定义展示的关键配置。permissions: [tabs]申请tabs权限弹窗页才能通过chrome.tabs.query()获取当前标签页信息并向其发送消息详见下文。content_scripts声明注入所有页面的 content script为“弹窗 → 页面”通信铺路。对照阅读仓库中另一份示例 CC_084_Word_Definition_Extension/JavaScript/manifest.jsonWord Lookup 查词扩展可以看到同样的模式browser_action.default_popup指向sketch/index.htmlbackground声明background.jscontent_scripts注入content.js。也就是说一个典型的三层结构pop-up background content在清单中就是由这三段配置共同描述的。版本提示本仓库示例均基于manifest_version: 2MV2。MV2 与 MV3manifest_version: 3在后台脚本、CSP 等字段上有差异运行示例时请以本仓库代码为准在 Chrome 中加载本地扩展时选择“开发者模式”即可。三、弹窗页面本身用 HTML JavaScript含 p5.js写交互面板default_popup指向的 HTML 就是一个普通网页示例 11-06_Pop-ups_Messaging/sketch/index.html 内容如下!DOCTYPE html html head meta charsetUTF-8 titlemaze_challenge/title script typetext/javascript srchttps://cdn.jsdelivr.net/npm/p51.4.1/lib/p5.min.js/script script typetext/javascript srcsketch.js/script /head body h1Paragraph Replacer/h1 p input iduserinput / /p /body /html该弹窗是一个“Paragraph Replacer段落替换器”页面中只有一个文本框#userinput用户输入文字后当前网页中所有p段落的内容会被替换成该文字。注意这里的页面宽度由弹窗尺寸决定实际开发时通常会在 HTML/CSS 中显式限制宽度例如 CC_084 的 sketch/index.html 中设置了body { width: 800px; }避免弹窗过宽。对应的 sketch.js 使用 p5.js 的setup()初始化并监听输入事件function setup() { noCanvas(); let userinput select(#userinput); userinput.input(changeText); function changeText() { console.log(text changed); let params { active: true, currentWindow: true }; chrome.tabs.query(params, gotTabs); function gotTabs(tabs) { console.log(got tabs); console.log(tabs); // send a message to the content script let message userinput.value(); let msg { txt: userinput.value() }; chrome.tabs.sendMessage(tabs[0].id, msg); } } }这段代码展示了 pop-up 页面中调用 Chrome 扩展 API 的典型流程noCanvas()本弹窗不需要 p5 画布仅使用 p5 的选择器与事件绑定能力select(#userinput).input(changeText)p5.js 的事件绑定等价于 DOM 的input事件监听chrome.tabs.query({ active: true, currentWindow: true }, gotTabs)查询当前活动窗口的活动标签页拿到其tabs[0].idchrome.tabs.sendMessage(tabs[0].id, msg)向该标签页注入的 content script 发送{ txt: 用户输入 }消息。这就是“弹窗 ↔ 页面”通信的最短路径pop-up 用chrome.tabs.sendMessage直接发给 content script无需经过 background。由于该 API 需要tabs权限所以清单中才出现了permissions: [tabs]。四、消息的另一端content script 如何接收并改写页面接收方是注入页面中的 content.jsconsole.log(Chrome extension go?); chrome.runtime.onMessage.addListener(gotMessage); function gotMessage(message, sender, sendResponse) { console.log(message); let paragraphs document.getElementsByTagName(p); for (elt of paragraphs) { elt.innerHTML message.txt; } }关键点chrome.runtime.onMessage.addListener(gotMessage)注册消息监听器gotMessage的第一个参数即对方发来的消息对象document.getElementsByTagName(p)content script 运行在页面上下文中因此可以像普通脚本一样操作页面 DOMelt.innerHTML message.txt把每个p的 HTML 内容整体替换为弹窗输入框中的文字。对照同目录的背景版示例 11-04_Chrome_Extensions_Background_Scripts/content.js其中gotMessage在收到message.txt hello时会把段落背景改为紫色#FF00FF——说明 content script 收到消息后可以执行任意 DOM 操作弹窗只是“指令发起者”。此外还有一条反向路径值得注意content script 也可以主动向扩展其他部分发消息。在 CC_084_Word_Definition_Extension/JavaScript/content.js 中用户用鼠标选中网页上的文字后window.addEventListener(mouseup, wordSelected); function wordSelected() { let selectedText window .getSelection() .toString() .trim(); console.log(selectedText); if (selectedText.length 0) { let message { text: selectedText }; chrome.runtime.sendMessage(message); } }即通过chrome.runtime.sendMessage(message)把选中的文字发给 background script详见下一节。这说明消息通信是双向、多跳的content → background → pop-up 可以构成完整链路。五、通过 background script 中转pop-up 读取后台共享状态有些场景下pop-up 需要的数据并不在 pop-up 自身而在 background script 中。原文档对应的延伸示例 11-06_Pop-ups_Messaging/background.js 展示了 background 如何接收消息并保存状态console.log(background running); chrome.browserAction.onClicked.addListener(buttonClicked); function buttonClicked(tab) { let msg { txt: hello }; chrome.tabs.sendMessage(tab.id, msg); }该 background 监听chrome.browserAction.onClicked当用户点击扩展图标时向当前标签页的 content script 发送{ txt: hello }此处因为清单中已配置default_popup图标点击会优先弹出 pop-uponClicked与 pop-up 二选一使用二者不能同时生效。更值得借鉴的是 CC_084_Word_Definition_Extension/JavaScript/background.js 中“把 background 当作共享存储”的做法console.log(background running); chrome.runtime.onMessage.addListener(receiver); window.word coding train; function receiver(request, sender, sendResponse) { console.log(request); word request.text; }这里window.word是挂在 background 全局对象上的变量。content script 选中的文字通过chrome.runtime.sendMessage送达后background 更新word随后 pop-up 通过chrome.extension.getBackgroundPage()直接读取// Word Lookup pop-up (CC_084) function setup() { noCanvas(); let bgpage chrome.extension.getBackgroundPage(); let word bgpage.word.trim(); // ... 用 word 拼装 Wordnik API 请求并 loadJSON 展示释义 }chrome.extension.getBackgroundPage()返回 background 页面的全局对象pop-up 借此拿到bgpage.word再请求 Wordnik 词典 API 把释义显示在弹窗中完整代码见 CC_084_Word_Definition_Extension/JavaScript/sketch/sketch.js。这是 pop-up 与 background 之间最简单直接的“共享内存”式通信适合数据量小、无需回调的场合。六、消息通信机制小结三条典型链路综合以上仓库源码pop-up 参与的消息通信可以归纳为三条典型链路它们覆盖了大多数实际需求链路一pop-up → content script弹窗直控页面pop-up 用chrome.tabs.query({ active: true, currentWindow: true })拿到标签页 id再用chrome.tabs.sendMessage(tabId, msg)发送content script 用chrome.runtime.onMessage.addListener()接收。 代表实现sketch.js content.js。链路二content script → background页面数据回传content script 用chrome.runtime.sendMessage(msg)发送background 用chrome.runtime.onMessage.addListener()接收并写入全局变量。 代表实现content.js background.js。链路三pop-up → background读取共享状态pop-up 用chrome.extension.getBackgroundPage()直接读取 background 的全局属性无需异步消息。 代表实现sketch.js。需要留意chrome.tabs.sendMessage与chrome.runtime.sendMessage的区别前者定向发送给指定标签页的 content script需要tabs权限与标签页 id后者广播给扩展自身的 background / 其他扩展页面。两者方向不同、用途不同选择时以“发送目标”为判断依据。七、加载、运行与调试 Pop-up 扩展本仓库是只读归档无法在此直接运行扩展但你可以按以下流程在本地浏览器中加载示例验证Chrome 桌面版将示例目录如Courses/programming_with_text/session11/11-06_Pop-ups_Messaging复制到本地可写目录打开 Chrome进入chrome://extensions/打开右上角“开发者模式Developer mode”开关点击“加载已解压的扩展程序Load unpacked”选择该目录点击ct.png图标弹出 Paragraph Replacer 面板在输入框中打字观察当前网页中所有p段落被替换。调试要点弹窗页调试在弹窗中右键 → “检查”即可打开 DevTools 查看 pop-up 的 console 与 DOMbackground / content script 调试在chrome://extensions/对应扩展卡片上点击“背景页 / service worker”链接查看 background consolecontent script 的日志会打印在其所在网页的 console 中消息是否送达各示例代码中保留了console.log(text changed)、console.log(got tabs)、console.log(message)等日志可据此逐跳确认消息链路加载本地扩展的限制Chrome 对开发者模式加载的本地扩展 API 限制较少如chrome.tabs.query、sendMessage均可使用但以非商店签名扩展发布给用户仍受限制本文不展开。八、实践注意事项结合仓库示例代码整理几个容易踩坑的点default_popup与browserAction.onClicked互斥清单配置了default_popup后图标点击弹出 pop-uponClicked回调不再触发若需要“点击图标直接执行动作”而非弹窗就不要配default_popup如 11-04_Chrome_Extensions_Background_Scripts/manifest.json 只配了default_icon。pop-up 生命周期短暂点击页面其他区域弹窗即关闭setup()中绑定的状态随之销毁需要跨弹窗保持的数据应放到 background如window.word或chrome.storage中。CSP 决定能否用 p5.js弹窗页从 CDN 加载库必须显式写入content_security_policy否则会被拦截本仓库示例统一允许cdn.jsdelivr.net/npm/p5.../p5.min.js。permissions按需申请chrome.tabs.query/sendMessage需要tabs权限不需要时不要滥用避免安装提示过于吓人。消息对象建议用结构化对象示例中统一使用{ txt: ... }/{ text: ... }包裹数据便于扩展更多字段也便于在接收端区分消息类型。九、延伸阅读弹窗消息通信的进阶内容pop-up ↔ content 双向对话见同系列 11.6-pop-ups-messaging.md仓库配套代码在 session11/11-06_Pop-ups_Messaging后台脚本的全局事件监听机制见 11.4-background-scripts.mdcontent script 的注入与页面修改见 11.3-content-scripts.md同系列扩展主题还有书签脚本11.2-bookmarklets.md、新标签页覆盖11.7-new-tab-override.md与跨浏览器扩展11.8-cross-browser-extensions.md更多完整可运行示例位于 CodingChallenges/CC_082_Image_Chrome_Extension_The_Ex-Kitten-sion/JavaScript、CodingChallenges/CC_083_Chrome_Extension_with_p5js_Sketch/JavaScript 与 CodingChallenges/CC_084_Word_Definition_Extension/JavaScript。综上pop-up 扩展的开发模式可以概括为清单里配好browser_action.default_popup弹窗页负责交互与 UIcontent script 负责操作页面background 负责共享状态与全局事件三者通过chrome.runtime/chrome.tabs消息 API 串成完整链路。掌握本文的配置与三条通信链路你就拥有了构建任意“工具栏弹窗型”扩展的基础能力。赞分享教程文档示例工程【免费下载链接】website-archiveArchive of the Coding Train website (first version)项目地址https://gitcode.com/gh_mirrors/we/website-archive点击查看免费下载相关推荐Meshery模型与设计构建可复用的云原生架构Meshery模型与设计构建可复用的云原生架构 Meshery是一个功能强大的云原生管理平台它提供了丰富的模型与设计工具帮助开发者轻松构建可复用的云原生架文档/教程Chrome 扩展与 App 消息通信示例解析chrome-extensions-samples 中的 Messaging 跨应用通信实战Chrome 扩展与 App 消息通信示例解析chrome extensions samples 中的 Messaging 跨应用通信实战 导读 本文以 Ch示例工程从工具栏玩打地鼠Chrome 扩展 Mole Game 的多扩展协作与跨扩展消息通信实战从工具栏玩打地鼠Chrome 扩展 Mole Game 的多扩展协作与跨扩展消息通信实战 Mole Game 是 chrome extensions sa示例工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考