【问题标题】:DOMContentLoaded only onceDOMContentLoaded 仅一次
【发布时间】:2011-09-09 20:33:54
【问题描述】:

我正在将此代码用于 Firefox 扩展

1: var Test {
2:  f: function() {
3:    alert("DOM content loaded");
4:    window.removeEventListener("DOMContentLoaded", function(e) { Test.f(); }, false);
5:  }
6: }
7: window.addEventListener("DOMContentLoaded", function(e) { Test.f(); }, false);

它应该在加载 DOM 内容(weg 页面)时执行函数 f() 中的代码,这意味着如果我打开新页面或新标签或重新加载页面,它应该给我一个警报。问题是,它给了我大约 20 个警报,而不是一个。
如果我想在函数 f() 中将一些文本附加到每个锚点,问题会更糟(例如,如果我想附加文本“(com)”,它将附加“(com)(com)(com)(com)( com)"

你知道如何实现我想要的行为吗? removeEventListener 没有帮助。

罪魁祸首似乎是其他 Firefox 扩展和 about:blank。我在 DOMContentLoaded 上的事件监听器是否有可能忽略其他扩展导致的页面加载?

谢谢

【问题讨论】:

  • 除了在 Wladimir 的回答中进行的讨论(这很好)之外,您可能希望避免使用 alert 来处理此类问题,因为它会一直阻塞,直到用户单击“确定”。也许改用window.dump
  • @MatrixFrog 我禁用了导致这些问题的插件并升级到 Firefox 4。我正在考虑接受他的回答,但如果可以只听 DOMContentLoaded 事件,我还是有点兴趣由浏览器(不是由其他插件)引起的。谢谢你的提示。我一直在寻找比alert 更好的选择。在哪里可以看到window.dump 的输出?
  • 一般来说,其他插件不应触发 DOMContentLoaded 事件,但页面内的框架/iframe 会触发。您需要启用配置设置才能使用 window.dump。见developer.mozilla.org/en/DOM/window.dump
  • 他们不应该,但“在后台”加载的链接在一个插件的数据库中(警报框 - 定期检查更改)。它们位于 e.target.URL 中。同样一些 chrome:// windows 和 about:blank
  • 我认为这与您的问题没有直接关系,但我只想指出 removeEventListener 调用实际上并没有像您认为的那样删除事件。在这两种情况下,您都传入了一个匿名函数,但它们不是 same 匿名函数。 JavaScript 每次定义时都会创建一个新的。为了真正删除事件侦听器,您需要将对该函数的引用保存在一个变量中,并将该变量传递给addremove 调用。

标签: javascript events firefox-addon addeventlistener


【解决方案1】:

您需要测试 DOMContentLoaded 是由框架加载还是主文档加载触发,并且仅在后一种情况下执行您的函数:

    var Test {
        f: function() {
            if (!event.originalTarget.defaultView.frameElement) {
                alert("DOM content loaded");
            }
        }
    }

    window.addEventListener("DOMContentLoaded", function(e) { Test.f(); }, false);

【讨论】:

  • 我使用了if (!e.originalTarget.defaultView.frameElement) { ...,但是当我启用扩展时问题仍然存在,我正在测试alert(e.target.URL);,我得到的网址正在下载另一个扩展。
  • 试试this 扩展,在里面设置一些警报,你会看到。
  • 所以问题是您在打开不包含正常网页的窗口时收到警报(例如扩展安装窗口)?如果我理解正确,您可能想尝试 alert(e.originalTarget.defaultView) 因为我敢打赌有些是 ChromeWindow 对象,您可以过滤掉这些类型。
  • 从扩展加载的 DOMContentLoaded 是 [object XrayWrapper [object Window]] 类型,与我重新加载正常内容时的类型相同。
【解决方案2】:

DOMContentLoaded 通常每个文档只触发一次,所以我怀疑您也在从页面的框架中捕获事件。根据提供的信息无法确定。

我可以告诉你为什么你没有删除监听器。 function(e) { Test.f(); } 是一个闭包,每次运行这段代码都会创建一个新函数。因此,您添加为侦听器的功能与您删除的功能不同。试试下面的例子:

alert(function(e) { Test.f(); } == function(e) { Test.f(); });

为了避免这个问题,你需要真正记住你的闭包,例如:

var listener = function(e)
{
    window.removeEventListener("DOMContentLoaded", listener, false);
    Test.f();
}
window.addEventListener("DOMContentLoaded", listener, false);

【讨论】:

  • @Wladimir Palent : 我应该把你的代码粘贴到哪里来测试它?
  • 您应该将其粘贴到添加侦听器的位置 - 并删除从 Test 删除侦听器的尝试。
  • @Wladimir。您的意思是在我的代码中的第 6 行和第 7 行之间粘贴您的两个 sn-ps?
  • 不,我的意思是用第二个sn-p替换第7行并删除第4行。第一个sn-p只是为了举例说明我所说的。
  • 现在,代码只执行一页。当我重新加载其他页面时,它不是。但我明白,那是因为事件监听器被移除了。所以我在Test.f(); 之后再次添加了它,我又收到了很多警报。我注意到虽然这些警报来自更多选项卡。如果我只打开一个选项卡会更好,当 Firefox 启动时我只会收到两个警报,然后它似乎没问题(到目前为止)。看来我只需要在焦点选项卡中修改 HTML 内容(在 DOMContentLoaded 事件上)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-03
  • 2012-11-01
  • 2020-12-14
  • 2012-02-27
  • 1970-01-01
  • 2017-07-01
相关资源
最近更新 更多