如何从另一个域调整 iframe 的大小
-编辑
向下滚动一些解决方案......或阅读如何不这样做:D
经过数小时的代码黑客攻击 - 结论是 iframe 中的任何内容都无法访问,即使是在我的域上呈现的滚动条。我尝试了很多技术都无济于事。
为了节省您的时间,甚至不要走这条路,只需使用 sendMessages 进行跨域通信。 我使用了 HTML < 5 的插件 - 转到底部的一个很好的例子:)
过去几天我一直在尝试将 iframe 集成到站点中。这是一个短期解决方案,而另一方开发和 API(可能需要几个月......)而且因为这是短期解决方案,我们确实想使用 easyXDM-我可以访问另一个域,但要求他们这样做已经够困难了按原样添加 p3p 标头.....
3 个 iframe
我找到的最接近的解决方案是 3 个 iframe - 但它对 chrome 和 safari 很敏感,所以我不能使用它。
在 chrome 中打开
http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179
测量滚动条
我发现了另一篇关于如何使用滚动高度尝试调整表单大小的帖子..理论上它运行良好,但我无法使用 iframes 滚动高度正确应用它..
document.body.scrollHeight
显然使用主体高度(无法访问这些属性 100% 是基于客户端显示的画布而不是 x 域文档高度)
我尝试使用 jquery 来获取 iframes 高度
$('#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/ <-java 不是 jscript
编辑 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>
在调用者域上,他们只需要在同一个地方添加 intermediate_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(有效但不是很好)
所以基本上,如果您与其他域有相互协议,那么您可以添加一个库来处理 sendmessage。如果您没有任何访问其他域的权限.. 继续寻找更多黑客 - 因为我找不到或完全证明我发现的这些。
所以另一个域将在那里包含这些 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
他们现在是一个用于管理跨域 iFrame 大小调整的小型 JS 库,它仍然需要 iFrame 中包含一些 JavaScript,但是,这只是 2.8k(765 字节 Gzipped)的原生 JS,没有任何依赖项并且在被父页面调用之前它不会做任何事情。这意味着它是其他人系统上的好客。
此代码使用 mutationObserver 来检测 DOM 更改并查看调整大小事件,以便 iFrame 保持与内容一致的大小。适用于 IE8+。