Chrome扩展:检测弹出窗口关闭的方法

7
对于我的Chrome扩展程序,我希望在browserAction弹出窗口关闭时执行某个操作。我了解到没有内置事件会在此时触发。我找到了this suggestion来打开与后台脚本的连接,然后使用连接的port.onDisconnect事件来检测弹出窗口是否关闭。
然而,当弹出窗口关闭时,我在后台脚本的开发人员控制台中看到以下错误:
(BLESSED_EXTENSION context for glkehflnlfekdijfhacccflbffbjhgbd) extensions::messaging:102: Uncaught TypeError: Cannot read property 'destroy_' of undefined{TypeError: Cannot read property 'destroy_' of undefined
   at PortImpl.destroy_ (extensions::messaging:102:37)
   at dispatchOnDisconnect (extensions::messaging:322:29)}

下面是我使用的脚本。
你能看出我哪里出错了吗?

manifest.json

{ "manifest_version": 2

, "name": "Detect when popup closes"
, "version": "0.1"

, "browser_action": {
    "default_icon": "popup.png"
  , "default_popup": "popup.html"
  }

, "background": {
    "scripts": [
      "background.js"
    ]
  }
}

popup.html

<!DOCTYPE html>
<body>
  <h1>Test</h1>

  <script src="popup.js"></script>  
</body>
</html>

popup.js

var port = chrome.runtime.connect()

background.js

chrome.runtime.onConnect.addListener(function (externalPort) {
  externalPort.onDisconnect = function () {
    try { 
      var ignoreError = chrome.runtime.lastError
    } catch (error) {
      console.log("onDisconnect")
    }
  }
)

2
建议是在后台脚本中检测事件。端口被断开连接是因为弹出窗口已被销毁,因此没有剩余的事件监听器可用于端口断开连接时调用。 - wOxxOm
@wOxxOm 我已经重写了我的基本扩展,使用port.onDisconnect在后台脚本中,正如你所建议的那样。然而,这只是将错误转移到弹出窗口关闭的时刻。 - James Newton
在这种情况下,错误已经被记录下来,可以通过简单的赋值 var ignoreError = chrome.runtime.lastError 忽略。重要的是断开连接监听器实际上会触发。 - wOxxOm
@wOxxOm 我加入了你建议的赋值,但我怀疑我放错了地方。也许断开连接的监听器会触发,但错误会阻止我做任何有用的事情。 - James Newton
1
@JamesNewton 我撤销了你的“已解决”编辑;将来,请在单独的答案中发布您自己的解决方案(如果适用)。自我回答绝对没问题,但是将答案混合到问题中是不行的。此外,在标题中标记问题为已解决是没有必要的(有一个被接受的答案就足够了)。 - Xan
2个回答

13

以下是 background.js 脚本的工作版本,仅供参考:

chrome.runtime.onConnect.addListener(function (externalPort) {
  externalPort.onDisconnect.addListener(function () {
    console.log("onDisconnect")
    // Do stuff that should happen when popup window closes here
  })

  console.log("onConnect")
})

7

onDisconnect不是可分配的属性。
它是一个对象,提供addListener方法来注册回调函数:

externalPort.onDisconnect.addListener(function() {
    var ignoreError = chrome.runtime.lastError;
    console.log("onDisconnect");
});

1
是的,但只是为了稍后修改端口的行为。侦听器本身在浏览器内部注册,所以它会保留下来。 - wOxxOm
当弹出窗口关闭时,如何触发.onDisconnect?每当我实现它时,它只在实际扩展被卸载时触发。 - Mudlabs
好的,太棒了!我正在尝试在我的 popup.jscontent script 之间设置一个消息端口。但是你必须通过 background.js,就像它是邮局,popup.jscontent script 是两个试图发送信件的人,对吗? - Mudlabs
内容脚本也应该正常工作。我的意思是onDisconnect不应该在弹出窗口本身中。 - wOxxOm
1
@wOxxOm,将onDisconnect监听器放置在Content Script中而不是background.js中是否可能?我尝试过了,但无法使其工作。这将节省我创建另一个要注入的脚本的时间,因为我希望在关闭弹出窗口时运行的方法位于Content Script内部。 - Magnus
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接