我正在开发一个类似 iGoogle 的应用程序。来自其他应用程序(在其他域上)的内容使用 iframe 显示。
如何调整 iframe 的大小以适合 iframe 内容的高度?
我试图破译谷歌使用的 javascript,但它被混淆了,到目前为止,搜索网络一直没有结果。
更新:请注意内容是从其他域加载的,因此适用同源策略。
我正在开发一个类似 iGoogle 的应用程序。来自其他应用程序(在其他域上)的内容使用 iframe 显示。
如何调整 iframe 的大小以适合 iframe 内容的高度?
我试图破译谷歌使用的 javascript,但它被混淆了,到目前为止,搜索网络一直没有结果。
更新:请注意内容是从其他域加载的,因此适用同源策略。
我们遇到了这种类型的问题,但与您的情况略有相反 - 我们向其他域上的站点提供 iframe 内容,因此同源策略也是一个问题。经过许多小时的 google 搜索,我们最终找到了一个(有点……)可行的解决方案,您可以根据自己的需要进行调整。
有一种绕过同源策略的方法,但是它需要在 iframe 内容和框架页面上进行更改,因此如果您没有能力在两侧请求更改,则此方法对您不会很有用,我耽心。
有一个浏览器的怪癖,它允许我们绕过同源策略 - javascript 可以与自己域中的页面通信,或者与它具有 iframe 的页面通信,但永远不会与它被框架化的页面通信,例如,如果您有:
www.foo.com/home.html, which iframes
|-> www.bar.net/framed.html, which iframes
|-> www.foo.com/helper.html
然后home.html
可以与framed.html
(iframed)和helper.html
(同一个域)通信。
Communication options for each page:
+-------------------------+-----------+-------------+-------------+
| | home.html | framed.html | helper.html |
+-------------------------+-----------+-------------+-------------+
| www.foo.com/home.html | N/A | YES | YES |
| www.bar.net/framed.html | NO | N/A | YES |
| www.foo.com/helper.html | YES | YES | N/A |
+-------------------------+-----------+-------------+-------------+
framed.html
可以向helper.html
(iframed)发送消息,但不能 home.html
(子级不能与父级进行跨域通信)。
这里的关键是,helper.html
能够接收来自消息framed.html
,并且还可以沟通与home.html
。
所以基本上,当framed.html
加载时,它会计算出自己的高度,告诉helper.html
,它将消息传递给home.html
,然后可以调整framed.html
坐下的 iframe 的大小。
我们发现,从传递消息最简单的方法framed.html
来helper.html
是通过URL参数。要做到这一点,framed.html
有一个src=''
指定的 iframe 。当它onload
触发时,它会评估自己的高度,并将此时 iframe 的 src 设置为helper.html?height=N
这里有一个关于facebook如何处理它的解释,这可能比我上面的更清楚!
在 中www.foo.com/home.html
,需要以下 javascript 代码(这可以从任何域上的 .js 文件加载,顺便说一句..):
<script>
// Resize iframe to full height
function resizeIframe(height)
{
// "+60" is a general rule of thumb to allow for differences in
// IE & and FF height reporting, can be adjusted as required..
document.getElementById('frame_name_here').height = parseInt(height)+60;
}
</script>
<iframe id='frame_name_here' src='http://www.bar.net/framed.html'></iframe>
在www.bar.net/framed.html
:
<body onload="iframeResizePipe()">
<iframe id="helpframe" src='' height='0' width='0' frameborder='0'></iframe>
<script type="text/javascript">
function iframeResizePipe()
{
// What's the page height?
var height = document.body.scrollHeight;
// Going to 'pipe' the data to the parent through the helpframe..
var pipe = document.getElementById('helpframe');
// Cachebuster a precaution here to stop browser caching interfering
pipe.src = 'http://www.foo.com/helper.html?height='+height+'&cacheb='+Math.random();
}
</script>
内容www.foo.com/helper.html
:
<html>
<!--
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content
-->
<body onload="parentIframeResize()">
<script>
// Tell the parent iframe what height the iframe needs to be
function parentIframeResize()
{
var height = getParam('height');
// This works as our parent's parent is on our domain..
parent.parent.resizeIframe(height);
}
// Helper function, parse param from request string
function getParam( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
</script>
</body>
</html>
如果你不需要处理来自不同域的 iframe 内容,试试这个代码,它会彻底解决问题,而且很简单:
<script language="JavaScript">
<!--
function autoResize(id){
var newheight;
var newwidth;
if(document.getElementById){
newheight=document.getElementById(id).contentWindow.document .body.scrollHeight;
newwidth=document.getElementById(id).contentWindow.document .body.scrollWidth;
}
document.getElementById(id).height= (newheight) + "px";
document.getElementById(id).width= (newwidth) + "px";
}
//-->
</script>
<iframe src="usagelogs/default.aspx" width="100%" height="200px" id="iframe1" marginheight="0" frameborder="0" onLoad="autoResize('iframe1');"></iframe>
https://developer.mozilla.org/en/DOM/window.postMessage
window.postMessage()
window.postMessage 是一种安全启用跨域通信的方法。通常,当且仅当执行它们的页面位于具有相同协议(通常都是 http)、端口号(80 是 http 的默认值)和主机(模document.domain 被两个页面设置为相同的值)。window.postMessage 提供了一种受控机制,以在正确使用时安全的方式规避此限制。
概括
window.postMessage,当调用时,会导致在任何必须执行的挂起脚本完成时在目标窗口分派 MessageEvent(例如,如果 window.postMessage 从事件处理程序中调用,则剩余的事件处理程序,先前设置的挂起超时等。 )。MessageEvent 有类型消息,一个数据属性,它被设置为提供给 window.postMessage 的第一个参数的字符串值,一个 origin 属性对应于在时间窗口调用 window.postMessage 的窗口中的主文档的来源。 postMessage 被调用,源属性是调用 window.postMessage 的窗口。(事件的其他标准属性与其预期值一起存在。)
该iframe的调整器库使用的postMessage保持一个iFrame尺寸为它的内容,随着MutationObserver检测改动的内容和不依赖于jQuery的。
https://github.com/davidjbradshaw/iframe-resizer
jQuery:跨域脚本的优点
http://benalman.com/projects/jquery-postmessage-plugin/
有调整 iframe 窗口大小的演示...
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
这篇文章展示了如何移除对 jQuery 的依赖... Plus 有很多有用的信息和其他解决方案的链接。
http://www.onlineaspect.com/2010/01/15/backwards-compatible-postmessage/
准系统示例...
http://onlineaspect.com/uploads/postmessage/parent.html
window.postMessage 上的 HTML 5 工作草案
http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
John Resig 谈跨窗口消息传递
使用 jQuery 的最简单方法:
$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
$(this).css("height", $(this).contents().height() + "px");
});
最后,我找到了一些其他解决方案,可以使用window.postMessage(message, targetOrigin);
. 我在这里解释我是如何做到的。
站点 A = http://foo.com 站点 B = http://bar.com
SiteB 正在加载 siteA 网站内
SiteB网站有这条线
window.parent.postMessage("Hello From IFrame", "*");
或者
window.parent.postMessage("Hello From IFrame", "http://foo.com");
然后站点A有以下代码
// Here "addEventListener" is for standards-compliant web browsers and "attachEvent" is for IE Browsers.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to message from child IFrame window
eventer(messageEvent, function (e) {
alert(e.data);
// Do whatever you want to do with the data got from IFrame in Parent form.
}, false);
如果你想添加安全连接,你可以使用这个 if 条件 eventer(messageEvent, function (e) {})
if (e.origin == 'http://iframe.example.com') {
alert(e.data);
// Do whatever you want to do with the data got from IFrame in Parent form.
}
浏览器
IFrame内部:
window.parent.postMessage('{"key":"value"}','*');
外部:
eventer(messageEvent, function (e) {
var data = jQuery.parseJSON(e.data);
doSomething(data.key);
}, false);