【问题标题】:Detect DOMContentLoaded in iframe检测 iframe 中的 DOMContentLoaded
【发布时间】:2020-03-10 06:54:06
【问题描述】:

我惊讶地发现以下似乎不起作用,因为 DOMContentLoaded 事件没有触发(this.els 是元素的对象)。

this.els.stage_ifr.prop('src', 'templates/'+ee.globals.creating+'/item'+this.id);
this.els.stage_ifr[0].addEventListener('DOMContentLoaded', function() {
    alert('loaded!');
}, false);

页面加载到 iframe 中正常,但没有回调。但是,DOM 零级 onload 可以工作。

this.els.stage_ifr[0].onload = function() { alert('loaded!'); }; //<-- fires

一种解决方法是在父页面中准备一个全局可访问的 jQuery 延迟对象,并通过调用 iframe 的页面触发 DOM-ready 事件来解决它,而不是从父页面监听 DOM-ready。

父页面:

dfd = new $.Deferred;
dfd.done(function() { alert("frame page's DOM is ready!"); });

框架页面:

$(function() { window.parent.dfd.resolve(); });

尽管如此,了解第一种方法的情况会很好......

【问题讨论】:

  • 我提供了一个指向 MSDN 的链接:iframe element。正如您在该页面上看到的那样,DOMContentLoaded 不能附加到 iframe
  • 有趣 - 如果框架属于同一域,我应该认为这非常好。如果这确实是案例结束,请随时将其作为答案发布,我会接受。
  • 您可以尝试将DOMContentLoaded(仅限document 的方法)附加到stage_ifr[0].contentDocument,我只是不确定它是否在您需要的时候存在。 ..
  • 我会试一试的。 jQuery deferred 解决方法可以在不可行的情况下工作。谢谢。

标签: javascript events dom iframe domready


【解决方案1】:

在回复this question的过程中,我发现了你的DOMContentLoaded事件监听器不起作用的原因。在我看来,您有两个问题。

首先,您尝试在 iFrame 本身上侦听 DOMContentLoaded 事件。这不是 iFrame 事件。这是一个文档事件。因此,您必须进入 iFrame 以获取 contentWindow,然后从中获取文档。这就引出了第二个问题。

其次,当第一次创建 iFrame 时,其中有一个虚拟的 document,它与通过 .src 属性加载动态内容时最终存在的文档不同。所以,即使你这样做了:

this.els.stage_ifr.contentWindow.document

要在 iFrame 中获取文档,它不一定是正确的文档,因此不会触发 DOMContentLoaded 事件(我在 Chrome 中看到过这种行为)。


MDN 表示可以在 iFrame 本身上侦听DOMFrameContentLoaded 事件,这与底层文档实际获取DOMContentLoaded 的时间相对应。不幸的是,我无法让这个事件在任何浏览器中工作。所以,目前,我知道的唯一解决方法是从 iFrame 本身触发加载事件,它可以在其中监听自己的 DOMContentLoaded 事件(如果需要,它可以调用父窗口)或者只监听 iFrame 对象上的 load 事件,并知道在 iFrame 中的样式表和图像等资源也加载之前它不会触发。


无论如何,我想我会解释一下你的初始代码发生了什么,并提供另一个解决方案,尽管这个问题是一年多前发布的(尽管从未回答过)。


更新:

我开发了一种跟踪DOMContentLoaded 的方法,该方法用于加载与其父级相同来源的 iFrame。可以看代码here

【讨论】:

  • 我已经在问自己为什么 readyState 在 Chrome 中总是 completed。现在我知道这是因为 Chrome 设置了一个空文档并在此之后创建了实际的 iframe 文档(与 src 属性相关)。如此糟糕的行为,如果 Chrome 能像其他浏览器一样处理这个问题,我们可以简单地使用 readyState
  • DOMFrameContentLoaded 不仅是Mozilla-specific event,而且还是一个“特定于插件的事件”,它“永远不会暴露于网络内容,只能在 chrome 内容上下文中使用”。
【解决方案2】:

在尝试了不同的选项后,我发现以下代码对我有用:

var iframe = document.getElementById("app-frame-id");
iframe.contentWindow.addEventListener("DOMContentLoaded", onFrameDOMContentLoaded, true);
function onFrameDOMContentLoaded () { 
     console.log("DOMContentLoaded");
};

【讨论】:

  • 当你更改 iframe 的来源时这不起作用
  • 似乎对我有用。但是您能否描述一下这到底是做什么的以及为什么不将此事件分配给contentWindow 的文档属性?
  • @dude 从其他答案复制“第二,当 iFrame 首次创建时,其中有一个虚拟文档,与通过 . src 属性"
【解决方案3】:

如果您的页面和 iframe 在同一个域中,您必须先等待原始页面触发 DOMContentLoaded,然后在 iframe 的 Window 上附加一个 DOMContentLoaded 事件侦听器(不是Document)。

假设您有如下 iframe,

<iframe id="iframe-id" name="iframe-name" src="..."></iframe>

下一个 sn-p 将允许您挂钩 iframe 的 DOMContentLoaded 事件:

document.addEventListener('DOMContentLoaded', function () {
    var iframeWindow = frames['iframe-name'];
    // var iframeWindow = document.querySelector('#iframe-id').contentWindow
    // var iframeWindow = document.getElementById('iframe-id').contentWindow

    iframeWindow.addEventListener('DOMContentLoaded', function () {
        console.log('iframe DOM is loaded!');
    });
});

【讨论】:

    【解决方案4】:

    这可能更像是一个 hack,但帮助我解决了一个类似的问题。

    我现在正在收听框架内容的onmouseenter

    此事件在load 之前触发(如果用户移动鼠标)。但就我而言,我需要事件来初始化上下文菜单,无论如何使用鼠标都是先决条件。

    它甚至会在鼠标下的框架内容发生变化时触发。

    【讨论】:

    • 有趣的方法。感谢您的提醒。
    猜你喜欢
    • 2013-06-03
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 2010-10-29
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多