我正在开发一个类似igoogle的应用程序。来自其他应用程序(在其他域中)的内容使用iframe显示。
我如何调整iframes的大小以适应iframes的内容的高度?
我试图破译的javascript谷歌使用,但它是模糊的,搜索网络至今一无所获。
更新:请注意,内容是从其他域加载的,因此适用同源策略。
我正在开发一个类似igoogle的应用程序。来自其他应用程序(在其他域中)的内容使用iframe显示。
我如何调整iframes的大小以适应iframes的内容的高度?
我试图破译的javascript谷歌使用,但它是模糊的,搜索网络至今一无所获。
更新:请注意,内容是从其他域加载的,因此适用同源策略。
当前回答
我们有这种类型的问题,但稍微与您的情况相反-我们正在向其他域的网站提供iframed内容,因此同源策略也是一个问题。在花了好几个小时搜索谷歌后,我们最终找到了一个(有点..)可行的解决方案,您可能能够适应您的需求。
有一种方法可以绕过同源策略,但它需要同时对iframe内容和框架页面进行更改,因此,如果您不能同时请求更改两边的内容,那么这种方法恐怕对您没有多大用处。
有一个浏览器的怪癖,它允许我们绕过同源策略——javascript可以与自己域中的页面通信,也可以与它已经框架的页面通信,但不能与它被框架的页面通信,例如,如果你有:
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可以向help .html (iframed)发送消息,但不能向home.html发送消息(子节点不能与父节点跨域通信)。
这里的关键是help .html可以接收来自framed.html的消息,也可以与home.html通信。
本质上,当framed。html加载时,它计算出自己的高度,告诉helper。html,后者将消息传递给home。html,后者可以调整framed。html所在的iframe的大小。
我们发现的将消息从framed.html传递到help .html的最简单方法是通过URL参数。为此,frames .html有一个iframe,并指定了src= "。当它的onload触发时,它计算自己的高度,并在此时将iframe的src设置为help .html?身高= 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>
其他回答
我相信这样的做法会奏效。
parent.document.getElementById(iFrameID).style.height=framedPage.scrollHeight;
在iframe内容中加载你的body。
This is slightly tricky as you have to know when the iframe page has loaded, which is difficuly when you're not in control of its content. Its possible to add an onload handler to the iframe, but I've tried this in the past and it has vastly different behaviour across browsers (not guess who's the most annoying...). You'd probably have to add a function to the iframe page that performs the resize and inject some script into the content that either listens to load events or resize events, which then calls the previous function. I'm thinking add a function to the page since you want to make sure its secure, but I have no idea how easy it will be to do.
David Bradshaw和Chris Jacob已经建议使用postMessage方法。我完全同意,做这些事情的正确方法。
我只是想发布一个例子,真实的代码,以防它对一些人来说是现成的答案。
在iframed面:
<body onload="docResizePipe()">
<script>
var v = 0;
const docResizeObserver = new ResizeObserver(() => {
docResizePipe();
});
docResizeObserver.observe(document.querySelector("body"));
function docResizePipe() {
v += 1;
if (v > 5) {
return;
}
var w = document.body.scrollWidth;
var h = document.body.scrollHeight;
window.parent.postMessage([w,h], "*");
}
setInterval(function() {
v -= 1;
if (v < 0) {
v = 0;
}
}, 300);
</script>
注意递归阻塞机制——这显然是必要的,因为Firefox中有一个bug,但不管怎样,让它存在吧。
在父文档端:
<iframe id="rpa-frame" src="3.html" style="border: none;"></iframe>
<script>
var rpaFrame = document.getElementById("rpa-frame");
window.addEventListener("message", (event) => {
var width = event.data[0];
var height = event.data[1];
rpaFrame.width = parseInt(width)+60;
rpaFrame.height = parseInt(height)+60;
console.log(event);
}, false);
</script>
希望对大家有用。
获取iframe内容高度,然后将其赋给这个iframe
var iframes = document.getElementsByTagName("iframe");
for(var i = 0, len = iframes.length; i<len; i++){
window.frames[i].onload = function(_i){
return function(){
iframes[_i].style.height = window.frames[_i].document.body.scrollHeight + "px";
}
}(i);
}
我在这里读了很多答案,但几乎每个人都给出了一些交叉起源的框架块。
错误示例:
未捕获的DOMException:阻止了一个原点为“null”的帧 访问跨原点框架。
在相关线程中的答案也是一样的:
使iframe自动调整高度根据内容而不使用滚动条?
我不想使用第三方库,如iFrame Resizer或类似的库。
来自@ChrisJacob的答案很接近,但我缺少一个完整的工作示例,而不仅仅是链接。@Selvamani和@latitov也是很好的互补。
https://stackoverflow.com/a/3219970/3850405
我使用width="100%"的iframe,但代码可以修改为宽度以及工作。
这是我如何解决设置自定义高度的iframe:
iframe嵌入:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description"
content="Web site" />
<title>Test with embedded iframe</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<iframe id="ifrm" src="https://localhost:44335/package/details?key=123" width="100%"></iframe>
<script type="text/javascript">
window.addEventListener('message', receiveMessage, false);
function receiveMessage(evt) {
console.log("Got message: " + JSON.stringify(evt.data) + " from origin: " + evt.origin);
// Do we trust the sender of this message?
if (evt.origin !== "https://localhost:44335") {
return;
}
if (evt.data.type === "frame-resized") {
document.getElementById("ifrm").style.height = evt.data.value + "px";
}
}
</script>
</body>
</html>
iframe源代码,示例来自创建React应用程序,但只使用HTML和JS。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description"
content="Web site created using create-react-app" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="text/javascript">
//Don't run unless in an iframe
if (self !== top) {
var rootHeight;
setInterval(function () {
var rootElement = document.getElementById("root");
if (rootElement) {
var currentRootHeight = rootElement.offsetHeight;
//Only send values if height has changed since last time
if (rootHeight !== currentRootHeight) {
//postMessage to set iframe height
window.parent.postMessage({ "type": "frame-resized", "value": currentRootHeight }, '*');
rootHeight = currentRootHeight;
}
}
}
, 1000);
}
</script>
</body>
</html>
带有setInterval的代码当然可以修改,但它与动态内容一起工作得非常好。setInterval仅在内容嵌入iframe时激活,postMessage仅在高度改变时发送消息。
你可以在这里阅读更多关于Window.postMessage()的内容,但描述非常适合我们想要实现的目标:
The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it. Normally, scripts on different pages are allowed to access each other if and only if the pages they originate from share the same protocol, port number, and host (also known as the "same-origin policy"). window.postMessage() provides a controlled mechanism to securely circumvent this restriction (if used properly).
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage