動的に挿入されたiframeのjQuery .ready
-
03-07-2019 - |
質問
jQuery シックボックスを使用して、誰かが画像をクリックしたときにiframeを動的に表示します。このiframeでは、 galleria JavaScriptライブラリを使用して、複数の写真を表示しています。
問題は、iframeの $(document).ready
の起動が早すぎるようで、iframeコンテンツがまだロードされていないため、ガレリアコードが適切に適用されていないことですDOM要素。 $(document).ready
はiframeの準備完了状態を使用して、iframeの準備ができているかどうかを判断しているようです。
ドキュメントによって呼び出された関数を別の関数で準備し、100ミリ秒のタイムアウト後に呼び出した場合。動作はしますが、遅いコンピューターで本番環境を利用することはできません。
$(document).ready(function() { setTimeout(ApplyGalleria, 100); });
私の質問:動的iframeの準備ができて、親だけではないときにコードを実行できるようにするには、どのjQueryイベントにバインドする必要がありますか?
解決
同様の質問に回答しました( 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の処理では、ドキュメントの準備完了イベントの代わりに読み込みイベントを使用するのに十分であることがわかりました。
他のヒント
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ページのコードを必要としません。すべてのコードが存在し、親フレーム/ウィンドウから実行されます。
IFrameでは、通常、ブロックの最後に小さなスクリプトを追加することでこの問題を解決します。
<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
fireOnReadyEvent();
parent.IFrameLoaded();
//]]>
</script>
</body>
これはほとんどの場合私にとってはうまくいきます。時には、最も単純で最も素朴な解決策が最も適切な場合があります。
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);
});
});
問題の解決策を見つけました。
iframeを開くシックボックスリンクをクリックすると、TB_iframeContentのIDを持つiframeが挿入されます。
iframeコードの $(document).ready
イベントに依存する代わりに、親ドキュメントのiframeのloadイベントにバインドするだけです:
$('#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');
これは、私がクライアントと遭遇した正確な問題でした。 iframeの準備に役立つと思われる小さなjqueryプラグインを作成しました。ポーリングを使用して、iframeドキュメントのreadyStateをiframeソースと組み合わせた内部ドキュメントのURLと組み合わせてチェックし、iframeが実際に「準備完了」であることを確認します。
&quot; onload&quot;の問題DOMに追加されている実際のiframeにアクセスする必要があるということです。そうでない場合は、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>