jQuery .ready in a dynamically inserted iframe

后端 未结 10 1960
闹比i
闹比i 2020-11-22 07:11

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 multip

相关标签:
10条回答
  • 2020-11-22 07:44

    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.

    0 讨论(0)
  • 2020-11-22 07:44

    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();
    }
    

    }

    0 讨论(0)
  • 2020-11-22 07:49

    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.

    0 讨论(0)
  • 2020-11-22 07:49

    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>
    
    0 讨论(0)
提交回复
热议问题