jQuery. zaten dinamik olarak eklenen bir iframe içinde


184

Birisi bir resmi tıkladığında dinamik olarak bir iframe görüntülemek için jQuery thickbox kullanıyoruz . Bu iframe'de, birden fazla resim görüntülemek için galleria javascript kütüphanesi kullanıyoruz .

Sorun $(document).ready, iframe'de çok yakında işlenecek gibi görünüyor ve iframe içeriği henüz yüklenmemiş gibi görünüyor, bu nedenle galleria kodu DOM öğelerine düzgün bir şekilde uygulanmadı. $(document).readyiframe'in hazır olup olmadığına karar vermek için iframe üst öğesi hazır durumunu kullanıyor gibi görünüyor.

Belge tarafından çağrılan işlevi ayrı bir işlevde çıkarırsak ve 100 ms zaman aşımından sonra çağırırsak. Çalışıyor, ancak yavaş bir bilgisayarla üretim şansını kullanamayız.

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

Sorum: dinamik iframe hazır olduğunda ve sadece bir üst öğe değilken kodumuzu yürütebilmemiz için hangi jQuery olayını bağlamalıyız?


1
Ve galleria'nın bir iframe yerine doğrudan yüklediğinizde çalıştığını onaylıyorsunuz, değil mi?
Jason Kealey

Evet, galleria doğrudan normal bir sayfada kullandığımızda mükemmel çalışıyor.
EtienneT

Yanıtlar:


291

Benzer bir soruyu yanıtladım ( IFRAME yüklemesi bittiğinde Javascript geri aramasına bakın ? ). Aşağıdaki kodla iframe yükleme olayı üzerinde denetim elde edebilirsiniz:

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

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

Iframe'lerle uğraşırken belgeye hazır olay yerine load olayını kullanmak için yeterince iyi buldum.


17
Attr ('src') çağrılmadan önce load olayını ayarlamamanız gerekir mi?
Shay Erlichmen

15
Hayır, önemli değil. Load olayı, bir sonraki olay döngüsüne kadar minimum tetiklenmez.
Barum Rho

29
yükleme olayı, indirme için kullanılan iframe'ler için çalışmaz. gibi <iframe src = "my.pdf" />
Mike Starov

5
Yük sorunu, tüm görüntüler ve alt çerçeveler yüklendiğinde tetiklenmesidir. Bir jQuery benzeri hazır etkinlik daha yararlı olacaktır.
Tom


30

JQuery 1.3.2 kullanarak aşağıdakiler benim için çalıştı:

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

REVİZYON:! Aslında yukarıdaki kod bazen Firefox'ta çalışıyor, Opera'da hiç çalışmıyor gibi görünüyor.

Bunun yerine amacım için bir seçim çözümü uyguladım. Basitleştirilmiş olarak şöyle görünür:

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

Bu, çağrılan iframe sayfalarında kod gerektirmez. Tüm kod, ana çerçevede / pencerede bulunur ve yürütülür.


SetTimeout () öğesinde atıfta bulunulan movePreview işlevi nedir?
cam8001

@ cam8001: Bir yazım hatasıydı - şimdi düzeltildi.
Már Örlygsson

Ben de bir yoklama çözümü kullanarak sona erdi. Diğer çözümlerin sadece kısmen başarılı olduğu görülüyordu. Ancak, benim için, başarıya ulaşmadan önce, sadece iframe'in içeriği için değil, bir javascript fonksiyonunun varlığını kontrol etmem gerekiyordu. Örneğin. (typeof iframe.contentWindow.myfunc == 'function')
Julian

2
Bu çözüm, her çağrı için bellek alan özyinelemelidir. İframe asla yüklenmezse, bellek bitene kadar sonsuza dek daha derin ve daha derin çağırır. Bunun setIntervalyerine oylama için tavsiye ederim .
eremzeit

15

IFrames'te genellikle bu sorunu bloğun sonuna küçük bir komut dosyası koyarak çözerim:

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

Bu iş çoğu zaman benim için. Bazen en basit ve en naif çözüm en uygunudur.


4
+1 Bu çözüm benim için harika çalışıyor! Bir büyük ek, parentjQuery'nin bir kopyasını almak parent.$(document).ready(function(){ parent.IFrameLoaded( ); });ve iframe'i başlatmak için kullanabilmenizdir .
David Murdoch

9

DrJokepu ve David Murdoch fikrinin ardından daha eksiksiz bir versiyon uyguladım. Bu gerektirir senin kontrolünde olması veli ve iframe ve iframe hem jQuery.

