如何检查iframe是否已加载或是否包含内容?


83

我有一个id =“ myIframe”的iframe,这里是我加载其内容的代码:

$('#myIframe').attr("src", "my_url");

问题是有时加载时间太长,有时加载速度非常快。所以我必须使用“ setTimeout”函数:

setTimeout(function(){
   if (//something shows iframe is loaded or has content)
   {
       //my code
   }
   else
   {
       $('#myIframe').attr("src",""); //stop loading content
   }
},5000);

我唯一想知道的是如何确定是否已加载iFrame或是否包含内容。使用iframe.contents().find()将不起作用。我不能用iframe.load(function(){})


因此,如果加载时间超过5秒,您不希望iframe加载任何内容?
skimberk1

谢谢你的帮助 :) 。是的,如果要花费5秒钟以上的时间,我不希望iframe加载任何内容。如下面所示,使用“ .ready()”不起作用。
newbie29


Answers:


87

试试这个。

<script>
function checkIframeLoaded() {
    // Get a handle to the iframe element
    var iframe = document.getElementById('i_frame');
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

    // Check if loading is complete
    if (  iframeDoc.readyState  == 'complete' ) {
        //iframe.contentWindow.alert("Hello");
        iframe.contentWindow.onload = function(){
            alert("I am loaded");
        };
        // The loading is complete, call the function we want executed once the iframe is loaded
        afterLoading();
        return;
    } 

    // If we are here, it is not loaded. Set things up so we check   the status again in 100 milliseconds
    window.setTimeout(checkIframeLoaded, 100);
}

function afterLoading(){
    alert("I am here");
}
</script>

<body onload="checkIframeLoaded();"> 

21
将字符串传递给setTimeout()的缺点。通过功能参考更干净:setTimeout(checkIframeLoaded, 100);
Jesse Hallett

1
这导致“不安全的JavaScript尝试从具有url2的框架访问具有URL url1的框架的域,协议和端口必须匹配。”
mohamed-ibrahim

这是我要完成的最佳解决方案。我在iFrame中使用AngularJS,并使用ng-include,这会延迟加载包含的文件。我试图在onload事件上打印iframe的内容,但是触发得太早了。检查是否readyState === "complete"成功,因为直到所有内容加载完毕,它才会改变。
Jeffrey A. Gochin

3
我必须说这也是对我有用的唯一解决方案。您只是不信任iframe上的load事件,因为在大多数情况下,该事件会立即在IE11,Chrome和Edge上触发,iframe.contentDocument.location.href显示为about:blank。即使直接在HTML中指定的src,这似乎也是正确iframe的。
rmalayter '16

21
如果iframe来自其他域,则此方法将无效:VM29320:1 Uncaught DOMException: Blocked a frame with origin "http://localhost:9002" from accessing a cross-origin frame.
Augustin Riedinger,2016年

45

请使用:

$('#myIframe').on('load', function(){
    //your code (will be called once iframe is done loading)
});

随着标准的变化,更新了我的答案。


5
现在不建议再调用.load。请改用.on('load',function(){})
Graham

51
现在不建议使用jQuery ^^
cchamberlain

4
这种方法根本不起作用,因为事件iframe通常会立即触发,因为s通常以开头src="about:blank",即使ssrc是直接在HTML中指定的,也没有在将iframe节点添加到DOM之前指定的。我测试了这通过轮询的iframecontentDocument.location.href在IE11,Chrome和边缘紧密循环。如果被框架化的内容确实通过meta标签或javascript进行了重定向,那么它也不起作用。
rmalayter '16

17

我遇到了同样的问题,并添加到此问题中,我需要检查是否加载了iframe,无论跨域策略如何。我正在开发一个chrome扩展程序,该扩展程序可以将某些脚本插入网页中,并在iframe中显示父页面的某些内容。我尝试了以下方法,这对我来说很完美。
PS:就我而言,我确实可以控制iframe中的内容,但不能控制父网站上的内容。(iframe托管在我自己的服务器上)

首先:
创建一个具有data-属性的iframe,就像(在我的情况下,这部分是在注入脚本中)
<iframe id="myiframe" src="http://anyurl.com" data-isloaded="0"></iframe>

现在在iframe代码中,使用:

var sourceURL = document.referrer;
window.parent.postMessage('1',sourceURL);



现在根据我的情况回到注入的脚本:

setTimeout(function(){
  var myIframe = document.getElementById('myiframe');
  var isLoaded = myIframe.prop('data-isloaded');
  if(isLoaded != '1')
  {
    console.log('iframe failed to load');
  } else {
    console.log('iframe loaded');
  }
},3000);


和,

window.addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
    if(event.origin !== 'https://someWebsite.com') //check origin of message for security reasons
    {
        console.log('URL issues');
        return;
    }
    else {
        var myMsg = event.data;
        if(myMsg == '1'){
            //8-12-18 changed from 'data-isload' to 'data-isloaded
            $("#myiframe").prop('data-isloaded', '1');
        }
    }           
}



它可能无法完全回答问题,但确实是我通过此方法解决的该问题的可能情况。


您的代码中有一些错误,例如document.getElement-> s <-ById,但是整个想法很有用。有用。谢谢)
JohnK

@JohnK感谢您指出这一点,我已修复它。很高兴知道这对您有用。
Tushar Shukla

12

最简单的选择:

<script type="text/javascript">
  function frameload(){
   alert("iframe loaded")
  }
</script>

<iframe onload="frameload()" src=...>

