动态插入 iframe 中的 jQuery .ready

发布于 2024-07-06 22:56:53 字数 681 浏览 15 评论 0原文

我们使用 jQuery thickbox 在有人点击图片时动态显示 iframe。 在此 iframe 中,我们使用 galleria 一个 JavaScript 库来显示多张图片。

问题似乎是 iframe 中的 $(document).ready 似乎被触发得太早,并且 iframe 内容甚至还没有加载,因此 Galleria 代码没有正确应用于 DOM 元素。 $(document).ready 似乎使用 iframe 父级就绪状态来决定 iframe 是否就绪。

如果我们将 document read 调用的函数提取到一个单独的函数中,并在 100 毫秒超时后调用它。 它可以工作,但我们不能在使用速度慢的计算机的情况下冒险。

$(document).ready(function() { setTimeout(ApplyGalleria, 100); });

我的问题:当动态 iframe 准备就绪而不仅仅是它的父级时,我们应该绑定哪个 jQuery 事件才能执行我们的代码?

We are using jQuery thickbox to dynamically display an iframe when someone clicks on a picture. In this iframe, we are using galleria a javascript library to display multiple pictures.

The problem seems to be that $(document).ready in the iframe seems to be fired too soon and the iframe content isn't even loaded yet, so galleria code is not applied properly on the DOM elements. $(document).ready seems to use the iframe parent ready state to decide if the iframe is ready.

If we extract the function called by document ready in a separate function and call it after a timeout of 100 ms. It works, but we can't take the chance in production with a slow computer.

$(document).ready(function() { setTimeout(ApplyGalleria, 100); });

My question: which jQuery event should we bind to to be able to execute our code when the dynamic iframe is ready and not just it's a parent?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

信仰 2024-07-13 22:56:53

我回答了类似的问题(请参阅IFRAME完成加载时的Javascript回调?)。
您可以使用以下代码获得对 iframe 加载事件的控制:

function callIframe(url, callback) {
    $(document.body).append('<IFRAME id="myId" ...>');
    $('iframe#myId').attr('src', url);

    $('iframe#myId').load(function() {
        callback(this);
    });
}

在处理 iframe 时,我发现使用加载事件而不是文档就绪事件就足够了。

I answered a similar question (see Javascript callback when IFRAME is finished loading?).
You can obtain control over the iframe load event with the following code:

function callIframe(url, callback) {
    $(document.body).append('<IFRAME id="myId" ...>');
    $('iframe#myId').attr('src', url);

    $('iframe#myId').load(function() {
        callback(this);
    });
}

In dealing with iframes I found good enough to use load event instead of document ready event.

银河中√捞星星 2024-07-13 22:56:53

使用 jQuery 1.3.2 以下内容对我有用:

$('iframe').ready(function() {
  $('body', $('iframe').contents()).html('Hello World!');
});

修订:!
实际上,上面的代码有时看起来像在 Firefox 中工作,但从来不像在 Opera 中工作。

相反,我出于我的目的实施了一个轮询解决方案。 简化后,它看起来像这样:

$(function() {
  function manipIframe() {
    el = $('body', $('iframe').contents());
    if (el.length != 1) {
      setTimeout(manipIframe, 100);
      return;
    }
    el.html('Hello World!');
  }
  manipIframe();
});

这不需要调用的 iframe 页面中的代码。 所有代码都驻留在父框架/窗口中并从父窗口执行。

Using jQuery 1.3.2 the following worked for me:

$('iframe').ready(function() {
  $('body', $('iframe').contents()).html('Hello World!');
});

REVISION:!
Actually the above code sometimes looks like it works in Firefox, never looks like it works in Opera.

Instead I implemented a polling solution for my purposes. Simplified down it looks like this:

$(function() {
  function manipIframe() {
    el = $('body', $('iframe').contents());
    if (el.length != 1) {
      setTimeout(manipIframe, 100);
      return;
    }
    el.html('Hello World!');
  }
  manipIframe();
});

This doesn't require code in the called iframe pages. All code resides and executes from the parent frame/window.

始于初秋 2024-07-13 22:56:53

在 IFrame 中,我通常通过在块的最后放置一个小脚本来解决这个问题:

<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
   fireOnReadyEvent();
   parent.IFrameLoaded();
//]]>
</script>
</body>

这对我来说大部分时间都有效。 有时,最简单、最幼稚的解决方案是最合适的。

In IFrames I usually solve this problem by putting a small script to the very end of the block:

<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
   fireOnReadyEvent();
   parent.IFrameLoaded();
//]]>
</script>
</body>

This work most of the time for me. Sometimes the simplest and most naive solution is the most appropriate.

゛时过境迁 2024-07-13 22:56:53

遵循 DrJokepu 和 David Murdoch 的想法,我实现了一个更完整的版本。
需要父级和 iframe 上的 jQuery,并且 iframe 处于您的控制之下。

iframe 代码:

var iframe = window.frameElement;

