firefox-addon - 当弹出窗口重新打开时,为什么弹出脚本会向内容脚本发送更多消息?
问题描述
我有 Firefox 网络扩展。在 popup.html 我有一个按钮,通过单击它,popup.js 将消息发送到 content.js。Content.js 接收消息并使用文本“来自弹出窗口的消息”制作 console.log。如果我再次单击该按钮,则会重复该操作。问题是当我单击远离弹出窗口并再次打开弹出窗口并再次单击按钮时,因为 content.js 从 popup.js 收到两条消息并生成两个 console.log。如果我再重复一遍,content.js 会收到三条消息,依此类推。我重新打开弹出窗口多少次,与发送消息的次数一样多。
我认为问题出在 popup.js 中,但我无法弄清楚。
清单.json:
{
"manifest_version": 2,
"name": "Extension",
"version": "1.0",
"description": "Firefox extension",
"permissions": [
"activeTab",
"<all_urls>",
"tabs"
],
"browser_action": {
"default_title": "Script",
"default_popup": "popup.html"
}
}
popup.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button class="action">Start</button>
<script src="popup.js"></script>
</body>
</html>
popup.js:
browser.tabs.executeScript({file: "content.js"})
.then(listenForClicks)
function listenForClicks() {
document.addEventListener("click", (e) => {
if (e.target.classList.contains("action")) {
browser.tabs.query({active: true, currentWindow: true})
.then(send)
}
function send(tabs) {
browser.tabs.sendMessage(tabs[0].id, {
command: "message"
});
}
});
}
内容.js:
function handleMessage(request, sender, sendResponse) {
if(request.command === "message"){
console.log("Message from popup");
}
}
browser.runtime.onMessage.addListener(handleMessage);
预期结果是单击按钮导致生成一个console.log。甚至认为弹出窗口已多次重新打开。
解决方案
弹出窗口关闭后不会立即删除侦听器。垃圾收集器需要一些时间才能将其移除。
如果您使用的是 Firefox 50+,您可以once
在EventTarget.addEventListener()中为侦听器设置,以便在第一次之后删除侦听器。
对于较旧的浏览器,您可以使用 手动删除侦听器document.removeEventListener()
。
现在,如果您希望内容只收到一条消息,那么您可以在第一次之后删除侦听器,例如:
评论后更新
popup.js:
// add event listener for the button (not the whole pop-up), to run ONCE only
document.querySelector('button.action').addEventListener('click', listener, {once: true}); // FF50+, Ch55+
async function listener() {
await browser.tabs.executeScript({file: 'content.js'});
const tabs = await browser.tabs.query({currentWindow: true, active: true});
browser.tabs.sendMessage(tabs[0].id, {command: 'message'});
}
内容.js:
// add listener only if it wasnt done before
if (!sessionStorage.getItem('runOnce')) {
// keep track of previous attempts in sessionStorage
sessionStorage.setItem('runOnce', 'true');
browser.runtime.onMessage.addListener(handleMessage);
}
function handleMessage(request, sender, sendResponse) {
if(request.command === 'message'){
console.log("Message from popup");
// remove listern after the first run
browser.runtime.onMessage.removeListener(handleMessage);
}
}
推荐阅读
- android - 导航返回时的 RecyclerView(导航组件)
- javascript - 如何使用 JavaScript 通过电子邮件发送发票?
- reactjs - 我在功能组件中使用了 useLazyQuery,但我需要在类组件中使用相同的。我该怎么做?
- javascript - 修改日期时出现问题(修改错误)
- python - NumPy 使用 reshape 函数重塑数组
- python - 在 Python 中自定义集合交集
- arrays - 你如何比较两个在Powershell中都有多个属性和对象的数组
- android - 从 Flutter android MainActivity 启动新的外部 Activity
- php - Str_replace 用 php 中的数据库插入标题
- javascript - Electron / Nativefier Web App - 新窗口打印问题 [HTML, JS]