web-dev-qa-db-ja.com

動的に挿入されたiframe内のjQuery。

誰かが絵をクリックしたときに動的にiframeを表示するためにjQuery thickbox を使っています。このiframeでは、 galleria javascriptライブラリを使用して複数の画像を表示しています。

問題は、iframe内の$(document).readyが早く起動され、iframeコンテンツがまだロードされていないため、ガレリアコードがDOM要素に正しく適用されないことです。 $(document).readyは、iframeの準備ができているかどうかを判断するために、iframeの親の準備完了状態を使用するようです。

Documentによって呼び出された関数を別の関数で抽出し、100ミリ秒のタイムアウトの後に呼び出すとします。それはうまくいきますが、私たちは遅いコンピュータで本番環境に入ることはできません。

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

私の質問:動的なiframeの準備が整ったときにコードを実行できるようにするには、どのjQueryイベントをバインドする必要がありますか。

179
EtienneT

私は同様の質問に答えました( 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を扱う上で、私はdocument readyイベントの代わりにloadイベントを使うのに十分に良いことがわかりました。

287
Pier Luigi

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ページのコードを必要としません。すべてのコードは親フレーム/ウィンドウから存在し実行されます。

28

IFrameでは、通常、ブロックの最後に小さなスクリプトを追加することでこの問題を解決します。

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

これは私のためにほとんどの時間働きます。時には最も単純で素朴な解決策が最も適切です。

14
Tamas Czinege

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);
    });
});
9
Ricardo Freitas

問題の解決策を見つけました。

Iframeを開くthickboxリンクをクリックすると、IDがTB_iframeContentのiframeが挿入されます。

Iframeコードの$(document).readyイベントに頼るのではなく、親ドキュメントのiframeのloadイベントにバインドするだけです。

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

このコードはiframe内にありますが、親文書内のコントロールのイベントにバインドします。 FireFoxとIEで動作します。

4
EtienneT

これを試して、

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

あなたがする必要があるのはそれからJavaScript関数testframe_loaded()を作成することだけです。

1
Danny G

基本的に他の人がすでに投稿したものですが、私見は少しきれいになります。

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

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";
1
Pavel Savara

これは私がクライアントと出会ったまさにその問題でした。私はiframe対応のために働くように思われる小さなjqueryプラグインを作成しました。これは、ポーリングを使用してiframe文書のreadyStateと、iframeソースと組み合わされた内部文書のURLを組み合わせて、iframeが実際に "ready"であることを確認します。

"onload"の問題は、DOMに追加されている実際のiframeにアクセスする必要があるということです。そうでなければ、iframeのロードをキャッチしようとする必要があります。私が必要としていたのは、いつでも呼び出せるスクリプトで、iframeが "ready"かどうかを判断することでした。

これが問題です:

ローカルのiframeが読み込まれたかどうかを判断するための聖杯

そして、これが私が結局思いついたjsfiddleです。

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

上のjsfiddleでは、onloadがiframeをdomに追加するのを待っていて、次にiframeの内部文書のready状態を調べています - これはwikipediaを指すのでクロスドメインであるべきです - しかしChromeは "complete"を報告するようです。プラグインのireadyメソッドは、iframeの準備が整ったときに呼び出されます。コールバックは内部ドキュメントの準備完了状態を再度チェックしようとします - 今度はクロスドメインリクエストを報告します(これは正しいです)。

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