jQuery .ready в динамически вставляемом iframe
-
03-07-2019 - |
Вопрос
Мы используем jQuery толстая коробка для динамического отображения iframe, когда кто-то нажимает на картинку.В этом iframe мы используем галерея библиотека JavaScript для отображения нескольких изображений.
Проблема, по-видимому, заключается в том, что $(document).ready
в iframe, похоже, запускается слишком рано, и содержимое iframe еще даже не загружено, поэтому код galleria не применяется должным образом к элементам DOM. $(document).ready
кажется, использует родительское состояние готовности iframe, чтобы решить, готов ли iframe.
Если мы выделим функцию, вызванную document ready, в отдельную функцию и вызовем ее по истечении тайм-аута в 100 мс.Это работает, но мы не можем рисковать при производстве с медленным компьютером.
$(document).ready(function() { setTimeout(ApplyGalleria, 100); });
Мой вопрос:к какому событию jQuery мы должны привязаться, чтобы иметь возможность выполнить наш код, когда динамический iframe готов, а не только родительский?
Решение
Я ответил на аналогичный вопрос (см. Обратный вызов 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 я счел достаточно хорошим использовать load event вместо document ready event.
Другие советы
Используя 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.Весь код находится и выполняется из родительского фрейма / окна.
В IFrames я обычно решаю эту проблему, помещая небольшой скрипт в самый конец блока:
<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
fireOnReadyEvent();
parent.IFrameLoaded();
//]]>
</script>
</body>
Эта работа занимает у меня большую часть времени.Иногда самое простое и наивное решение является наиболее подходящим.
Следуя идее доктора Джокепу и Дэвида Мердока, я реализовал более полную версию.IT требует 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);
});
});
Нашел решение этой проблемы.
Когда вы нажимаете на ссылку thickbox, которая открывает iframe, он вставляет iframe с идентификатором TB_iframeContent.
Вместо того, чтобы полагаться на $(document).ready
событие в коде iframe, мне просто нужно привязаться к событию загрузки iframe в родительском документе:
$('#TB_iframeContent', top.document).load(ApplyGalleria);
Этот код находится в iframe, но привязывается к событию элемента управления в родительском документе.Это работает в FireFox и IE.
Попробуй это,
<iframe id="testframe" src="about:blank" onload="if (testframe.location.href != 'about:blank') testframe_loaded()"></iframe>
Все, что вам нужно сделать затем, это создать JavaScript-функцию testframe_loaded().
Я загружаю 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";
В основном то, что другие уже опубликовали, но, ИМХО, немного чище:
$('<iframe/>', {
src: 'https://example.com/',
load: function() {
alert("loaded")
}
}).appendTo('body');
Это была именно та проблема, с которой я столкнулся с нашим клиентом.Я создал небольшой плагин jquery, который, кажется, работает для обеспечения готовности iframe.Он использует опрос для проверки состояния готовности документа iframe в сочетании с внутренним URL-адресом документа в сочетании с источником iframe, чтобы убедиться, что iframe действительно "готов".
Проблема с "onload" заключается в том, что вам нужен доступ к фактическому iframe, добавляемому в DOM, если вы этого не сделаете, вам нужно попытаться перехватить загрузку iframe, которая, если она кэширована, может быть недоступна.Что мне было нужно, так это скрипт, который можно было вызвать в любое время и определить, был ли iframe "готов" или нет.
Вот в чем вопрос:
Святой грааль для определения того, загрузился ли локальный iframe
и вот jsfiddle, к которому я в конце концов пришел.
https://jsfiddle.net/q0smjkh5/10/
В приведенном выше jsfiddle я жду, когда onload добавит iframe в dom, затем проверяет состояние готовности внутреннего документа iframe - которое должно быть междоменным, потому что оно указывает на википедию, - но Chrome, похоже, сообщает "завершено".Затем метод 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>