if (iframe){
    iframe.contentDocument = document;//normalization: some browsers don't set the contentDocument, only the contentWindow

    var parent = window.parent;
    $(parent.document).ready(function(){//wait for parent to make sure it has jQuery ready
        var parent$ = parent.jQuery;

        parent$(iframe).trigger("iframeloading");

        $(function(){
            parent$(iframe).trigger("iframeready");
        });

        $(window).load(function(){//kind of unnecessary, but here for completion
            parent$(iframe).trigger("iframeloaded");
        });

        $(window).unload(function(e){//not possible to prevent default
            parent$(iframe).trigger("iframeunloaded");
        });

        $(window).on("beforeunload",function(){
            parent$(iframe).trigger("iframebeforeunload");
        });
    });
}

父测试代码:

$(function(){
    $("iframe").on("iframeloading iframeready iframeloaded iframebeforeunload iframeunloaded", function(e){
        console.log(e.type);
    });
});

Following DrJokepu's and David Murdoch idea I implemented a more complete version.
It requires jQuery on both the parent and iframe and the iframe to be in your control.

iframe code:

var iframe = window.frameElement;

if (iframe){
    iframe.contentDocument = document;//normalization: some browsers don't set the contentDocument, only the contentWindow

    var parent = window.parent;
    $(parent.document).ready(function(){//wait for parent to make sure it has jQuery ready
        var parent$ = parent.jQuery;

        parent$(iframe).trigger("iframeloading");

        $(function(){
            parent$(iframe).trigger("iframeready");
        });

        $(window).load(function(){//kind of unnecessary, but here for completion
            parent$(iframe).trigger("iframeloaded");
        });

        $(window).unload(function(e){//not possible to prevent default
            parent$(iframe).trigger("iframeunloaded");
        });

        $(window).on("beforeunload",function(){
            parent$(iframe).trigger("iframebeforeunload");
        });
    });
}

parent test code:

$(function(){
    $("iframe").on("iframeloading iframeready iframeloaded iframebeforeunload iframeunloaded", function(e){
        console.log(e.type);
    });
});
淤浪 2024-07-13 22:56:53

找到了问题的解决方案。

当您单击打开 iframe 的厚盒链接时,它会插入一个 id 为 TB_iframeContent 的 iframe。

我不必依赖 iframe 代码中的 $(document).ready 事件,而只需绑定到父文档中 iframe 的 load 事件:

$('#TB_iframeContent', top.document).load(ApplyGalleria);

此代码位于 iframe 中,但绑定到父文档中的控件的事件。 它适用于 FireFox 和 IE。

Found the solution to the problem.

When you click on a thickbox link that open a iframe, it insert an iframe with an id of TB_iframeContent.

Instead of relying on the $(document).ready event in the iframe code, I just have to bind to the load event of the iframe in the parent document:

$('#TB_iframeContent', top.document).load(ApplyGalleria);

This code is in the iframe but binds to an event of a control in the parent document. It works in FireFox and IE.

肤浅与狂妄 2024-07-13 22:56:53

这个答案中的这个函数是处理这个问题的最佳方法,因为 $.ready 显式失败iframe。 这里决定不支持这一点。

如果 iframe 已加载,则 load 事件也不会触发。 非常令人沮丧的是,这在 2020 年仍然是一个问题!

function onIframeReady($i, successFn, errorFn) {
    try {
        const iCon = $i.first()[0].contentWindow,
        bl = "about:blank",
        compl = "complete";
        const callCallback = () => {
            try {
                const $con = $i.contents();
             if($con.length === 0) { // https://git.io/vV8yU
                throw new Error("iframe inaccessible");
             }


   successFn($con);
     } catch(e) { // accessing contents failed
        errorFn();
     }
  };
  const observeOnload = () => {
    $i.on("load.jqueryMark", () => {
        try {
            const src = $i.attr("src").trim(),
            href = iCon.location.href;
            if(href !== bl || src === bl || src === "") {
                $i.off("load.jqueryMark");
                callCallback();
            }
        } catch(e) {
            errorFn();
        }
    });
  };
  if(iCon.document.readyState === compl) {
    const src = $i.attr("src").trim(),
    href = iCon.location.href;
    if(href === bl && src !== bl && src !== "") {
        observeOnload();
    } else {
        callCallback();
    }
  } else {
    observeOnload();
  }
} catch(e) {
    errorFn();
}

}

This function from this answer is the best way to handle this as $.ready explicitly fails for iframes. Here's the decision not to support this.

The load event also doesn't fire if the iframe has already loaded. Very frustrating that this remains a problem in 2020!

function onIframeReady($i, successFn, errorFn) {
    try {
        const iCon = $i.first()[0].contentWindow,
        bl = "about:blank",
        compl = "complete";
        const callCallback = () => {
            try {
                const $con = $i.contents();
             if($con.length === 0) { // https://git.io/vV8yU
                throw new Error("iframe inaccessible");
             }


   successFn($con);
     } catch(e) { // accessing contents failed
        errorFn();
     }
  };
  const observeOnload = () => {
    $i.on("load.jqueryMark", () => {
        try {
            const src = $i.attr("src").trim(),
            href = iCon.location.href;
            if(href !== bl || src === bl || src === "") {
                $i.off("load.jqueryMark");
                callCallback();
            }
        } catch(e) {
            errorFn();
        }
    });
  };
  if(iCon.document.readyState === compl) {
    const src = $i.attr("src").trim(),
    href = iCon.location.href;
    if(href === bl && src !== bl && src !== "") {
        observeOnload();
    } else {
        callCallback();
    }
  } else {
    observeOnload();
  }
} catch(e) {
    errorFn();
}

}

