完成IFRAME加载后的JavaScript回调?


147

我需要在IFRAME完成加载后执行回调。我无法控制IFRAME中的内容,因此无法从那里触发回调。

该IFRAME是通过编程方式创建的,我需要将其数据作为变量传递给回调,以及销毁iframe。

有任何想法吗?

编辑:

这是我现在所拥有的:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.src = url;            
    document.body.appendChild(iFrameObj);   

    $(iFrameObj).load(function() 
    {
        document.body.removeChild(iFrameObj);
        callback(iFrameObj.innerHTML);
    });
}

此回调在iFrame加载之前进行,因此回调没有返回任何数据。


1
我认为您不想将事件处理程序附加到iframe本身,而是内容窗口。
bobwienholt's

1
问题是跨域请求。你不能做到这一点,如果iframe是从另一个域
维克托

实际上,iframe对象上有一个加载事件,每次iframe完成加载文档时都会触发,否则,每次加载后您都需要连接到窗口
Juan Mendes


在这里查看我的答案:stackoverflow.com/a/36155560/3894981
dude 2016年

Answers:


49

首先,使用函数名称xssRequest听起来好像您正在尝试跨站点请求-如果这是正确的,则您将无法读取iframe的内容。

另一方面,如果iframe的URL在您的域中,则可以访问正文,但是我发现如果我使用超时来删除iframe,则回调可以正常工作:

// possibly excessive use of jQuery - but I've got a live working example in production
$('#myUniqueID').load(function () {
  if (typeof callback == 'function') {
    callback($('body', this.contentWindow.document).html());
  }
  setTimeout(function () {$('#frameId').remove();}, 50);
});

4
您可以替换$('body', this.contentWindow.document).html()this.contentDocument.body.outerHTML
Sam Soffes 2010年

12
任何想法如何在没有jQuery的情况下做到这一点?
devios1 2012年

6
从jQuery 3.0开始,load它已经不复存在。请.on('load', function() { ... })改用。
Doppelganger

36

我正在使用jQuery,令人惊讶的是,这似乎在我刚刚测试并加载了一个沉重的页面时就加载了,直到我看到iframe加载,我才收到警告几秒钟:

$('#the_iframe').load(function(){
    alert('loaded!');
});

因此,如果您不想使用jQuery,请查看它们的源代码,看看该函数在iframe DOM元素上的行为是否有所不同,我将在以后感兴趣的地方亲自看一下,并在此处发布。我也只在最新的Chrome中测试过。


我注意到您使用纯JavaScript创建了DOM元素,然后将该变量作为选择器传递给了jQuery,也许这就是为什么您的代码无法正常工作的原因?

12
从jQuery 3.0开始,load它已经不复存在。请.on('load', function() { ... })改用。
多贝冈

8

iframe的innerHTML是空白的,因为您的iframe标记不会围绕父文档中的任何内容。为了从iframe的src属性所引用的页面中获取内容,您需要访问iframe的contentDocument属性。但是,如果src来自其他域,则会引发异常。这是一项安全功能,可防止您在其他人的页面上执行任意JavaScript,这会产生跨站点脚本漏洞。这是一些示例代码,说明了我在说什么:

<script src="http://prototypejs.org/assets/2009/8/31/prototype.js" type="text/javascript"></script>

<h1>Parent</h1>

<script type="text/javascript">
function on_load(iframe) {
  try {
    // Displays the first 50 chars in the innerHTML of the
    // body of the page that the iframe is showing.
    // EDIT 2012-04-17: for wider support, fallback to contentWindow.document
    var doc = iframe.contentDocument || iframe.contentWindow.document;
    alert(doc.body.innerHTML.substring(0, 50));
  } catch (e) {
    // This can happen if the src of the iframe is
    // on another domain
    alert('exception: ' + e);
  }
}
</script>
<iframe id="child" src="iframe_content.html" onload="on_load(this)"></iframe>

为了进一步说明该示例,请尝试将其用作iframe的内容:

<h1>Child</h1>

<a href="http://www.google.com/">Google</a>

<p>Use the preceeding link to change the src of the iframe
to see what happens when the src domain is different from
that of the parent page</p>

1
IE 7不支持contentDocument属性,也许更多的IE也不支持,处理IE的方法是window ['iframeid']。document或完全相同的window.frames ['iframeid']。document证明链接。 mozilla.org/en/…–
奥尔加,

