确定本地iframe是否已加载的圣杯 [英] Holy grail for determining whether or not local iframe has loaded

查看:86
本文介绍了确定本地iframe是否已加载的圣杯的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这里有一些背景知识:我一直在研究一个不显眼的脚本来试图确定dom中的本地iframe是否已经加载,这是因为我们的一个客户在其网站上内置框架及其中的许多内容在Lightbox中打开 - 可以随时动态地将内联框架添加到dom中。我可以附加到灯箱的公开事件,但它是否能在加载之前抓住iframe的命中或漏掉。



让我解释一下在我的测试中,我确定onload事件只会触发一次 - 只有在iframe实际加载之前绑定它。例如:这个页面应该只警告添加到iframe标签,并且之后附加的侦听器不会触发 - 对我来说这是有道理的。 (例如,我使用iframe onload属性)。

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

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

我的下一个方法是检查iframe的文档就绪状态,该状态似乎在几乎所有的我的测试,除了铬报告完整 - 我期待访问被拒绝的跨域请求。我对跨域错误很满意,因为我可以不理会iframe,因为我只对本地iframe感兴趣 - firefox报告unintialized,我可以,因为我知道我可以附加一个onload事件。



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

 < iframe id =testsrc =https://en.wikipedia.org /维基/ HTML_element#帧>< / iframe中> 
< script>
alert($(#test)。contents()[0] .readyState);
< / script>

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



$ b

 code>< iframe id =testsrc =https://en.wikipedia.org/wiki/HTML_element#Frames>< / iframe> 
< script>
setTimeout(function(){
try {
alert($(#test)。contents()[0] .readyState);
} catch(ignore){
alert(跨域请求);
}
},100);
< / script>

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



< a href =https://jsfiddle.net/g1bkd3u1/5/ =nofollow> https://jsfiddle.net/g1bkd3u1/5/

 < iframe id =testsrc =https://en.wikipedia.org/wiki/HTML_element#Frames>< / iframe> 
< script>
setTimeout(function(){
var placeholder = $(< span>);
$(#test)。load(function(){
alert ();
})。after(placeholder).detach()。insertAfter(placeholder);
placeholder.detach();
},3000 );
< / script>

虽然这个方法有效,但它让我想知道是否有更好的更优雅的技术来检查iframe的加载(不显眼) ?



感谢您的时间。 遇到了一个错误,那就是我删除并重新插入iframe的时候,在一个网站上打破了wysiwyg的编辑器。所以我创建了一个小的jQuery插件来检查iframe是否准备就绪。它不是生产准备好的,我没有做太多的测试,但它应该提供一个更好的替代方法来分离和重新连接一个iframe - 如果需要的话,它会使用轮询,但是应该在iframe准备就绪时删除setInterval。 / p>

它可以用于:

  $(iframe) .iready(function(){...}); 

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

 < script> 
(函数($,document,undefined){
$ .fn [iready] =函数(回调){
var ifr = this.filter(iframe),
arg = arguments,
src = this,
clc = null,// collection
lng = 50,//等待时间间隔
ivl = -1 ,//间隔id
chk =函数(ifr){
尝试{
var cnt = ifr.contents(),
doc = cnt [0],
src = ifr.attr(src),
url = doc.URL;
switch(doc.readyState){
casecomplete:
if(!src | | src ===about:blank){
//我们不关心空iframe
ifr.data(ready,true);
} else if (!url || url ===about:blank){
//空文件仍然需要加载
ifr.data(read y,未定义);
} else {
//不是空的iframe而不是空的src
//应该加载
ifr.data(ready,true);
}

break;
caseinteractive:
ifr.data(ready,true);
休息;
caseloading:
默认值:
// //正在加载
break;
}
} catch(忽略){
//据我们担心iframe已准备就绪
//因为我们无法跨域访问它
ifr.data(ready,true);
}

return ifr.data(ready)===true;
};
$ b $ if(ifr.length){
ifr.each(function(){
if(!$(this).data(ready)){
//添加到集合
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);
}
返回此;
};
}(jQuery,document));
< / script>

这个例子一直等到窗口已经加载动态添加一个iframe到DOM,它会发出警报文档的readyState - 在铬显示完成,不正确。 iready函数应该在调用之后调用,并且试图输出文档的readyState证明了跨域的异常 - 这还没有经过彻底测试,但适用于我所需要的。


Firstly, I see this question asked a few times but no answers seem satisfactory. What I am looking for is to be able to call a script at anytime and determine whether or not an iframe has loaded - and to not limit the script to require being added to the iframe tag itself in an onload property.

Here's some background: I have been working on an unobtrusive script to try and determine whether or not local iframes in the dom have loaded, this is because one of our clients includes forms on their website in iframes and many of them open in lightboxes - which dynamically add the iframes into the dom at any time. I can attach to the open event of the lightbox, but its hit or miss as to whether I can "catch" the iframe before it has loaded.

Let me explain a little more.

In my testing I've determined that the onload event will only fire once - and only if it is bound before the iframe actually loads. For example: This page should only alert "added to iframe tag" and the listener that is attached afterward does not fire - to me that makes sense. (I'm using the iframe onload property for simple example).

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>

My next approach was to check the document ready state of the iframe which seems to work in almost all of my testing except chrome which reports "complete" - I was expecting "Access Denied" for cross domain request. I'm ok with a cross domain error because I can disregard the iframe since I am only interested in local iframes - firefox reports "unintialized" which I'm ok with because I know I can then attach an onload event.

Please open in 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>

I've found that if I wait just 100ms - then the iframe seems to report as expected (a cross domain security exception - which is what I want - but I don't want to have to wait an arbitrary length).

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>

My current workaround / solution is to add the onload event handler, then detach the iframe from the dom, then insert it back into the dom in the same place - now the onload event will trigger. Here's an example that waits 3 seconds (hoping thats enough time for the iframe to load) to show that detaching and re-attaching causes the iframe onload event to fire.

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>

While this works it leaves me wondering if there are better more elegant techniques for checking iframe load (unobtrusively)?

Thank you for your time.

解决方案

Today I actually ran into a bug where my removing and re-inserting of iframes was breaking a wysiwyg editor on a website. So I created the start of a small jQuery plugin to check for iframe readiness. It is not production ready and I have not tested it much, but it should provide a nicer alternative to detaching and re-attaching an iframe - it does use polling if it needs to, but should remove the setInterval when the iframe is ready.

It can be used like:

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

The example waits until the window has loaded to dynamically add an iframe to the DOM, it then alerts its document's readyState - which in chrome displays "complete", incorrectly. The iready function should be called after and an attempt to output the document's readyState proves cross domain exception - again this has not been thoroughly tested but works for what I need.

这篇关于确定本地iframe是否已加载的圣杯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