JQuery. уже в динамически вставленном iframe

Мы используем jQuery thickbox для динамического отображения iframe, когда кто-то нажимает на изображение. В этом iframe мы используем galleria javascript-библиотеку для отображения нескольких изображений.

Проблема заключается в том, что $(document).ready в iframe, похоже, срабатывает слишком рано, а содержимое iframe еще не загружено, поэтому код шкалы не применяется должным образом к элементам DOM. $(document).ready, похоже, использует состояние готовности родителя iframe, чтобы решить, готов ли iframe.

Если мы выберем функцию, вызванную документом, готовой в отдельной функции и вызовите ее после таймаута 100 мкс. Он работает, но мы не можем воспользоваться этой возможностью на медленном компьютере.

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

Мой вопрос: какое событие jQuery мы должны связывать, чтобы иметь возможность выполнять наш код, когда динамический iframe готов, а не только родительский?

Ответ 1

Я ответил на аналогичный вопрос (см. обратный вызов Javascript, когда IFRAME закончил загрузку?). Вы можете получить контроль над событием загрузки iframe с помощью следующего кода:

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

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

В обращении с iframes я нашел достаточно хорошим, чтобы использовать событие загрузки вместо события готовности документа.

Ответ 2

Использование 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. Весь код сохраняется и выполняется из родительского фрейма/окна.

Ответ 3

В IFrames я обычно решаю эту проблему, помещая небольшой script в самый конец блока:

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

Эта работа большую часть времени для меня. Иногда наиболее подходящим является самое простое и наивное решение.

Ответ 4

Следуя идее д-ра Джокепу и Дэвида Мердока, я реализовал более полную версию. Для этого требуется jQuery как для родительского, так и для iframe, а 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);
    });
});

Ответ 5

Найден решение проблемы.

Когда вы нажимаете ссылку на толстую ячейку, открывающую iframe, она вставляет iframe с идентификатором TB_iframeContent.

Вместо того, чтобы полагаться на событие $(document).ready в коде iframe, мне просто нужно привязать к событию загрузки iframe в родительском документе:

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

Этот код находится в iframe, но привязывается к событию элемента управления в родительском документе. Он работает в FireFox и IE.

Ответ 6

Попробуйте это,

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

Все, что вам нужно сделать, это создать функцию JavaScript testframe_loaded().

Ответ 7

Я загружаю PDF с помощью jQuery ajax в кеш браузера. Затем я создаю внедренный элемент с данными, уже находящимися в кеше браузера. Я думаю, он будет работать и с 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";

Ответ 8

В основном то, что другие уже опубликовали, но IMHO немного чище:

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

Ответ 9

Это была проблема, с которой я столкнулся с нашим клиентом. Я создал небольшой плагин jquery, который, похоже, работает для готовности iframe. Он использует опрос для проверки документа iframe readyState в сочетании с внутренним URL-адресом документа в сочетании с источником iframe, чтобы убедиться, что iframe фактически "готов".

Проблема с "onload" заключается в том, что вам нужен доступ к фактическому iframe, добавляемому в DOM, если вы этого не сделаете, вам нужно попытаться поймать загрузку iframe, которая, если она кэширована, тогда вы не можете. Мне нужен был script, который можно было бы вызвать в любое время, и определить, был ли iframe "готов" или нет.

Здесь вопрос:

Святой грааль для определения того, загружен ли локальный iframe

и здесь jsfiddle я в конце концов придумал.

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

В jsfiddle выше, я жду, когда onload добавит iframe в dom, а затем проверит состояние готовности внутреннего документа iframe - что должно быть перекрестным доменом, поскольку оно указывает на википедию, но Chrome, похоже, сообщает "complete". Затем метод plug-in 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>