倾听心声的旋律 2024-07-13 22:56:53

基本上其他人已经发布了但恕我直言更干净一点:

$('<iframe/>', {
    src: 'https://example.com/',
    load: function() {
        alert("loaded")
    }
}).appendTo('body');

Basically what others have already posted but IMHO a bit cleaner:

$('<iframe/>', {
    src: 'https://example.com/',
    load: function() {
        alert("loaded")
    }
}).appendTo('body');
北音执念 2024-07-13 22:56:53

尝试一下,

<iframe id="testframe" src="about:blank" onload="if (testframe.location.href != 'about:blank') testframe_loaded()"></iframe>

您所需要做的就是创建 JavaScript 函数 testframe_loaded()。

Try this,

<iframe id="testframe" src="about:blank" onload="if (testframe.location.href != 'about:blank') testframe_loaded()"></iframe>

All you need to do then is create the JavaScript function testframe_loaded().

刘备忘录 2024-07-13 22:56:53

我正在使用 jQuery ajax 将 PDF 加载到浏览器缓存中。 然后,我使用浏览器缓存中已有的数据创建嵌入元素。 我想它也可以与 iframe 一起使用。


var url = "http://example.com/my.pdf";
// show spinner
$.mobile.showPageLoadingMsg('b', note, false);
$.ajax({
    url: url,
    cache: true,
    mimeType: 'application/pdf',
    success: function () {
        // display cached data
        $(scroller).append('<embed type="application/pdf" src="' + url + '" />');
        // hide spinner
        $.mobile.hidePageLoadingMsg();
    }
});

您还必须正确设置 http 标头。


HttpContext.Response.Expires = 1;
HttpContext.Response.Cache.SetNoServerCaching();
HttpContext.Response.Cache.SetAllowResponseInBrowserHistory(false);
HttpContext.Response.CacheControl = "Private";

I'm loading the PDF with jQuery ajax into browser cache. Then I create embedded element with data already in browser cache. I guess it will work with iframe too.


var url = "http://example.com/my.pdf";
// show spinner
$.mobile.showPageLoadingMsg('b', note, false);
$.ajax({
    url: url,
    cache: true,
    mimeType: 'application/pdf',
    success: function () {
        // display cached data
        $(scroller).append('<embed type="application/pdf" src="' + url + '" />');
        // hide spinner
        $.mobile.hidePageLoadingMsg();
    }
});

You have to set your http headers correctly as well.


HttpContext.Response.Expires = 1;
HttpContext.Response.Cache.SetNoServerCaching();
HttpContext.Response.Cache.SetAllowResponseInBrowserHistory(false);
HttpContext.Response.CacheControl = "Private";
别挽留 2024-07-13 22:56:53

这正是我与客户遇到的问题。 我创建了一个小 jquery 插件,似乎可以为 iframe 做好准备。 它使用轮询来检查 iframe 文档的就绪状态,并结合内部文档 url 和 iframe 源,以确保 iframe 实际上已“就绪”。

“onload”的问题是你需要访问添加到 DOM 的实际 iframe,如果你不这样做,那么你需要尝试捕获 iframe 加载,如果它被缓存,那么你可能不会。 我需要的是一个可以随时调用的脚本,并确定 iframe 是否“准备好”。

这是问题:

确定是否或的圣杯未加载本地 iframe

这是我最终想出的 jsfiddle。

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

在上面的jsfiddle中,我正在等待onload 将 iframe 附加到 dom,然后检查 iframe 的内部文档的就绪状态 - 这应该是跨域的,因为它指向维基百科 - 但 Chrome 似乎报告“完成”。 当 iframe 实际上准备好时,插件的 iready 方法就会被调用。 回调尝试再次检查内部文档的就绪状态 - 这次报告跨域请求(这是正确的) - 无论如何,它似乎可以满足我的需要,并希望它可以帮助其他人。

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

This was the exact issue I ran into with our client. I created a little jquery plugin that seems to work for iframe readiness. It uses polling to check the iframe document readyState combined with the inner document url combined with the iframe source to make sure the iframe is in fact "ready".

The issue with "onload" is that you need access to the actual iframe being added to the DOM, if you don't then you need to try to catch the iframe loading which if it is cached then you may not. What I needed was a script that could be called anytime, and determine whether or not the iframe was "ready" or not.

Here's the question:

Holy grail for determining whether or not local iframe has loaded

and here's the jsfiddle I eventually came up with.

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

In the jsfiddle above, I am waiting for onload to append an iframe to the dom, then checking iframe's inner document's ready state - which should be cross domain because it's pointed to wikipedia - but Chrome seems to report "complete". The plug-in's iready method then gets called when the iframe is in fact ready. The callback tries to check the inner document's ready state again - this time reporting a cross domain request (which is correct) - anyway it seems to work for what I need and hope it helps others.

<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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文