首页 / WXT 浏览器扩展框架教程 / Popup:点击图标弹出来的小窗

WXT 浏览器扩展框架教程

Popup:点击图标弹出来的小窗

本教程共 45 篇 · 第 8 篇 · 更新于 2026-08-13 · 约 3 分钟阅读

WXTpopup弹窗action浏览器扩展UI

本节目标:认识弹窗入口,学会创建 popup 页面、配置标题与图标,理解尺寸和生命周期限制,以及「没有弹窗的 action」怎么用。

弹窗是什么

popup 是点击工具栏图标后弹出的那个小窗。它像一张便利贴:轻量、即用即走,适合放最常用的操作。它对应浏览器 manifest 里的 action(MV2 的 browser_action / page_action)。

创建弹窗

📂 entrypoints/
   📄 popup.html            # 写法一

📂 entrypoints/
   📂 popup/
      📄 index.html         # 写法二(可带 main.tsx、style.css)

构建后产物是 popup.html,WXT 自动把它写进 manifest 的 action.default_popup。用户点图标,浏览器就打开这个页面。

一个最小弹窗:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>我的扩展</title>
  </head>
  <body>
    <button id="hello">你好</button>
    <script type="module" src="./main.ts"></script>
  </body>
</html>
// entrypoints/popup/main.ts
document.getElementById('hello')?.addEventListener('click', () => {
  console.log('Hello popup!');
});

HTML 里

引用的模块会被 Vite 打包,所以你可以用 React、Vue,也可以只用原生 JS。一个 HTML 文件本身就是合法入口,框架不是必需的。

标题、图标与 manifest 的关联

弹窗文件里的几样东西会变成 action 的配置:

  • <title> 变成 action.default_title,也就是鼠标悬停图标时的提示文字;
  • manifest.default_icon meta 设置各尺寸图标;
  • manifest.type 控制 MV2 用 browser_action 还是 page_action
  • Firefox 专属:manifest.default_area 控制按钮位置,manifest.theme_icons 设置亮/暗主题图标。
<meta
  name="manifest.default_icon"
  content="{ '16': '/icon-16.png', '24': '/icon-24.png', '128': '/icon-128.png' }"
/>
<meta name="manifest.type" content="browser_action" />

默认情况下,WXT 构建 MV2 时会自动把 action 转成 browser_action。想用 page_action,加

这个 meta 即可。

尺寸与生命周期限制

弹窗有两个先天限制,写 UI 前先记住。

尺寸:浏览器把弹窗当特殊窗口处理,Chrome 上限约 800×600 像素,超出部分会被裁掉(社区实测确认,见 https://github.com/ungoogled-software/ungoogled-chromium/issues/3018 )。内容一多,就该考虑选项页(§09)。

生命周期:弹窗只在打开时存在。点击页面其他地方或按 Esc 就关闭;下次打开是全新加载,内存里的变量全部清零。需要跨打开保留的数据,必须写进存储(如 §18 所述)。

弹窗里只放「看一眼就能完成」的操作。复杂表单、长列表,交给选项页或未列出页面。

两个常见坑提前说:一是别在弹窗里直接改网页 DOM——弹窗是扩展自己的页面,和网页完全隔离,改网页要靠内容脚本(§11)加消息通信(§17);二是弹窗里 JS 报错时,Console 要选对上下文:在扩展图标右键菜单选「检查弹出式窗口」打开的是弹窗自己的 DevTools,普通网页的 DevTools 里看不到它。

没有弹窗的 action

有些扩展点图标只想触发动作,不想弹窗。两步搞定:

  1. 删除 popup 入口(如果有);
  2. wxt.config.ts 里声明一个空 action:
export default defineConfig({
  manifest: {
    action: {},
  },
});

然后配合 browser.action.onClicked 事件:用户点图标时后台执行逻辑。监听器写在哪、为什么,见 §10。

三步创建一个带 React 的弹窗

  1. 建目录 entrypoints/popup/
  2. index.html,提供 #root 容器并引用 ./main.tsx
  3. main.tsx,创建 React root 渲染组件:
// entrypoints/popup/main.tsx
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './style.css';

ReactDOM.createRoot(document.getElementById('root')!).render(<App />);

simple_demo 项目的弹窗就是这么搭的,它的 index.html 里还带了 <meta name="manifest.type" content="browser_action" />,明确让 MV2 使用 browser_action。

真实示例

mkext 的弹窗是一个紧凑欢迎页,用 React 渲染:

// entrypoints/popup/main.tsx
const Popup = () => (
  <Layout surface="popup" className="w-[23rem] gap-5 p-4">
    <Main mode="active-tab" />
  </Layout>
);

mount(<Popup />);

宽度 23rem(约 368px)是弹窗常见的紧凑宽度,在 800px 上限内留足余量,避免内容被裁。如果弹窗需要展示当前标签页信息,tabs.query({ active: true, currentWindow: true }) 是标准做法。

弹窗内容多到需要滚动时,就是该考虑选项页(§09)的信号。

小结

  • 弹窗是「点图标就出」的轻量界面,默认标题、图标等 manifest 选项写在 HTML 的 meta 标签里。
  • Chrome 的尺寸上限约 800×600,紧凑布局更稳妥。
  • 不需要弹窗时,把 action 的点击监听交给后台(§10)。