【发布时间】:2011-08-20 00:04:15
【问题描述】:
如何从另一个域调整 iframe 的大小
-编辑
向下滚动以获取一些解决方案.. 或阅读如何不这样做:D
经过数小时的代码破解 - 结论是 iframe 内的任何内容都无法访问,即使是在我的域上呈现的滚动条也是如此。我尝试了很多技术都无济于事。
为了节省您的时间,甚至不要走这条路,只需使用 sendMessages 进行跨域通信即可。 我使用了 HTML
过去几天我一直在尝试将 iframe 集成到网站中。这是一个短期解决方案,而另一方开发和 API(可能需要几个月...) 而且因为这是我们想要使用easyXDM的短期解决方案-我可以访问另一个域,但是要求他们按原样添加p3p标头已经足够困难了.....
3 个 iframe
我找到的最接近的解决方案是 3 个 iframe,但它是 chrome 和 safari 的一种,所以我不能使用它。
在 chrome 中打开
http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179
测量滚动条
我发现了另一篇关于如何使用滚动高度来尝试调整表单大小的帖子。理论上它效果很好,但我无法使用 iframe 滚动高度正确应用它。
document.body.scrollHeight
这显然使用了主体高度(无法访问这些属性 100% 是基于客户端显示画布而不是 x 域文档高度)
我尝试使用 jquery 来获取 iframe 高度
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
返回值在 chrome 和 ie 中不同 - 或者根本没有意义。 问题是框架内的所有内容都被拒绝 - 甚至滚动条......
计算样式
但是,如果我检查 iframe 的 chrome 中的元素,它会向我显示 iframe 内的文档尺寸(使用 jquery x-domain 获取 iframe.heigh - 访问被拒绝) 计算出的 CSS
中没有任何内容现在 chrome 是如何计算的呢? (编辑 - 浏览器使用其内置渲染引擎重新渲染页面以计算所有这些设置 - 但没有附加到任何地方以防止跨域欺诈......所以......)
HTML4
我阅读了 HTML4.x 的规范,它说应该有通过 document.element 公开的只读值,但通过 jquery 拒绝访问
代理框架
我沿着代理站点的路线返回并计算哪个可以..直到用户通过 iframe 登录并且代理获取登录页面而不是实际内容。还有一些调用页面两次是不可接受的
http://www.codeproject.com/KB/aspnet/asproxy.aspx
http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/
重新渲染页面
我没有走这么远,但是那里有 jscript 引擎,它们会查看源代码并根据源文件重新呈现页面。但这需要破解那些 jscripts.. 这对于商业实体来说不是一个理想的情况...... 以及一些引入纯 Java 小程序或服务器端渲染
http://en.wikipedia.org/wiki/Server-side_JavaScript
http://htmlunit.sourceforge.net/
编辑 09-2013 更新
所有这些都可以通过 HTML5 套接字来完成。但是对于非 HTML5 投诉页面,easyXDM 是很好的后备方案。
解决方案 1 非常好的解决方案!
使用easyXDM
在您的服务器上,您以以下形式设置页面
<html>
<head>
<script src="scripts/easyXDM.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">
var transport = new easyXDM.Socket(/** The configuration */{
remote: "http://www.OTHERDOMAIN.com/resize_intermediate.html?url=testpages/resized_iframe_1.html",
//ID of the element to attach the inline frame to
container: "embedded",
onMessage: function (message, origin) {
var settings = message.split(",");
//Use jquery on a masterpage.
//$('iframe').height(settings[0]);
//$('iframe').width(settings[1]);
//The normal solution without jquery if not using any complex pages (default)
this.container.getElementsByTagName("iframe")[0].style.height = settings[0];
this.container.getElementsByTagName("iframe")[0].style.width = settings[1];
}
});
</script>
</head>
<body>
<div id="embedded"></div>
</body>
在调用者域中,他们只需要在同一个地方添加 intermediadate_frame html 和 easyXDM.js。像父文件夹一样 - 然后您可以访问相关目录或仅适合您的包含文件夹。
选项 1
如果您不想将脚本添加到所有页面,请查看选项 2!
然后他们可以在您需要调整大小的每个页面的末尾添加一个简单的 jscript。无需在每个页面中都包含 easyxdm。
<script type="text/javascript">
window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) ); };
</script>
我已经修改了它发送的参数。如果您希望宽度正常工作,则 otherdomain 上的页面需要将页面宽度包含在类似于以下内容的样式中:
<style type="text/css">
html, body {
overflow: hidden;
margin: 0px;
padding: 0px;
background-color: rgb(75,0,85);
color:white;
width:660px
}
a {
color:white;
visited:white;
}
</style>
这对我很有用。如果不包括宽度,则框架的行为有点奇怪,并且有点试图猜测它应该是什么......并且如果你需要它不会缩小。
选项 2
修改中间帧以轮询更改
你的中间框架应该看起来像这样..
<!doctype html>
<html>
<head>
<title>Frame</title>
<script type="text/javascript" src="easyXDM.js">
</script>
<script type="text/javascript">
var iframe;
var socket = new easyXDM.Socket({
//This is a fallback- not needed in many cases
swf: "easyxdm.swf",
onReady: function(){
iframe = document.createElement("iframe");
iframe.frameBorder = 0;
document.body.appendChild(iframe);
iframe.src = "THE HOST FRAME";
iframe.onchange = messageBack();
},
onMessage: function(url, origin){
iframe.src = url;
}
});
//Probe child.frame for dimensions.
function messageBack(){
socket.postMessage ( iframe.contentDocument.body.clientHeight + "," + iframe.contentDocument.body.clientWidth);
};
//Poll for changes on children every 500ms.
setInterval("messageBack()",500);
</script>
<style type="text/css">
html, body {
overflow: hidden;
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
}
iframe {
width: 100%;
height: 100%;
border: 0px;
}
</style>
</head>
<body>
</body>
</html>
间隔可以更有效地检查大小是否发生变化,并且仅在尺寸发生变化时才发送,而不是每 500 毫秒发布一次消息。如果您实施此检查,那么您可以将轮询更改为低至 50 毫秒!玩得开心
跨浏览器工作,速度很快。很棒的调试功能!!
Excellent Work to Sean Kinsey who made the script!!!
解决方案 2(有效但效果不佳)
所以基本上,如果您与其他域有相互协议,那么您可以添加一个库来处理发送消息。如果您对其他域没有任何访问权限.. 继续寻找更多黑客 - 因为我找不到或完全证明我发现的这些。
所以其他域会将这些包含在 Head 标签中
<script src="scripts/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery.postmessage.min.js" type="text/javascript"></script>
<script src="scripts/club.js" type="text/javascript"></script>
在 club.js 中只是我为调整大小调用而进行的一些自定义调用,并且包含..
$(document).ready(function () {
var parent_url = decodeURIComponent( document.location.hash.replace( /^#/, '' ) ),link;
//Add source url hash to each url to authorise callback when navigating inside the frame.Without this clicking any links will break the communication and no messages will be received
$('a[href]').each(function(){
this.href = this.href + document.location.hash ;
});
//Get the dimensions and send back to calling page.
var h1 = document.body.scrollHeight;
var w1 = document.body.scrollWidth;
$.postMessage({ if_height: h1, if_width: w1 }, parent_url, parent );
});
您的页面将完成所有艰苦的工作并有一个不错的脚本...
//This is almost like request.querystring used to get the iframe data
function querySt(param, e) {
gy = e.split("&");
for (i = 0; i < gy.length; i++) {
ft = gy[i].split("=");
if (ft[0] == param) {
return ft[1];
}
}
}
$(function () {
// Keep track of the iframe dimensions.
var if_height;
var if_width;
// Pass the parent page URL into the Iframe in a meaningful way (this URL could be
// passed via query string or hard coded into the child page, it depends on your needs).
src = 'http://www.OTHERDOAMIN.co.uk/OTHERSTARTPAGE.htm' + '#' + encodeURIComponent(document.location.href),
// Append the Iframe into the DOM.
iframe = $('<iframe " src="' + src + '" width="100%" height="100%" scrolling="no" frameborder="0"><\/iframe>').appendTo('#iframe');
// Setup a callback to handle the dispatched MessageEvent event. In cases where
// window.postMessage is supported, the passed event will have .data, .origin and
// .source properties. Otherwise, this will only have the .data property.
$.receiveMessage(function (e) {
// Get the height from the passsed data.
//var h = Number(e.data.replace(/.*if_height=(\d+)(?:&|$)/, '$1'));
var h = querySt("if_height", e.data);
var w = querySt("if_width", e.data);
if (!isNaN(h) && h > 0 && h !== if_height) {
// Height has changed, update the iframe.
iframe.height(if_height = h);
}
if (!isNaN(w) && w > 0 && w !== if_width) {
// Height has changed, update the iframe.
iframe.width(if_width = w);
}
//For debugging only really- can remove the next line if you want
$('body').prepend("Recieved" + h + "hX" + w + "w .. ");
// An optional origin URL (Ignored where window.postMessage is unsupported).
//Here you must put the other domain.com name only! This is like an authentication to prevent spoofing and xss attacks!
}, 'http://www.OTHERDOMAIN.co.uk');
});
选项 3
他们现在是一个小型 JS 库,用于管理跨域 iFrame 的大小调整,它仍然需要 iFrame 中包含一些 JavaScript,然而,这只是 2.8k(765 字节 Gzipped)的原生 JS,没有有任何依赖关系,并且在父页面调用之前它不会做任何事情。这意味着它是其他人系统的好客人。
此代码使用 mutationObserver 检测 DOM 更改并注意调整大小事件,以便 iFrame 保持与内容大小一致。适用于 IE8+。
【问题讨论】:
-
easyXDM 示例的代码实际上要少得多,不依赖外部库,并且也可以在旧版浏览器中运行 :) 是的,因为我是作者,所以我有偏见,但仍然如此。 .
-
我尝试了easyXDM,但我无法让内部框架浏览到其他链接以工作..我寻找示例..有些链接已损坏,示例页面未清除..确实工作!是我原来的答案..但我用了这个。你能发布一个内部浏览的方法吗..我看了又看..
-
@ppumkin example that ships 与下载完全支持内部浏览。断开的链接可能是我做的一个实验,但服务器在某一时刻被刷新了..
-
是的,看了又看:D 由于某种原因,我无法让它与我的网站一起使用。我会再试一次。
-
它可以工作-但是如果我单击该域上的链接,它会重新加载页面-与您一起使用库-但我无法收到任何消息。无论请求来自何处,我如何让它接受请求。这个 easyxdm.swf 有什么用? :)
标签: javascript html css iframe cross-domain