iframe kodu:

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

ebeveyn test kodu:

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

herhangi bir nedenle üst öğede $ (iframe) .ready (function ...) kullanmak benim için işe yaramaz. İframe dom hazır olmadan önce geri arama işlevi yürütülüyordu. Bu yöntemi kullanmak harika çalıştı!
w--

4

Sorunun çözümünü buldum.

Bir iframe açan bir kalın kutu bağlantısına tıkladığınızda, TB_iframeContent kimliğine sahip bir iframe ekler.

$(document).readyIframe kodundaki olaya güvenmek yerine, sadece üst belgede iframe'in load olayına bağlanmak zorundayım:

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

Bu kod iframe'dedir, ancak üst belgedeki bir denetim olayına bağlanır. FireFox ve IE'de çalışır.


9
Çözüm mü buldunuz? Görünüşe göre Pier zaten göndermişti. Kendi başınıza bulsanız da bulmasanız da, görgü kuralları yanıtını kabul etmek ve böylece size cevap vermek için harcadığı zamanı ödüllendirmek olacaktır.
Sky Sanders

Pier'in çözümü ile bu (ve benim kodumda eksik olan) arasındaki top.documentfark , iframe'in içindeki kodun iframe'in ne zaman yüklendiğini söyleyebilmesini sağlayan bağlamdır . (Her ne kadar loadbu yanıttan beri kullanımdan kaldırılmış olsa da ve bunun yerine değiştirilmesi gerekir on("load").)
Teepeemm

2

Temelde diğerlerinin zaten ne yayınladı ama IMHO biraz daha temiz:

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

1

Bunu dene,

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

Daha sonra tek yapmanız gereken testframe_loaded () JavaScript işlevini oluşturmaktır.


1
Yük sorunu, tüm görüntüler ve alt çerçeveler yüklendiğinde tetiklenmesidir. Bir jQuery benzeri hazır etkinlik daha yararlı olacaktır.
Tom

1

PDF'yi jQuery ajax ile tarayıcı önbelleğine yüklüyorum. Sonra zaten tarayıcı önbelleğindeki verilerle gömülü öğe oluşturuyorum. Sanırım iframe ile de çalışacak.


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 başlıklarınızı da doğru şekilde ayarlamanız gerekir.


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

1
Önbelleğin PDF boyutundan daha küçük olabileceği mobil tarayıcılarda iyi çalışmadığını unutmayın.
Pavel Savara

1

Müşterimizle karşılaştığım sorun buydu. Iframe hazırlığı için işe yarayan küçük bir jquery eklentisi oluşturdum. İframe'in aslında "hazır" olduğundan emin olmak için iframe belgesinin readyState dokümanını iç çerçeve url'si ile birlikte iframe kaynağıyla birlikte kontrol etmek için yoklama kullanır.

"Onload" ile ilgili sorun, DOM'a eklenen gerçek iframe'e erişmeniz gerektiğidir, eğer yoksa, önbelleğe alınırsa iframe'in yüklenemeyeceği iframe yüklemesini yakalamaya çalışmanız gerekir. Ne gerek her zaman çağrılabilir bir komut dosyası ve iframe "hazır" olup olmadığını belirlemek oldu.

İşte soru:

Yerel iframe'in yüklü olup olmadığını belirlemek için kutsal kâse

ve işte sonunda bulduğum jsfiddle.

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

Yukarıdaki jsfiddle'da, dom'a bir iframe eklemek için onload'u bekliyorum, sonra iframe'in iç belgesinin hazır durumunu kontrol ediyorum - wikipedia'ya işaret ettiği için alanlar arası olmalı - ancak Chrome "tamamlandı" gibi görünüyor. Daha sonra, iframe aslında hazır olduğunda eklentinin akıllı yöntemi çağrılır. Geri arama, iç belgenin hazır durumunu tekrar kontrol etmeye çalışır - bu sefer bir alanlar arası istek (bu doğru) bildirir - yine de ihtiyacım olan şey için çalışıyor ve umarım başkalarına yardımcı olur.

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

Benim için iyi çalıştı
Hassan Tareq

0

Bu yanıttan gelen bu işlev, $.readyiframe'ler için açıkça başarısız olduğu için bunu işlemenin en iyi yoludur . İşte karar bunu desteklememe .

loadİframe zaten yüklenip yüklenmediğini olay da patlamaz. Bunun 2020'de bir sorun olarak kalması çok sinir bozucu!

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

}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.