7

在将Word文档和pdf等文档流式传输到iframe并找到一个效果很好的解决方案的情况下,我不得不这样做。关键是要处理onreadystatechanged在iframe上事件。

可以说您的框架名称是“ myIframe”。首先在代码启动的某个位置(我在iframe之后的任何位置进行内联)添加类似以下内容以注册事件处理程序:

document.getElementById('myIframe').onreadystatechange = MyIframeReadyStateChanged;

我无法在iframe上使用onreadystatechage属性,我不记得为什么,但是该应用程序必须能够在IE 7和Safari 3中运行,因此这可能是一个因素。

这是如何获取完整状态的示例:

function MyIframeReadyStateChanged()
{
    if(document.getElementById('myIframe').readyState == 'complete')
    {
        // Do your complete stuff here.
    }
}

6

当i框架内容完全加载到IE时,我想隐藏等待中的Spinner div,我实际上尝试了Stackoverflow.Com中提到的所有解决方案,但没有按我希望的方式工作。

然后我有了一个想法,当第i个框架内容完全加载时,可能会触发$(Window)加载事件。正是这样。所以,我写了这个小脚本,像魔术一样工作:

     $(window).load(function () {
     //alert("Done window ready ");
     var lblWait = document.getElementById("lblWait");
     if (lblWait != null ) {
         lblWait.style.visibility = "false";
         document.getElementById("divWait").style.display = "none";
     }
 });

希望这可以帮助。


这是一个简单的解决方案,如果您希望在加载整个页面后执行javascript,则效果很好。这意味着首先您会看到完全加载的页面,没有js效果,然后可能在一两秒钟后(取决于负载),JavaScript所创建的任何更改都将发生。我个人尝试过调整iframe的大小,如果您在单击页面后的前三秒内不注意屏幕,则该方法可以工作,但是这可能(如我的情况)看起来像是代码的拼凑而成。
符号

1
感谢您的评论,此解决方案在我的情况下非常有效,因为我希望在页面加载后加载iframe。
Nada N. Hantouli 2015年

2

我和你有类似的问题。我所做的是使用了一种称为jQuery的东西。然后,您在javascript代码中执行的操作是:

$(function(){ //this is regular jQuery code. It waits for the dom to load fully the first time you open the page.

    $("#myIframeId").load(function(){
       callback($("#myIframeId").html());
       $("#myIframeId").remove();

    });

});

似乎在删除iFrame之前,您先从中获取html。现在,我确实看到了一个问题:p

希望这可以帮助 :)。


1

我的项目中有类似的代码,可以正常工作。使我的代码适应您的功能,可以采用以下解决方案:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.id = 'myUniqueID';
    document.body.appendChild(iFrameObj);       
    iFrameObj.src = url;                        

    $(iFrameObj).load(function() 
    {
        callback(window['myUniqueID'].document.body.innerHTML);
        document.body.removeChild(iFrameObj);
    });
}

也许您有一个空的innerHTML,因为(一个或两个原因):1.您应该将它用于body元素2.您已从页面DOM中删除了iframe


1

我认为加载事件是正确的。不正确的是您用来从iframe内容dom中检索内容的方法。

您需要的是在iframe中加载的页面的html,而不是iframe对象的html。

您要做的是使用来访问内容文档iFrameObj.contentDocument。如果iframe位于当前页面的同一域中,则将返回加载到iframe中的页面的dom。

在删除iframe之前,我会先整理内容。

我已经在Firefox和Opera中测试过。

然后,我认为您可以使用$(childDom).html()或来检索数据$(childDom).find('some selector') ...


0

过去,我遇到了完全相同的问题,找到解决此问题的唯一方法是将回调添加到iframe页面中。当然,只有在您可以控制iframe内容的情况下,该方法才有效。


22
我没有否决您的意见,但我想您被否决了,是因为您确切地提出了他说他不能做的事情-他确实说过:“我无法控制IFRAME中的内容,因此我可以”请从那里触发回调。”
戴夫·海恩斯

-1

使用 onload attrbute将解决您的问题。

这是一个例子。

function a() {
alert("Your iframe has been loaded");
}
<iframe src="https://stackoverflow.com" onload="a()"></iframe>

这是你想要的吗?

单击此处了解更多信息。

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.