【问题标题】:Javascript callback when IFRAME is finished loading?IFRAME 完成加载时的 Javascript 回调?
【发布时间】:2010-09-14 21:54:01
【问题描述】:

当 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 加载之前,所以回调没有返回数据。

【问题讨论】:

  • 我认为您不想将事件处理程序附加到 iframe 本身,但它是内容窗口。
  • 问题是跨域请求。如果 iframe 来自另一个域,则不能这样做
  • 实际上,每次 iframe 完成加载文档时都会触发 iframe 对象上的 load 事件,否则,您需要在每次加载后连接到窗口
  • 在这里查看我的答案:stackoverflow.com/a/36155560/3894981

标签: javascript events dom iframe


【解决方案1】:

过去我也遇到过完全相同的问题,我发现解决它的唯一方法是将回调添加到 iframe 页面中。当然,这仅在您可以控制 iframe 内容时才有效。

【讨论】:

  • 我没有给你投反对票,但我想你被投反对票是因为你确切地建议了他说他不能做的事情——他确实明确地说,“我无法控制内容在 IFRAME 中,所以我不能从那里触发回调。”
【解决方案2】:

我的项目中有类似的代码运行良好。 使我的代码适应您的功能,解决方案可能如下:

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

【讨论】:

    【解决方案3】:

    首先,通过函数名称 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);
    });
    

    【讨论】:

    • 你可以用this.contentDocument.body.outerHTML替换$('body', this.contentWindow.document).html()
    • 知道如何在没有 jQuery 的情况下做到这一点吗?
    • 从 jQuery 3.0 开始,load 消失了。请改用.on('load', function() { ... })
    【解决方案4】:

    如果 word docs 和 pdf 等文档被流式传输到 iframe 并找到了一个运行良好的解决方案,我不得不这样做。关键是处理 iframe 上的onreadystatechanged 事件。

    假设您的框架的名称是“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.
        }
    }
    

    【讨论】:

      【解决方案5】:

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

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

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

      我会在删除 iframe 之前检索内容。

      我已经在 firefox 和 opera 中测试过。

      那么我认为您可以使用$(childDom).html()$(childDom).find('some selector') ... 检索您的数据

      【讨论】:

        【解决方案6】:

        您的 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>
        

        【讨论】:

        • IE 7 不支持 contentDocument 属性,也许还有更多的 IE,处理 IE 的方式是 window['iframeid'].document 或完全相同的 window.frames['iframeid' ].文件证明链接在这里developer.mozilla.org/en/…
        【解决方案7】:

        我遇到了和你类似的问题。我所做的是我使用了一个叫做 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();
        
            });
        
        });
        

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

        希望这会有所帮助:)。

        【讨论】:

          【解决方案8】:

          我正在使用 jQuery,令人惊讶的是,这似乎加载了,因为我刚刚测试并加载了一个沉重的页面,并且在看到 iframe 加载之前几秒钟我没有收到警报:

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

          因此,如果您不想使用 jQuery,请查看他们的源代码,看看此函数与 iframe DOM 元素的行为是否不同,稍后我会自己查看它,因为我有兴趣并在此处发布。另外我只在最新的 chrome 中测试过。

          【讨论】:

          • 我注意到您使用纯 javascript 创建了 DOM 元素,然后将该变量作为选择器传递给 jQuery,也许这就是您的代码不起作用的原因?
          • 从 jQuery 3.0 开始,load 消失了。请改用.on('load', function() { ... })
          【解决方案9】:

          当 i 框架内容在 IE 上完全加载时,我想隐藏等待的微调器 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 的大小,如果您在单击页面后的前三秒钟内不注意屏幕,它会起作用,但否则这可能(就像我的情况一样)显示为代码的拼凑。
          • 感谢您的评论,这个解决方案在我的情况下非常有效,因为我希望在页面加载后加载 iframe。
          【解决方案10】:

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

          这是一个例子。

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

          这是你想要的吗?

          Click here 了解更多信息。

          【讨论】:

            【解决方案11】:

            如果 iFrame 已经加载或等待 iFrame 完全加载,此函数将立即运行您的回调函数。

            这也解决了以下问题:

            1. Chrome 使用 about:blank 页面初始化每个 iFrame,该页面将包含 readyState == "complete"。稍后,它会将 `about:blank 替换为实际的 iframe src 值。所以,readyState 的初始值不会代表你实际 iFrame 的 readyState。因此,除了检查 readyState 值之外,该函数还解决了 about:blank 问题。

            2. DOMContentLoaded 事件不适用于 iFrame。因此,如果 iFrame 尚未加载,它会使用 load 事件来运行回调函数。 load 事件相当于readyState == "complete",用于检查 iFrame 是否已加载。因此,在任何情况下,回调函数都会在 iFrame 完全加载后运行。

            3. iFrame src 可以有重定向,因此加载与原始 src url 不同的页面。此功能也适用于该场景。

            将您想要在 iFrame 完成加载时运行的回调函数和 &lt;iframe&gt; 元素传递给此函数:

            function iframeReady(callback, iframeElement) {
                const iframeWindow = iframeElement.contentWindow;
                if ((iframeElement.src == "about:blank" || (iframeElement.src != "about:blank" && iframeWindow.location.href != "about:blank")) && iframeWindow.document.readyState == "complete") {
                    callback();
                } else {
                    iframeWindow.addEventListener("load", callback);
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-01-18
              • 1970-01-01
              • 1970-01-01
              • 2013-06-21
              • 1970-01-01
              • 2018-07-03
              • 2023-03-08
              • 1970-01-01
              相关资源
              最近更新 更多