javascript - 确定本地 iframe 是否已加载的 chalice

标签 javascript jquery html iframe

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

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

让我再解释一下。

在我的测试中,我确定 onload 事件只会触发一次 - 并且仅当它在 iframe 实际加载之前被绑定(bind)时才会触发。例如:这个页面应该只警告“添加到 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 报告“未初始化”,我可以接受,因为我知道我可以附加一个 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 事件处理程序,然后将 iframe 从 dom 分离,然后将其插入到 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 加载(不引人注目)?

感谢您的宝贵时间。

最佳答案

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

它可以像这样使用:

$("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>

该示例会等到窗口加载后动态添加一个 iframe 到 DOM,然后提醒其文档的 readyState - 在 chrome 中错误地显示“完成”。应在之后调用 iready 函数,并尝试输出文档的 readyState 证明跨域异常 - 同样,这尚未经过彻底测试,但可以满足我的需要。

关于javascript - 确定本地 iframe 是否已加载的 chalice ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35227469/

相关文章:

c# - 新鲜的 MVC 3 项目给我奇怪的不引人注目的验证脚本错误

javascript - jquery 获取自动编号的输入值并从中创建选择框

javascript - 单击图标两次不关闭下拉菜单

html - 在网页中保持垂直菜单不变

javascript - 正则表达式验证不允许 home、end、箭头键工作

javascript - 如何在 font.css 中添加字体以便在 CKEDITOR 中使用字体

javascript - 附加元素的输入更改时事件不会触发

javascript - 循环遍历 slider

html - 如何在图标框下方显示文字?

javascript - 什么时候清除整个 Canvas 更快?