我正在开发一个类似igoogle的应用程序。来自其他应用程序(在其他域中)的内容使用iframe显示。

我如何调整iframes的大小以适应iframes的内容的高度?

我试图破译的javascript谷歌使用,但它是模糊的,搜索网络至今一无所获。

更新:请注意,内容是从其他域加载的,因此适用同源策略。


当前回答

这是一个老话题,但在2020年,这仍然是一个相关的问题。事实上,我已经在另一个旧线程上发布了这个答案^^ (https://stackoverflow.com/a/64110252/4383587)


只是想分享我的解决方案和兴奋之情。我花了整整四天的时间进行密集的研究和失败,但我认为我已经找到了一种让iframe完全响应的巧妙方法!容量!

我尝试了很多不同的方法……我不希望像使用postMessage那样使用双向通信隧道,因为它对于同源来说很尴尬,对于跨源来说很复杂(因为没有管理员愿意打开门并代表您实现它)。

I've tried using MutationObservers and still needed several EventListeners (resize, click,..) to ensure that every change of the layout was handled correctly. - What if a script toggles the visibility of an element? Or what if it dynamically preloads more content on demand? - Another issue was getting an accurate height of the iframe contents from somewhere. Most people suggest using scrollHeight or offsetHeight, or combination of it by using Math.max. The problem is, that these values don't get updated until the iframe element changes its dimensions. To achieve that you could simply reset the iframe.height = 0 before grabbing the scrollHeight, but there are even more caveats to this. So, screw this.

然后,我有了另一个想法,用requestAnimationFrame实验来摆脱我的事件和观察者地狱。现在,我可以立即对每个布局变化做出反应,但我仍然没有可靠的来源来推断iframe的内容高度。然后我偶然发现了getComputedStyle !这是一种启蒙!一切都很顺利。

好吧,看看我从无数次尝试中提炼出来的代码。

function fit() {
    var iframes = document.querySelectorAll("iframe.gh-fit")

    for(var id = 0; id < iframes.length; id++) {
        var win = iframes[id].contentWindow
        var doc = win.document
        var html = doc.documentElement
        var body = doc.body
        var ifrm = iframes[id] // or win.frameElement

        if(body) {
            body.style.overflowX = "scroll" // scrollbar-jitter fix
            body.style.overflowY = "hidden"
        }
        if(html) {
            html.style.overflowX = "scroll" // scrollbar-jitter fix
            html.style.overflowY = "hidden"
            var style = win.getComputedStyle(html)
            ifrm.width = parseInt(style.getPropertyValue("width")) // round value
            ifrm.height = parseInt(style.getPropertyValue("height"))
        }
    }

    requestAnimationFrame(fit)
}

addEventListener("load", requestAnimationFrame.bind(this, fit))

就是这样,没错!在你的HTML代码中写入<iframe src="page.html" class="gh-fit gh-fullwidth"></iframe>。gh-fit只是一个伪CSS类,用于识别DOM中的哪些iframe元素应该受到脚本的影响。gh-fullwidth是一个简单的CSS类,只有一个规则宽度:100%;

上面的脚本自动从DOM中获取所有分配了.gh-fit类的iframe。然后它从document.getComputedStyle(iframe)中获取并使用预先计算的宽度和高度的样式值,其中总是包含该元素的像素完美大小!!只是完美!

注意,此解决方案不能跨起源工作(没有像IFrameResizer这样的双向通信策略,任何其他解决方案也不能)。JS不能访问iframe的DOM,如果它不属于你的话。

我能想到的另一个跨起源解决方案是使用https://github.com/gnuns/allorigins这样的代理。但这将涉及到深度复制你所发出的每个请求——换句话说——你“窃取”了整个页面源代码(让它成为你的,让JS访问DOM),你修补这个源代码中的每个链接/路径,这样它也会通过代理。重新链接程序是一个困难的,但可行的。

我可能会自己尝试解决这个跨起源问题,但那是另一天的事了。享受代码吧!:)

其他回答

获取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);
 }

使用jQuery的最简单方法:

$("iframe")
.attr({"scrolling": "no", "src":"http://www.someotherlink.com/"})
.load(function() {
    $(this).css("height", $(this).contents().height() + "px");
});

如果你不需要处理来自不同域的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>
<html>
<head>
<script>
function frameSize(id){
var frameHeight;

document.getElementById(id).height=0 + "px";
if(document.getElementById){
    newheight=document.getElementById(id).contentWindow.document.body.scrollHeight;    
}

document.getElementById(id).height= (frameHeight) + "px";
}
</script>
</head>

<body>

<iframe id="frame"  src="startframe.html" frameborder="0" marginheight="0" hspace=20     width="100%" 

onload="javascript:frameSize('frame');">

<p>This will work, but you need to host it on an http server, you can do it locally.    </p>
</body>
</html>

使用jQuery:

parent.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<style>
iframe {
    width: 100%;
    border: 1px solid black;
}
</style>
<script>
function foo(w, h) {
    $("iframe").css({width: w, height: h});
    return true;  // for debug purposes
}
</script>
<iframe src="child.html"></iframe>
</body>

child.html

<body>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$(function() {
    var w = $("#container").css("width");
    var h = $("#container").css("height");

    var req = parent.foo(w, h);
    console.log(req); // for debug purposes
});
</script>
<style>
body, html {
    margin: 0;
}
#container {
    width: 500px;
    height: 500px;
    background-color: red;
}
</style>
<div id="container"></div>
</body>