检测 Iframe 内容何时加载(跨浏览器)

Posted

技术标签:

【中文标题】检测 Iframe 内容何时加载(跨浏览器)【英文标题】:Detecting when Iframe content has loaded (Cross browser) 【发布时间】:2010-10-19 13:58:46 【问题描述】:

我正在尝试检测 iframe 及其内容何时加载但运气不佳。我的应用程序在父窗口的文本字段中输入一些内容并更新 iframe 以提供“实时预览”

我开始使用以下代码 (YUI) 来检测 iframe 加载事件何时发生。

$E.on('preview-pane', 'load', function()
    previewBody = $('preview-pane').contentWindow.document.getElementsByTagName('body')[0];

'preview-pane' 是我的 iframe 的 ID,我正在使用 YUI 来附加事件处理程序。但是,尝试在我的回调中访问正文(在 iframe 加载时)失败,我认为是因为 iframe 在事件处理程序准备好之前加载。如果我通过使生成它的 php 脚本休眠来延迟 iframe 加载,则此代码有效。

基本上,我问的是跨浏览器检测 iframe 何时加载且其文档何时准备就绪的正确方法是什么?

【问题讨论】:

从 YUI 开始是个坏主意(以及任何其他 JS 库)。为什么?因为你不知道图书馆在做什么魔法。如果他们不能完全支持“加载”,你最好用清晰易读的javascript自己做。 您可以经常阅读库@Christian 的源代码。我发现无论您是否使用它们的实现,这通常都会为您提供如何自己做的很好的提示。 @AJP 你误解了我的意思。如果你正在做一些你不确定的事情,最好少写一些代码,这样出错的空间就会更小。 取决于你如何看待它。我知道当时 YUI 的事件处理是有效的,所以我不必担心那部分代码。我也知道如何编写自己的 addEvent 处理程序,但在这个问题上它的效果并不比 YUI 好。 @Nico 问题指的是 YUI,$ 是 YUI 的 Dom 包装器的别名。 【参考方案1】:

检测 iframe 何时加载且其文档准备就绪?

如果您可以让 iframe 从框架内的脚本告诉您自己,那就太理想了。例如,它可以直接调用父函数来告诉它它已经准备好了。跨框架代码执行始终需要小心,因为事情可能会以您意想不到的顺序发生。另一种选择是在自己的范围内设置“var isready= true;”,并让父脚本嗅探“contentWindow.isready”(如果没有,则添加 onload 处理程序)。

如果由于某种原因让 iframe 文档协作不切实际,您就会遇到传统的负载竞争问题,即即使元素彼此相邻:

<img id="x" ... />
<script type="text/javascript">
    document.getElementById('x').onload= function() 
        ...
    ;
</script>

无法保证该项目在脚本执行时尚未加载。

解决负载竞争的方法是:

    在 IE 上,您可以使用“readyState”属性来查看是否已加载;

    如果可以接受仅启用 JavaScript 的项目,您可以动态创建它,在设置源和附加到页面之前设置“onload”事件函数。在这种情况下,在设置回调之前无法加载;

    将其包含在标记中的老式方法:

    &lt;img onload="callback(this)" ... /&gt;

html 中的内联“onsomething”处理程序几乎总是错误的,应该避免,但在这种情况下,有时它是最不坏的选择。

【讨论】:

谢谢。我的解决方案检查 readyState(如果存在),然后检查 body 元素的 innerHTML 长度以查看它是否已加载。如果不是,则附加加载事件处理程序。似乎工作正常 -1 - 内联事件并不“坏”,这只是当前的时尚。事实上,内联事件更容易调试和理解,不像它们的魔法对应物(另一方面,更容易无缝地附加、堆叠和使用)。 @Christian,当您需要将事件附加到很长列表的每个元素时,内联事件也是最佳选择。由于您已经在服务器端循环构建列表,因此附加内联事件效率更高。 @haknick 您不想在列表中使用单个事件侦听器并使用事件委托吗? 这样会更有效率。 如果 iframe 是跨域的,这将不起作用。 iframe 内的脚本无法访问父窗口。【参考方案2】:

请参阅 this 博客文章。它使用 jQuery,但即使您不使用它,它也会对您有所帮助。

基本上你把它添加到你的document.ready()

$('iframe').load(function() 
    RunAfterIFrameLoaded();
);

【讨论】:

有趣,但我遇到的问题是加载事件和时间。我正在按照那篇文章的建议监听 load 事件。 我已经用console.log 尝试过这个。它在 iframe 加载后被记录。【参考方案3】:

对于那些使用 React 的人来说,检测同源 iframe 加载事件就像在 iframe 元素上设置 onLoad 事件监听器一样简单。

<iframe src='path-to-iframe-source' onLoad=this.loadListener frameBorder=0 />

【讨论】:

onLoad事件是否只能触发同源iframe?【参考方案4】:

对于使用 Ember 的任何人,这应该可以按预期工作:

<iframe onLoad=action 'actionName'  frameborder='0' src=iframeSrc />

【讨论】:

【参考方案5】:
    此代码检测何时加载了 iframe 内容不使用 jquery

信用Biranchi's answer

    // wait for the doc to load (wait for the class 'iframe...' to load) before sending the script
    checkIframeLoaded()
    
    function checkIframeLoaded() 
        // console.log(" function checked")
        // Get a handle to the iframe element
        var iframe = document.getElementsByClassName("docs-texteventtarget-iframe")[0];
        console.log("iframe", iframe)
        // check if the iframe is loaded or not (= undefined = null)
        if (iframe == null) 
            // If we are here, it is not loaded. Set things up so we check the status again in 1000 milliseconds
            window.setTimeout(checkIframeLoaded, 1000);
         else 
            var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
            // Check if loading is completed
            if (iframeDoc.readyState == 'complete') 
    
                // The loading is complete, call the function we want executed once the iframe is loaded
                iframeDoc.addEventListener("keydown", dispatchkeyboard, false);
             else 
                // even if the iframe is loaded the "readystate may not be completed yet" so we need to recall the function.
                window.setTimeout(checkIframeLoaded, 1000);
            
        
    
    
  
    此代码与 jquery 一起工作

信用:gilles bousquet's answer

    // use jquery to detect when iframe is loaded but doesn't work offline
    // (this code needs jQuery because it use the "$" below). if you use it; add this require in the ===usercript=== section
    //  @require    http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js

    var editingIFrame = $('iframe.docs-texteventtarget-iframe')[0];
   if (editingIFrame) 
        console.log("inside doc.getele")
        editingIFrame.contentDocument.addEventListener("keydown", dispatchkeyboard, false);
    
    

【讨论】:

【参考方案6】:
jQuery(document).ready(function () 
    jQuery('iframe').load(function() 
        console.log(jQuery(this))
    );
)

【讨论】:

以上是关于检测 Iframe 内容何时加载(跨浏览器)的主要内容,如果未能解决你的问题,请参考以下文章

计算跨浏览器 iframe 高度

从子级到父级的跨站点 iframe postMessage

如何检测在线/离线事件跨浏览器?

检测浏览器何时接收文件下载

检测浏览器何时接收文件下载

检测浏览器何时接收文件下载