【问题标题】:Why the popup script send more message to content script, when the popup is reopened?当弹出窗口重新打开时,为什么弹出脚本会向内容脚本发送更多消息?
【发布时间】:2019-01-01 18:53:29
【问题描述】:

我有 Firefox 网络扩展。在 popup.html 我有一个按钮,通过单击它,popup.js 将消息发送到 content.js。 Content.js 接收消息并使用文本“来自弹出窗口的消息”制作 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-addon firefox-addon-webextensions


    【解决方案1】:

    弹出窗口关闭后不会立即删除侦听器。垃圾收集器需要一些时间才能将其移除。

    如果您使用的是 Firefox 50+,您可以在 EventTarget.addEventListener() 中为侦听器设置 once,以便在第一次之后删除侦听器。

    对于较旧的浏览器,您可以使用 document.removeEventListener() 手动删除侦听器。

    现在,如果您希望内容只接收 ONE 消息,那么您可以在第一次之后删除侦听器,例如:

    cmets 后更新

    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);
      }
    }
    

    【讨论】:

    • 不幸的是,这不是我的问题的解决方案。这将在我打开弹出窗口并单击几次按钮时做到这一点,只会发送一条消息。但这并没有解决当我关闭弹出窗口并再次打开弹出窗口时,单击按钮后会发送两条消息的问题。问题示例:我在没有单击按钮的情况下打开和关闭弹出窗口五次。现在,我打开第六个弹出窗口并单击按钮。 Popup.js 将发送 6 条消息而不是 1 条。
    • 非常感谢。它工作得几乎完美。当我打开弹出窗口,单击按钮并关闭弹出窗口时,它会起作用。我可以重复这些步骤,它会正常工作。当我在不单击按钮的情况下重新打开弹出窗口时,然后再次打开弹出窗口并单击按钮,它仍然可以正常工作。但是如果我多次重新打开弹出窗口而不点击,当我再次点击按钮时它会发送更多消息。也许必须从 popup.js 中删除监听器。我试过了,但没有成功。您对如何解决这个问题有任何想法吗? @erosman
    • 谢谢。我现在明白了。
    猜你喜欢
    • 2020-10-12
    • 1970-01-01
    • 2017-12-24
    • 2013-10-12
    • 2014-10-06
    • 1970-01-01
    • 2017-06-11
    • 2023-04-11
    • 2011-08-31
    相关资源
    最近更新 更多