Browser Extension Dev - 07. Popup UI
本文最后更新于:2026年1月29日 凌晨
前言
在上一章 Browser Extension Dev - 06. Inject Script on Demand 中,我们介绍了按需为网页注入脚本执行自定义的功能,还实现了一个简单的复制网页主要内容为 Markdown 的扩展。在这一章中,我们将继续实现一个 Popup 弹窗,用于显示页面主要内容转换得到的 Markdown,并支持在复制之前进行预览和编辑。
首先,需要明确 Popup 是什么?
之前我们已经接触过 Content Script 注入网页的 UI 和 Options 配置页面。Popup 类似于 Options 页面,独立运行,但权限相比 Background/Options 更加受限。通常而言,它和 Content Script UI 的应用场景非常接近,都是显示一些当前网页相关的内容,但它也有一些独有的适用场景:
- 安全与隔离,网站无法以任何方式主动访问 Popup UI,它们完全由浏览器的不同线程/进程进行隔离。Content Script 注入的任何 UI 都有可能被网页检测出来,这就是网页能够检测是否使用了广告拦截器的原因之一。
- 不受普通网站影响,例如一个定时刷新的扩展,可以自动刷新当前页面,我们肯定不希望每次刷新网页之后都重新注入并显示操控面板。
- 无需内存清理,注入 Content Script 很难完全清理内存,这在普通网页不会出现问题,但在 SPA 网页可能会导致问题,复杂的(换句话说,使用了很多 npm 包的)JavaScript 代码真的到处都是内存泄漏。而 Popup 在关闭后就彻底销毁了,下次会再次重建。
- 可以在特权页面打开,例如 https://chromewebstore.google.com/,所有扩展的 Content Script UI 都会在这个网站禁用,但可以打开 popup 并且获得当前标签页的 URL,这在特定场景很有用,例如用于下载扩展 zip 文件的工具
Content Script UI 则有其他几个优势
- 更大的 UI 区域:Popup UI 受限于面板宽度,无法制作全屏面板
- 更容易与网站本身高度集成,例如需要添加符合网站外观的按钮时
- 更容易控制和修改网站本身,例如希望拦截网络、监听并修改 DOM、或者拦截脚本的特定代码执行之类的 – Popup 可以结合 Background Script 注入脚本做到,但没有那么灵活
接下来,让我们接着之前的实现继续完善吧。
参考 Chrome 官方文档 https://developer.chrome.com/docs/extensions/develop/ui/add-popup
思考
现在面临一个问题:如何在 Popup 中获取页面的内容?
答案是无法直接获取,需要通过 Background Script 中转,大致流程如下:
Popup → Background → executeScript(inject.js) → 返回 markdown → Popup 显示
但是等等,scripting.executeScript 可以有返回值吗?当然可以,它支持同步和异步返回值,但返回值必须是可结构化克隆的。
参考 Chrome scripting API 关于 Promise 返回值的官方文档 https://developer.chrome.com/docs/extensions/reference/api/scripting#promises
实现
添加 popup 页面
首先添加一个 popup 页面,在 entrypoints/popup 下添加 index.html 和 main.ts
1 | |
1 | |
在浏览器中加载扩展之后,点击 action 可以看到弹窗出现了。

修改注入的脚本 Inject Script
在实现通信部分之前,需要修改一下之前注入的 Inject Script,不再复制 Markdown 到剪切板,而是使用 return 返回给调用者。
1 | |
实现 Popup 与 Background Script 通信
下面开始实现 Popup 与 Background Script 的通信部分,由于 Chrome 原生的通信 API 使用起来非常痛苦,这里使用一个浅包装 @webext-core/messaging。
安装依赖
1 | |
然后在 lib/messager.ts 中定义接口
1 | |
然后在 Background Script 定义实现
1 | |
最后在 Popup 中调用,出于简化考虑,这里直接使用 pre 渲染了 Markdown,我们将在下一步引入所见即所得的 Markdown 编辑器。
1 | |

添加 markdown 编辑器
由于并未使用 react,所以这里直接使用一个 vanilla JS 实现的 markdown 编辑器 easymde。
还是先安装依赖。
1 | |
然后在 Popup 中使用它。
1 | |
现在就可以看到最终的效果了。

总结
在这一章,我们介绍了 Popup 的应用场景、Popup 与 Background Script 的通信、以及从网页获取数据的功能与实现。在下一章,我们终于要发布插件了,我将演示如何将插件发布到 Chrome Web Store,以便让其他人也能使用开发的扩展。
如果有任何问题,欢迎加入 Discord 群组讨论。
https://discord.gg/VxbAqE7gj2
完整代码:https://github.com/rxliuli/browser-extension-dev-examples/tree/main/packages/07-popup-ui