消息传情:插件组件间的通信密语
在浏览器插件的宇宙中,各个组件如同散落星辰,弹窗(Popup)是闪烁的灯塔,后台服务(Service Worker)是沉默的指挥官,内容脚本(Content Script)则是穿梭在网页中的信使。它们各自为政,却需默契协作。此时,消息传递便成了跨越时空的密语,让组件间的心跳同步共鸣。
通信三重境界:从私语到呐喊
一对一私语(最常用的通信方式)
适用于弹窗与后台,内容脚本与服务的深度对话,通过chrome.runtime.sendMessage来发送信息,使用chrome.runtime.onMessage来接收信息。
发送密信 --- sendMessage的艺术
参数详解
message -- 消息本尊 -- 任意可序列化的对象 -- 携带要传递的数据,是通信的核心内容
options -- 配置之门 -- 可选
callback -- 响应之桥 -- 函数 -- 接收接收方的响应(通过 sendResponse
或 Promise
)-- 可选
使用示例
// 发送方:弹窗或内容脚本 chrome.runtime.sendMessage({ type: "REQUEST", // 消息类型(建议枚举) payload: { data: 42 }, // 有效载荷(可为任意结构) source: "popup" // 可选来源标识 });
倾听密语 --- onMessage的守望
参数详情
request -- 发送方消息的对象
sender -- 发送者元信息 (tab frame url)
sendResponse -- 响应函数
使用示例
// 接收方:Service Worker 或 Content Script chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.type === "REQUEST") { console.log("收到来自", sender.tab?.url || sender.url, "的请求"); sendResponse({ status: "SUCCESS", result: request.payload.data * 2 }); } // 若需异步处理,返回 true 保持通道开放 return true; });
进阶技巧
//定义messageType.js 统一管理通信协议 export const TYPES = { CHANGE_COLOR: "CHANGE_COLOR", FETCH_DATA: "FETCH_DATA", ERROR: "ERROR" }; //错误处理 chrome.runtime.sendMessage(message, (response) => { if (chrome.runtime.lastError) { console.error("通信失联!", chrome.runtime.lastError); } else if (response?.status === "SUCCESS") { console.log("响应成功", response.result); } });
一对多广播
适用于广播全局状态变更(如用户登录),通过chrome.runtime.connect发送,chrome.runtime.onConnect接收。
使用示例
// 后台服务:创建监听通道 const port = chrome.runtime.connect({ name: "statusChannel" }); port.onMessage.addListener((msg) => { if (msg.type === "STATUS_UPDATE") { console.log("全局状态更新为:", msg.payload); } }); // 其他组件:发送广播 chrome.runtime.connect().postMessage({ type: "STATUS_UPDATE", payload: "online" });
跨域传输
适用于插件与网页,跨域iframe的非常规通信,通过window.postMessage借道
使用示例
// Content Script:监听网页消息 window.addEventListener("message", (event) => { if (event.origin !== "https://trusted-site.com") return; if (event.data.type === "PLUGIN_REQUEST") { chrome.runtime.sendMessage({ type: "WEB_REQUEST", payload: event.data.payload }); } }); // 网页脚本:主动通信 window.postMessage({ type: "PLUGIN_REQUEST", payload: "需要插件处理的数据" }, "https://your-extension.com");
实践案例---拖拽图片直接下载
有时候,你会不会觉得在网页上下载图片麻烦了点🤔,你们能不能把这个过程简化一下呢,比如我点击图片拖动一下就自动下载。
{ "manifest_version": 3, "name": "拖拽图片自动下载", "version": "1.0", "description": "在网页中拖动图片时自动下载图片", "permissions": [ "downloads", "activeTab" ], "content_scripts": [ { "matches": [ "<all_urls>" ], "js": [ "content.js" ] } ], "background": { "service_worker": "background.js" } }
// content.js // 监听图片的拖动开始事件 document.addEventListener("dragstart", (event) => { const target = event.target; // 确保是图片 if (target.tagName.toLowerCase() === "img") { const imageUrl = target.src; // 向后台发送图片地址,触发下载 chrome.runtime.sendMessage({ type: "downloadImage", url: imageUrl }); } });
//background.js function getFileNameL() { return `image_${Date.now()}.png`; } chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.type === "downloadImage") { const imageUrl = message.url; const name = getFileNameL() // 使用 chrome.downloads.download 下载图片 chrome.downloads.download({ url: imageUrl, filename: name, saveAs: true // 弹出保存对话框 }); } });
成果展示
从零开始的谷歌浏览器插件开发 文章被收录于专栏
从零探索Chrome插件开发,手把手教你构建实用功能,开启浏览器扩展创作之旅。