如何从其他域调整iframe的大小
-编辑
向下滚动一些解决方案..或阅读如何不这样做:D
经过数小时的代码黑客攻击后,得出的结论是,iframe内部的任何内容都无法访问,即使是在我的域中呈现的滚动条也是如此。我尝试了许多技巧都无济于事。
为了节省您的时间,甚至不要走这条路,只需使用sendMessages进行跨域通信。 我使用了HTML <5的插件-进入底部找到一个好例子:)
过去几天,我一直在尝试将iframe集成到网站中。这是一个短期解决方案,而另一方正在开发和API(可能要花费数月的时间...),并且因为这是短期解决方案,所以我们确实想使用easyXDM-我可以访问其他域,但要求他们这样做非常困难按原样添加p3p标头.....
3个iframe
我找到的最接近的解决方案是3个iframe,但考虑到了chrome和safari,所以我不能使用它。
镀铬
http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&height=1179
测量滚动条
我找到了另一篇有关如何使用scrollheight尝试调整表单大小的文章。理论上它可以正常工作,但是我无法使用iframe滚动高度正确应用它。
document.body.scrollHeight
那显然使用了主体的高度(无法访问这些属性100%是基于客户端显示的Canvaz而非x域文档的高度)
我尝试使用jquery来获取iframe的高度
$('#frameId').Height()
$('#frameId').clientHeight
$('#frameId').scrollHeight
返回不同的Chrome值,即-或根本没有任何意义。问题是框架内的所有内容都被拒绝-甚至滚动条...
计算样式
但是,如果我检查并在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引擎可以查看源代码并根据源文件重新呈现页面。但这需要破解这些jscript ..对于商业实体而言,那不是理想的情况...以及一些涉及纯Java小程序或服务器端渲染的发票
http://en.wikipedia.org/wiki/Server-side_JavaScript
http://htmlunit.sourceforge.net/ <-java而不是jscript
编辑09-2013 更新
所有这些都可以通过HTML5套接字完成。但是easyXDM对于非HTML5投诉页面来说是很好的后备。
解决方案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>
在调用者域上,他们只需要在同一位置添加intermiedate_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毫秒发布一次消息,才发送间隔。如果执行此检查,则可以将轮询更改为低至50ms!玩得开心
跨浏览器工作并且速度很快。强大的调试功能!
Excellent Work to Sean Kinsey who made the script!!!
解决方案2(可行,但效果不佳)
因此,基本上,如果您与其他域有共同的协议,则可以添加一个库来处理sendmessage。如果您无权访问另一个域,请继续寻找更多的hacks,因为我找不到或完全证明我找到的这些hacks。
因此其他域将在其中包含这些标签
<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(Gzipped 765字节压缩)本机JS,没有任何依赖关系。并且在父页面调用之前,它不会执行任何操作。这意味着它是其他人系统上的好客人。
这段代码使用mutationObserver来检测DOM的变化,还可以查找调整大小的事件,从而使iFrame的大小与内容保持一致。适用于IE8 +。