当弹出窗口重新打开时,为什么弹出脚本会向内容脚本发送更多消息?
Why the popup script send more message to content script, when the popup is reopened?
我有 firefox webextension。在 popup.html 中我有一个按钮,通过单击它,popup.js 将消息发送到 content.js。 Content.js 收到消息并用文本 "Message from popup" 制作 console.log。如果我再次单击该按钮,则会重复该操作。问题是当我离开弹出窗口并再次打开弹出窗口并再次单击按钮时,因为 content.js 从 popup.js 收到两条消息并发出两条 console.log。如果我再重复一次,content.js 收到三个消息,依此类推。
多少次我重新打开弹出窗口,多少次发送消息。
我认为问题出在 popup.js 的某处,但我想不通。
manifest.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"
});
}
});
}
content.js:
function handleMessage(request, sender, sendResponse) {
if(request.command === "message"){
console.log("Message from popup");
}
}
browser.runtime.onMessage.addListener(handleMessage);
预期的结果是点击按钮导致点击一次 console.log。甚至认为弹出窗口被重新打开了多次。
弹出窗口关闭后不会立即删除侦听器。垃圾收集器需要一些时间来删除它。
如果您使用的是 Firefox 50+,您可以在 EventTarget.addEventListener() 中为侦听器设置 once
,以便在第一次后删除侦听器。
对于旧版浏览器,您可以使用 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'});
}
content.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);
}
}
我有 firefox webextension。在 popup.html 中我有一个按钮,通过单击它,popup.js 将消息发送到 content.js。 Content.js 收到消息并用文本 "Message from popup" 制作 console.log。如果我再次单击该按钮,则会重复该操作。问题是当我离开弹出窗口并再次打开弹出窗口并再次单击按钮时,因为 content.js 从 popup.js 收到两条消息并发出两条 console.log。如果我再重复一次,content.js 收到三个消息,依此类推。 多少次我重新打开弹出窗口,多少次发送消息。
我认为问题出在 popup.js 的某处,但我想不通。
manifest.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"
});
}
});
}
content.js:
function handleMessage(request, sender, sendResponse) {
if(request.command === "message"){
console.log("Message from popup");
}
}
browser.runtime.onMessage.addListener(handleMessage);
预期的结果是点击按钮导致点击一次 console.log。甚至认为弹出窗口被重新打开了多次。
弹出窗口关闭后不会立即删除侦听器。垃圾收集器需要一些时间来删除它。
如果您使用的是 Firefox 50+,您可以在 EventTarget.addEventListener() 中为侦听器设置 once
,以便在第一次后删除侦听器。
对于旧版浏览器,您可以使用 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'});
}
content.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);
}
}