我正在编写一个谷歌浏览器扩展程序,可以单击链接和按钮。单击重定向按钮/链接并且页面发生更改后,我必须使用后台脚本撤销扩展。问题是该消息仅指示后台脚本中发送了一条消息,但内容脚本中的 onMessage 侦听器收到了两条消息。怎么解决这个问题?
背景.js
chrome.webNavigation.onCompleted.addListener((details) => {
chrome.tabs &&
chrome.tabs.query({ active: true, currentWindow: true }, () => {
setTimeout(() => {
const storage = chrome.storage.local;
storage.get("activeProcess", (result) => {
let activeProcess = Object.values(result)[0];
if (activeProcess && details.frameType === "outermost_frame") {
const tabId = details.tabId;
storage.get("message", (result) => {
result.message.url = details.url;
result.message.source = "background";
console.log("message sent");
chrome.tabs.sendMessage(tabId, result.message, (res) => {
console.log(res);
});
});
}
});
}, 100);
});
return true;
});
message sent
内容.js
chrome.runtime.onMessage.addListener(messagesListener);
async function messagesListener(message, sender, response) {
await processMessage(message, sender, response);
}
export const processMessage = async (message, sender, response) => {
console.log("message received")
}
message received message received
预渲染选项卡也会被报告,然后它会变为活动状态并再次被报告。
解决方法:检查
documentLifecycle
参数中的
details
。
chrome.tabs.sendMessage 发送到选项卡的所有框架,因此如果您的内容脚本被注入到所有框架中,每个实例都将收到消息的副本。
解决方案:在 sendMessage 选项参数中显式使用事件的
frameId
。
如果您使用 chrome.scripting.executeScript 注入,它可能会运行两次。
解决方案:首先发送消息以验证内容脚本运行或检查内容脚本内的全局变量(示例)。
chrome.webNavigation.onCompleted.addListener(d => {
if (d.frameType !== 'outermost_frame' || d.documentLifecycle !== 'active')
return;
setTimeout(async () => {
const {activeProcess, message} = await chrome.storage.local.get(
['activeProcess', 'message']);
if (!activeProcess) return;
message.url = d.url;
message.source = 'background';
const res = await chrome.tabs.sendMessage(d.tabId, message, {frameId: d.frameId});
console.log(res);
}, 100);
});
您所需要做的就是仅在主机中监听消息。
// Check if the current window is top-level and not in an iframe
if (window.self === window.top && window.frameElement === null) {
// listen to messages from background
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
// Handle the received message
});
}