如何从内容脚本向Chrome扩展传递已打开弹窗的引用
问题描述
在我的Web应用中,通过let popup = window.open(url, 'MyPopupName', ...)打开了一个跨源弹窗,现在需要在Chrome扩展中获取该弹窗对应的标签页引用(tabId)。但受限于跨源限制,无法在弹窗中注入或运行任何脚本;同时Chrome扩展无法直接通过指定的MyPopupName窗口名称查询标签页(除了给所有标签页注入脚本并通过消息传递获取window.name这种繁琐方式),想知道有没有更简便的方法把popup对象传递给扩展并获取弹窗的tabId?
解决方案
方法1:Web应用主动向扩展传递弹窗特征,结合标签页查询
当Web应用调用window.open后,立即向扩展发送包含弹窗关键特征的消息,扩展通过这些特征快速筛选目标标签页:
- Web应用侧代码(需提前配置扩展的消息接收权限):
const popup = window.open(targetUrl, 'MyPopupName', 'width=500,height=600'); // 向扩展发送弹窗特征 chrome.runtime.sendMessage('你的扩展ID', { action: 'locatePopup', popupUrl: targetUrl, openTimestamp: Date.now(), width: 500, height: 600 }); - 扩展侧背景脚本代码:
chrome.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => { if (msg.action === 'locatePopup') { chrome.tabs.query({}, (tabs) => { // 筛选最近打开、URL匹配、尺寸接近的标签页 const targetTab = tabs.find(tab => { return tab.url.includes(msg.popupUrl) && Date.now() - tab.lastAccessed < 1500 && Math.abs(tab.width - msg.width) < 50 && Math.abs(tab.height - msg.height) < 50; }); if (targetTab) { // 成功获取tabId,可进行后续操作 console.log('弹窗tabId:', targetTab.id); } }); } }); - 配置要求:在扩展的
manifest.json中添加externally_connectable,允许你的Web应用域名发送消息:"externally_connectable": { "matches": ["https://你的Web应用域名/*"] }
方法2:结合标签页创建事件+Web应用的弹窗状态同步
利用扩展的标签页创建监听事件,配合Web应用发送的弹窗触发信号,精准定位刚创建的弹窗标签页:
- Web应用侧代码:
const popup = window.open(targetUrl, 'MyPopupName', 'width=500,height=600'); // 通知扩展准备监听新标签页 chrome.runtime.sendMessage('你的扩展ID', { action: 'waitForPopup' }); - 扩展侧背景脚本代码:
let pendingPopupFlag = false; const targetUrlPrefix = '目标弹窗URL的固定前缀'; chrome.runtime.onMessageExternal.addListener((msg, sender, sendResponse) => { if (msg.action === 'waitForPopup') { pendingPopupFlag = true; // 监听新标签页创建事件 const onTabCreated = (tab) => { if (pendingPopupFlag && tab.url.includes(targetUrlPrefix)) { console.log('弹窗tabId:', tab.id); pendingPopupFlag = false; chrome.tabs.onCreated.removeListener(onTabCreated); } }; chrome.tabs.onCreated.addListener(onTabCreated); } });
方法3:针对独立弹窗窗口的筛选
如果弹窗是以独立窗口(而非标签页)形式打开的,可直接通过窗口类型筛选:
// 扩展侧代码 chrome.windows.getAll({ populate: true }, (windows) => { const targetPopup = windows.find(win => { return win.type === 'popup' && win.tabs[0].url.includes(targetUrl); }); if (targetPopup) { console.log('弹窗tabId:', targetPopup.tabs[0].id); } });
内容的提问来源于stack exchange,提问作者user2531657
相关产品推荐
相关产品推荐

