Firefox 扩展并非“每个标签页运行一份独立副本”,而是通过分层架构实现高效复用:背景脚本(background script)在浏览器启动或扩展启用时全局仅运行一次,长期驻留内存并管理状态;内容脚本(content script)则按需注入到匹配的网页中,每次加载新页面时单独执行,彼此隔离但可通过背景脚本协同通信。
firefox 扩展并非“每个标签页运行一份独立副本”,而是通过分层架构实现高效复用:背景脚本(background script)在浏览器启动或扩展启用时**全局仅运行一次**,长期驻留内存并管理状态;内容脚本(content script)则按需注入到匹配的网页中,每次加载新页面时单独执行,彼此隔离但可通过背景脚本协同通信。
Firefox WebExtensions 采用清晰的进程与作用域分离模型,理解其执行生命周期是开发跨标签页功能(如“从 A 页面采集数据,自动填充至 B 页面”)的前提。
| 脚本类型 | 启动时机 | 运行范围 | 生命周期 | 典型用途 |
|---|---|---|---|---|
| Background 脚本 | 扩展安装/启用时启动,全程仅一次(除非手动重载或浏览器重启) | 全局(单例) | 持续驻留内存 | 状态管理、消息中转、定时任务、跨标签通信中枢 |
| Content 脚本 | 按 manifest.json 规则匹配页面后注入(可设 "run_at": "document_idle" 等) | 每个匹配的 tab 独立运行 | 页面卸载即销毁 | DOM 操作、数据提取、表单注入 |
| Popup / Options 脚本 | 用户点击弹窗或打开设置页时加载 | 单个 UI 实例 | UI 关闭即释放 | 用户交互、配置读写 |
? 关键事实:背景脚本是唯一能持久保存共享状态的组件。它不随标签页增减而重复创建,因此是实现“跨页数据桥接”的天然枢纽。
假设需求:在电商商品页(Tab A)点击“复制价格”,在比价表单页(Tab B)自动粘贴该价格。
// content-script-a.js(注入商品页)document.getElementById("copy-price-btn").addEventListener("click", () => { const price = document.querySelector(".price").textContent.trim(); // 发送消息至 background,附带 tab ID 便于溯源 chrome.runtime.sendMessage({ action: "savePrice", price, sourceTabId: window.chrome?.tabs?.id || -1 // 或使用 chrome.runtime.id 安全标识 });});
// background.js(全局单例)let sharedData = { lastPrice: null };chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === "savePrice") { sharedData.lastPrice = request.price; console.log(`✅ 已缓存价格: ${sharedData.lastPrice}`); // 主动通知所有监听中的 content script(如 Tab B) chrome.tabs.query({ active: true, currentWindow: true }, tabs => { tabs.forEach(tab => { chrome.tabs.sendMessage(tab.id, { action: "updatePriceField", price: sharedData.lastPrice }).catch(() => {}); // 忽略未监听的 tab }); }); }});
// content-script-b.js(注入表单页)chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === "updatePriceField") { const input = document.querySelector("#price-input"); if (input) { input.value = message.price; input.dispatchEvent(new Event('input', { bubbles: true })); // 触发 Vue/React 更新 console.log(`? 已自动填入价格: ${message.price}`); } }});
Firefox 扩展的本质是事件驱动的分布式系统:背景脚本作为“大脑”一次启动、永续在线;内容脚本作为“手脚”按需激活、专注当前页面。跨标签页协作不是靠“共享内存”,而是通过 chrome.runtime.sendMessage 构建可靠的消息总线——这既是设计约束,也是保障安全与稳定的关键架构选择。掌握这一范式,即可构建出如 Multi-Account Containers(容器隔离)、Tab Killer(标签管控)等复杂而健壮的浏览器增强功能。