10
不是一个可靠的解决方案,因为即使URL损坏,它也会发出警报。
bboy

7

您可以load在加载iframe时使用iframe的事件进行响应。

document.querySelector('iframe').onload = function(){
    console.log('iframe loaded');
};

这不会告诉您是否加载了正确的内容:要进行检查,可以检查contentDocument

document.querySelector('iframe').onload = function(){
    var iframeBody = this.contentDocument.body;
    console.log('iframe loaded, body is: ', body);
};

contentDocument如果iframesrc指向代码运行所在的其他域,则无法进行检查。


2
请考虑编辑您的文章,以添加更多有关代码功能以及其解决问题原因的解释。通常只包含代码(即使它在起作用)的答案通常不会帮助OP理解他们的问题。
SuperBiasedMan 2015年

5

我不确定是否可以检测到它是否已加载,但是一旦加载完成就可以触发事件:

$(function(){
    $('#myIframe').ready(function(){
        //your code (will be called once iframe is done loading)
    });
});

编辑:正如Jesse Hallett所指出的,这将始终在iframe加载时触发,即使它已经加载也是如此。因此,从本质上讲,如果iframe已加载,则回调将立即执行。


2
关于此方法的好处是,即使在iframe完全加载后将其绑定,也将触发jQuery“ ready”事件。因此,这是检查iframe是否已包含内容或在获取内容时通知您的好方法。
杰西·哈雷特

1
对于iframe,这似乎只触发一次。但是,如果您的iframe中包含链接,可能会导致iframe中的内容被重新加载,则此事件将不会再次触发。如果您是这种情况,请使用@pratikabu的答案$('#myIframe').load(function(){ })
ragamufin 2013年

@ skimberk1嗨,根据这个答案,您的解决方案将无法工作,因为jquery拥有一个变量来记住DOM是否已加载,并且onley会检查当前帧的当前DOM而不是iframe的DOM。
Marco Medrano 2014年

是的,您可以发起事件,播放视频,准备就绪后播放音乐,非常有信息....
Giridhar Karnik 2015年

根据此票证:在iframe上使用dev.jquery.com/ticket/5511ready将始终立即执行该功能,因为其他文档(运行jQuery的框架)不支持该功能。
花花公子

5

在我的情况下,它是跨源框架,有时没有加载。对我有用的解决方案是:如果加载成功,则尝试以下代码:

var iframe = document.getElementsByTagName('iframe')[0];
console.log(iframe.contentDocument);

它不会允许您访问contentDocument并引发跨域错误,但是如果未成功加载框架,contentDocument则会返回一个#document对象


2

加载iFrame时,它最初包含#document,因此检查加载状态最好通过检查当前内容来完成。

if ($('iframe').contents().find('body').children().length > 0) {
    // is loaded
} else {
    // is not loaded
}

6
如果它在其他域上,则将失败
Funkodebat,2015年

这是不正确的,因为iframe可能正在加载过程中(未完全加载)。
Mike Shiyan

1

我得到了如下的技巧:[尚未测试跨浏览器!]

定义iframe的onload事件处理程序,定义为

$('#myIframe').on('load', function() {
    setTimeout(function() {
        try {
            console.log($('#myIframe')[0].contentWindow.document);
        } catch (e) {
            console.log(e);
            if (e.message.indexOf('Blocked a frame with origin') > -1 || e.message.indexOf('from accessing a cross-origin frame.') > -1) {
                alert('Same origin Iframe error found!!!');
                //Do fallback handling if you want here
            }
        }
    }, 1000);

});

免责声明:仅适用于SAME ORIGIN IFRAME文档。


0

一个非常好的方法是使用jQuery AJAX。父框架如下所示:

<iframe src="iframe_load.php" style="width: 100%; height: 100%;"></iframe>

iframe_load.php文件将加载jQuery库和一个JavaScript,以尝试在AJAX GET中加载目标URL:

var the_url_to_load = "http://www.your-website.com" ;
$.ajax({
            type: "GET",
            url: the_url_to_load,
            data: "",
            success: function(data){
                // if can load inside iframe, load the URL
                location.href = the_url_to_load ;
            },
            statusCode: {
                500: function() {
                    alert( 'site has errors' ) ;
                }
            },
            error:function (xhr, ajaxOptions, thrownError){
                // if x-frame-options, site is down or web server is down
                alert( 'URL did not load due to x-frame-options' ) ;
            } });

重要信息目标必须包含“ Access-Control-Allow-Origin”标头。PHP中的示例:

HEADER( "Access-Control-Allow-Origin: *" ) ;

0

如果您需要知道何时可以准备操作iframe,请使用一个间隔。在这种情况下,我每250毫秒对内容进行“ ping”操作,如果目标iframe中有任何内容,请停止“ ping”操作。

var checkIframeLoadedInterval = setInterval( checkIframeLoaded, 250 );

function checkIframeLoaded() {
    var iframe_content = $('iframe').contents();

    if (iframe_content.length > 0) {
        clearInterval(checkIframeLoadedInterval);

        //Apply styles to the button
        setTimeout(function () {
            //Do something inside the iframe 
            iframe_content.find("body .whatever").css("background-color", "red");
        }, 100); //100 ms of grace time
    }
}

0

如果您将网页和iframe托管在同一个域中,则可以监听iframe的Window.DOMContentLoaded事件。您必须先等待原始页面触发DOMContentLoaded,然后DOMContentLoaded在iframe的上附加事件监听器Window

假设您具有以下iframe,

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

下一个代码段将允许您了解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!');
    });
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.