DOMContentLoaded仅触发一次

7

我正在使用这段代码制作火狐扩展

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内容(网页)加载时,它应该执行函数f()中的代码,这意味着如果我打开新页面、新标签或重新加载页面,它应该给我一个警报。问题是,它给了我大约20个警报,而不是一个。
如果我想在函数f()中附加一些文本到每个锚点上(例如,如果我想要附加文本“(com)”,它将会附加“(com)(com)(com)(com)(com)”),那么问题会更加严重。
你知道如何实现我想要的行为吗? removeEventListener并没有帮助。
罪魁祸首似乎是其他Firefox扩展和about:blank。我的DOMContentLoaded事件监听器是否忽略了由其他扩展引起的页面加载?
谢谢。

除了Wladimir的回答中正在进行的讨论外,你可能希望避免像这样使用alert,因为它会阻塞直到用户点击OK。也许可以使用window.dump代替。 - Tyler
@MatrixFrog 我禁用了导致这些问题的插件并升级到Firefox 4。我正在考虑接受他的答案,但我仍然有点想知道是否可能仅侦听由浏览器(而不是其他插件)引起的DOMContentLoaded事件。谢谢你的提示。我正在寻找比“alert”更好的替代方案。我在哪里可以看到window.dump的输出? - xralf
通常情况下,其他插件不应该触发DOMContentLoaded事件,但是页面中的框架/内联框架将会触发。您需要启用配置设置才能使用window.dump。请参见https://developer.mozilla.org/en/DOM/window.dump。 - Tyler
他们不应该,但是在后台加载的链接在一个插件的数据库中(alertbox - 定期检查更改)。它们在e.target.URL中。同样的,一些chrome://窗口和about:blank。 - xralf
我不认为这与您的问题直接相关,但我想指出removeEventListener调用实际上并没有像您想象的那样删除事件。在两种情况下,您都传递了一个匿名函数,但它们不是相同的匿名函数。JavaScript每次定义时都会创建一个新的函数。为了真正删除事件侦听器,您需要将该函数保存到变量中,并将该变量传递到addremove调用中。 - mAAdhaTTah
2个回答

1

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:我应该把你的代码粘贴到哪里来测试它? - xralf
你应该将它粘贴到添加监听器的位置,并删除从“Test”中尝试删除监听器的操作。 - Wladimir Palant
不,我的意思是用第二个片段替换第7行,并删除第4行。第一个片段只是为了说明我说的话。 - Wladimir Palant
我只打开了两个标签页,这两个网址被警告了。其他约10个警报是关于:blank和chrome://firebug或类似的内容。但是,除了这两个标签页,我没有打开其他标签页。 - xralf
当我开始浏览时,我会收到很多警报,其中包含未打开的URL,好像它与其他Firefox扩展冲突。 - xralf
显示剩余5条评论

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); 我得到的 URL 是下载其他扩展程序的地址。 - xralf
使用扩展程序,设置一些警报并查看结果。 - xralf
所以问题是当打开不包含正常网页(例如扩展安装窗口)的窗口时,您会收到警报?如果我理解正确的话,您可以尝试 alert(e.originalTarget.defaultView),因为我敢打赌其中一些是 ChromeWindow 对象,您可以过滤掉这些类型。 - Amir Nathoo
扩展程序中的DOMContentLoaded类型为[object XrayWrapper [object Window]],与我重新加载普通内容时的类型相同。 - xralf

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