用于确定本地iframe是否已加载的圣杯

时间:2016-02-05 15:14:46

标签: javascript jquery html iframe

首先,我看到这个问题被问过几次,但没有答案似乎令人满意。我正在寻找的是能够随时调用脚本并确定iframe是否已加载 - 并且不限制脚本要求在onload属性中添加到iframe标记本身。

这里有一些背景知识:我一直在研究一个不显眼的脚本,试图确定dom中的本地iframe是否已加载,这是因为我们的一个客户在其网站上的iframe中包含表单,其中许多都打开了灯箱 - 随时动态地将iframe添加到dom中。我可以附加到灯箱的开放事件,但它是否可以在加载之前“捕获”iframe。

让我再解释一下。

在我的测试中,我确定onload事件只会触发一次 - 并且只有在iframe实际加载之前绑定它。例如:此页面应仅警告“添加到iframe标记”,并且之后附加的侦听器不会触发 - 对我来说是有意义的。 (我使用iframe onload属性作为简单示例)。

https://jsfiddle.net/g1bkd3u1/2/

<script>
    function loaded () {
        alert ("added to iframe tag");
        $("#test").load(function(){
            alert("added after load finished");
        });
    };
</script>
<iframe onload="loaded()" id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>

我的下一个方法是检查iframe的文档就绪状态,这似乎在我的几乎所有测试中都有效,除了报告“完整”的chrome之外 - 我希望跨域请求“拒绝访问”。我没有跨域错误,因为我可以忽略iframe,因为我只对本地iframe感兴趣 - firefox报告“unintialized”我很好,因为我知道我可以附加一个onload事件。

请在Chrome中打开: https://jsfiddle.net/g1bkd3u1/

<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
    alert($("#test").contents()[0].readyState);
</script>

我发现如果我只等待100毫秒 - 那么iframe似乎按预期报告(跨域安全异常 - 这就是我想要的 - 但我不想等待任意长度)。

https://jsfiddle.net/g1bkd3u1/4/

<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
    setTimeout(function () { 
        try {
            alert($("#test").contents()[0].readyState);
        } catch (ignore) {
            alert("cross domain request");
        }
    }, 100);
</script>

我当前的解决方法/解决方案是添加onload事件处理程序,然后从dom中分离iframe,然后将其插回到dom中的相同位置 - 现在onload事件将触发。这是一个等待3秒的例子(希望有足够的时间加载iframe)来显示分离和重新连接会导致iframe onload事件被触发。

https://jsfiddle.net/g1bkd3u1/5/

<iframe id="test" src="https://en.wikipedia.org/wiki/HTML_element#Frames"></iframe>
<script>
    setTimeout(function(){
        var placeholder = $("<span>");
        $("#test").load(function(){
            alert("I know the frame has loaded now");
        }).after(placeholder).detach().insertAfter(placeholder);
        placeholder.detach();
    }, 3000);
</script>

虽然这有效但是让我想知道是否有更优雅的技术来检查iframe加载(不引人注目)?

感谢您的时间。

2 个答案:

答案 0 :(得分:2)

今天我遇到了一个错误,我删除并重新插入iframe正在网站上破坏了一个所见即所得的编辑器。所以我创建了一个小jQuery插件的开始,以检查iframe准备情况。它不是生产就绪的,我没有对它进行过多的测试,但是它应该提供一个更好的替代方法来分离和重新附加iframe - 它确实在需要时使用轮询,但是当iframe准备就绪时应该删除setInterval。 / p>

可以像:

一样使用
$("iframe").iready(function() { ... });

https://jsfiddle.net/q0smjkh5/10/

<script>
  (function($, document, undefined) {
    $.fn["iready"] = function(callback) {
      var ifr = this.filter("iframe"),
          arg = arguments,
          src = this,
          clc = null, // collection
          lng = 50,   // length of time to wait between intervals
          ivl = -1,   // interval id
          chk = function(ifr) {
            try {
              var cnt = ifr.contents(),
                  doc = cnt[0],
                  src = ifr.attr("src"),
                  url = doc.URL;
              switch (doc.readyState) {
                case "complete":
                  if (!src || src === "about:blank") {
                    // we don't care about empty iframes
                    ifr.data("ready", "true");
                  } else if (!url || url === "about:blank") {
                    // empty document still needs loaded
                    ifr.data("ready", undefined);
                  } else {
                    // not an empty iframe and not an empty src
                    // should be loaded
                    ifr.data("ready", true);
                  }

                  break;
                case "interactive":
                  ifr.data("ready", "true");
                  break;
                case "loading":
                default:
                  // still loading
                  break;   
              }
            } catch (ignore) {
              // as far as we're concerned the iframe is ready
              // since we won't be able to access it cross domain
              ifr.data("ready", "true");
            }

            return ifr.data("ready") === "true";
          };

      if (ifr.length) {
        ifr.each(function() {
          if (!$(this).data("ready")) {
            // add to collection
            clc = (clc) ? clc.add($(this)) : $(this);
          }
        });
        if (clc) {
          ivl = setInterval(function() {
            var rd = true;
            clc.each(function() {
              if (!$(this).data("ready")) {
                if (!chk($(this))) {
                  rd = false;
                }
              }
            });

            if (rd) {
              clearInterval(ivl);
              clc = null;
              callback.apply(src, arg);
            }
          }, lng);
        } else {
          clc = null;
          callback.apply(src, arg);
        }
      } else {
        clc = null;
        callback.apply(this, arguments);
      }
      return this;
    };
  }(jQuery, document));
</script>

该示例等待窗口加载后动态地向DOM添加iframe,然后警告其文档的readyState - 在chrome中显示&#34;完成&#34;,错误。 iready函数应该在之后被调用,并且尝试输出文档的readyState证明了跨域异常 - 再次对此进行了彻底的测试但是可以满足我的需要。

答案 1 :(得分:0)

我遇到了一个类似的问题,因为我有一个iframe,需要修改它的&#39;文件一旦完成加载。

IF 您知道或可以控制iFrame中已加载文档的内容,那么您只需检查/添加一个可以检查其存在的元素,然后再更新iframe文献。 至少你知道你想要使用的元素被加载到文档中。

在我的情况下,我调用了一个函数,它本身检查了我已知元素的存在,在我需要更新的元素已经被加载之后总是会找到它 - 在没有找到它的情况下,它自称再次通过setTimeout()。

function updateIframeContents() {
    if ($("#theIframe").contents().find('.SaveButton').length > 0) {
        // iframe DOM Manipulation
    } else {
        setTimeout(updateIframeContents, 250);
    }
}

updateIframeContents();