javascript 检测 iframe 中的 DOMContentLoaded

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16960829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 06:36:17  来源:igfitidea点击:

Detect DOMContentLoaded in iframe

javascripteventsdomiframedomready

提问by Utkanos

I was surprised to find the following doesn't appear to work, insofar as the DOMContentLoaded event doesn't fire (this.elsis an object of elements).

我很惊讶地发现以下内容似乎不起作用,因为 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);

The page loads into the iframe fine, but no callback. The DOM level zero onload, however, works.

页面加载到 iframe 中,但没有回调。onload然而,DOM level zero有效。

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

A workaround is to prepare a globally-accessible jQuery deferred object in the parent page and resolve it via a DOM-ready event fired from the page called into the iframe, rather than listening for DOM-ready from the parent.

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

Paraent page:

父页面:

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

Frame page:

框架页面:

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

Nonetheless it would be good to know what's up with the first approach...

尽管如此,最好知道第一种方法的情况......

回答by jfriend00

In the process of answering this question, I discovered the reason your DOMContentLoadedevent listener doesn't work. It appears to me that you have two issues.

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

First, you're trying to listen for the DOMContentLoadedevent on the iFrame itself. That isn't an iFrame event. It is a document event. So you have to reach into the iFrame to get the contentWindow and then get the document from that. That leads into the second issue.

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

Second, when an iFrame is first created, it has a dummy documentin it that is NOT the same document as will eventually be there when dynamic content is loaded via the .srcattribute. So, even if you did:

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

this.els.stage_ifr.contentWindow.document

to get the document in the iFrame, it will not necessarily be the right document and thus the DOMContentLoadedevent won't fire on it (I've seen this behavior in Chrome).

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



MDN says that one can listen for the DOMFrameContentLoadedevent on the iFrame itself and this will correspond with when the underlying document actually gets DOMContentLoaded. Unfortunately, I can't get this event to work in any browser. So, at this moment, the only work-around I know of is to either trigger the load event from within the iFrame itself where it can listen to its own DOMContentLoadedevent (it can call out to the parent window if need be) or to just listen for the loadevent on the iFrame object and know that it won't fire until resources such as style sheets and images in the iFrame are also loaded.

MDN 说可以DOMFrameContentLoaded在 iFrame 本身上监听事件,这将与底层文档实际获取DOMContentLoaded. 不幸的是,我无法在任何浏览器中使用此事件。因此,目前,我所知道的唯一解决方法是从 iFrame 本身内部触发加载事件,在那里它可以侦听自己的DOMContentLoaded事件(如果需要,它可以调用父窗口)或只是侦听loadiFrame 对象上的事件,并知道在加载 iFrame 中的样式表和图像等资源之前它不会触发。



Anyway, I thought I'd explain some of what was going on with your initial code and offer another solution even though this question was posted more than a year ago (though never answered).

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



Update:

更新:

I've developed a method of tracking DOMContentLoadedfor an iFrame loaded with the same origin as its parent. You can see the code here.

我开发了一种跟踪DOMContentLoadediFrame的方法,该 iFrame 加载的来源与其父级相同。您可以在此处查看代码。

回答by ivan.ice

After trying different options I found that the following code works for me:

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

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

回答by JochenJung

This might be more of a hack, but helped me solve a similar issue.

这可能更像是一种黑客攻击,但帮助我解决了类似的问题。

I am listening for onmouseenterof the frame content now.

我现在正在监听onmouseenter框架内容。

This event triggers ahead of load(if the user moves the mouse). But as in my case I need the event for initialising a context menu, using the mouse was a precondition anyway.

此事件提前触发load(如果用户移动鼠标)。但在我的情况下,我需要初始化上下文菜单的事件,无论如何使用鼠标是一个先决条件。

It even triggers when the frame content changes under the mouse.

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

回答by Daniel

If your page and the iframe are on the same domainyou have to wait for the original page to fire DOMContentLoadedfirst, then attach a DOMContentLoadedevent listener on the iframe's Window(not Document).

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

Given you have an iframe as follows,

鉴于您有一个 iframe,如下所示,

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

the next snippet will allow you to hook into the iframe's DOMContentLoadedevent:

下一个片段将允许您挂接到 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!');
    });
});