我们正在使用jQuery thickbox在有人点击图片时动态显示iframe。在这个iframe中,我们使用galleria javascript库来显示多张图片。
问题似乎是,iframe中的$(document).ready
似乎过早被解雇,iframe内容甚至尚未加载,因此galleria代码未在DOM元素上正确应用。 $(document).ready
似乎使用iframe父级就绪状态来决定iframe是否准备就绪。
如果我们在单独的函数中提取由文档就绪调用的函数,并在超时100毫秒后调用它。它有效,但我们不能利用慢速计算机进行生产。
$(document).ready(function() { setTimeout(ApplyGalleria, 100); });
我的问题:我们应该绑定哪个jQuery事件,以便在动态iframe准备就绪时能够执行我们的代码,而不仅仅是它的父级?
答案 0 :(得分:287)
我回答了类似的问题(见Javascript callback when IFRAME is finished loading?)。 您可以使用以下代码控制iframe加载事件:
function callIframe(url, callback) {
$(document.body).append('<IFRAME id="myId" ...>');
$('iframe#myId').attr('src', url);
$('iframe#myId').load(function() {
callback(this);
});
}
在处理iframe时,我发现使用load事件而不是文档就绪事件就足够了。
答案 1 :(得分:28)
使用jQuery 1.3.2,以下对我有用:
$('iframe').ready(function() {
$('body', $('iframe').contents()).html('Hello World!');
});
REVISION:! 实际上上面的代码看起来有点像在Firefox中工作,看起来它在Opera中看起来没用。
相反,我为我的目的实施了一个轮询解决方案。简化它看起来像这样:
$(function() {
function manipIframe() {
el = $('body', $('iframe').contents());
if (el.length != 1) {
setTimeout(manipIframe, 100);
return;
}
el.html('Hello World!');
}
manipIframe();
});
这不需要调用iframe页面中的代码。所有代码都驻留在父框架/窗口中并执行。
答案 2 :(得分:14)
在IFrame中,我通常通过在块的最末端放一个小脚来解决这个问题:
<body>
The content of your IFrame
<script type="text/javascript">
//<![CDATA[
fireOnReadyEvent();
parent.IFrameLoaded();
//]]>
</script>
</body>
这项工作大部分时间都适合我。有时最简单,最天真的解决方案是最合适的。
答案 3 :(得分:9)
按照约克博士和大卫默多克的想法,我实施了一个更完整的版本。 需要 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);
});
});
答案 4 :(得分:4)
找到问题的解决方案。
当您点击打开iframe的厚盒链接时,会插入一个ID为TB_iframeContent的iframe。
我不必依赖iframe代码中的$(document).ready
事件,而只需绑定到父文档中iframe的load事件:
$('#TB_iframeContent', top.document).load(ApplyGalleria);
此代码位于iframe中,但绑定到父文档中控件的事件。它适用于FireFox和IE。
答案 5 :(得分:1)
试试这个,
<iframe id="testframe" src="about:blank" onload="if (testframe.location.href != 'about:blank') testframe_loaded()"></iframe>
您需要做的就是创建JavaScript函数testframe_loaded()。
答案 6 :(得分:1)
我正在将带有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";
答案 7 :(得分:1)
基本上其他人已发布但恕我直言的更清洁:
$('<iframe/>', {
src: 'https://example.com/',
load: function() {
alert("loaded")
}
}).appendTo('body');
答案 8 :(得分:0)
这是我与客户遇到的确切问题。我创建了一个小jquery插件,似乎适用于iframe准备。它使用轮询来检查iframe文档readyState与内部文档URL结合iframe源以确保iframe实际上是“就绪”。
“onload”的问题是你需要访问添加到DOM的实际iframe,如果你没有,那么你需要尝试捕获iframe加载,如果它被缓存,那么你可能不会。我需要的是一个可以随时调用的脚本,并确定iframe是否“准备好”。
以下是问题:
Holy grail for determining whether or not local iframe has loaded
这是我最终提出的jsfiddle。
https://jsfiddle.net/q0smjkh5/10/
在上面的jsfiddle中,我正在等待onload将一个iframe附加到dom,然后检查iframe的内部文档的就绪状态 - 这应该是跨域的,因为它指向维基百科 - 但Chrome似乎报告“完成”。然后在iframe实际就绪时调用插件的iready方法。回调试图再次检查内部文档的就绪状态 - 这次报告跨域请求(这是正确的) - 无论如何它似乎适用于我需要的东西并希望它能帮助其他人。
<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>
答案 9 :(得分:0)
this answer中的此功能是处理此问题的最佳方法,因为$.ready
对于iframe明确失败。 Here's the decision不支持这一点。
如果iframe已经加载,则load
事件也不会触发。非常沮丧的是,这仍然是2020年的问题!
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();
}
}