jQuery获取iframe加载后的内容高度

93

我有一个帮助页面,help.php,我正在主文件main.php的iframe中加载它。如何在iframe加载完毕后获取此页面的高度?

我之所以问这个问题,是因为我无法将iframe的高度样式设置为100%或自动。这就是为什么我认为我需要使用JavaScript的原因。 我正在使用jQuery。

CSS:

body {
    margin: 0;
    padding: 0;
}
.container {
    width: 900px;
    height: 100%;
    margin: 0 auto;
    background: silver;
}
.help-div {
    display: none;
    width: 850px;
    height: 100%;
    position: absolute;
    top: 100px;
    background: orange;
}
#help-frame {
    width: 100%;
    height: auto;
    margin:0;
    padding:0;
}

JS:

$(document).ready(function () {
    $("a.open-help").click(function () {
        $(".help-div").show();
        return false;
    })
})

HTML:

<div class='container'>
    <!-- -->
    <div class='help-div'>
        <p>This is a div with an iframe loading the help page</p>
        <iframe id="help-frame" src="../help.php" width="100%" height="100%" frameborder="1"></iframe>
    </div>  <a class="open-help" href="#">open Help in iFrame</a>

    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
    <p>hello world</p>
</div>

iFrame的内容是否来自于包含它的页面相同的域名? - Andrew
是的,这是安德鲁。我想使用一个iFrame,因为在帮助页面中我使用了锚点。 - FFish
11个回答

109

好的,我终于找到了一个好的解决方案:

$('iframe').load(function() {
    this.style.height =
    this.contentWindow.document.body.offsetHeight + 'px';
});
因为某些浏览器(旧版Safari和Opera)在CSS渲染之前报告了onload完成,所以您需要设置微小的超时时间并清空并重新分配iframe的src。
$('iframe').load(function() {
    setTimeout(iResize, 50);
    // Safari and Opera need a kick-start.
    var iSource = document.getElementById('your-iframe-id').src;
    document.getElementById('your-iframe-id').src = '';
    document.getElementById('your-iframe-id').src = iSource;
});
function iResize() {
    document.getElementById('your-iframe-id').style.height = 
    document.getElementById('your-iframe-id').contentWindow.document.body.offsetHeight + 'px';
}

2
我相信load事件在同一事件循环中触发,因此1毫秒的setTimout同样有效。 - George Mauer
有人知道如何在父级加载时获取隐藏的 iframe 的高度吗? 这种方法会返回 0。 - JT...
1
你可能需要文档高度,而不是主体高度。使用jQuery,您可以通过 $(this.contentWindow.document).height() 获取它。 - vpiTriumph
对于旧版本的 IE,可以使用 iframe.contentDocument.body.offsetHeight 来获得正确的结果。请参考 https://dev59.com/rU3Sa4cB1Zd3GeqPuFK0。 - user1087079
3
当我运行这个程序时,我得到了“未捕获的DOM异常:无法访问跨域对象上的属性”document"” 的错误信息。 - Brady Dowling
显示剩余3条评论

53
较简单的方法是使用.contents()来访问iframe。有趣的是,它返回的值与我在原始答案中使用的代码不同,可能是由于body上的填充引起的。
$('iframe').contents().height() + 'is the height'

这是我用于跨域通信的方法,可能过于复杂。首先,我会将jQuery放在iFrame的文档中;这会消耗更多内存,但不应该增加加载时间,因为脚本只需要加载一次。

使用iFrame的jQuery尽早(在DOM准备就绪时)测量iFrame的body高度,然后将URL哈希设置为该高度。在父文档中,添加一个onload事件到iFrame标签,它将查看iFrame的位置并提取所需的值。因为DOM准备就绪事件始终会在文档加载事件之前发生,您可以相当确信该值将在没有竞争条件的情况下正确传递。

换句话说:

...在Help.php中:

var getDocumentHeight = function() {
    if (location.hash === '') { // EDIT: this should prevent the retriggering of onDOMReady
        location.hash = $('body').height(); 
        // at this point the document address will be something like help.php#1552
    }
};
$(getDocumentHeight);

...并且在父文档中:

var getIFrameHeight = function() {
    var iFrame = $('iframe')[0]; // this will return the DOM element
    var strHash = iFrame.contentDocument.location.hash;
    alert(strHash); // will return something like '#1552'
};
$('iframe').bind('load', getIFrameHeight );

嗨,安德鲁,到目前为止你的帮助非常好。contents()函数运行得很好,但我仍然需要使用带宽限制器进行测试。也许你可以使用innerHeight()属性。在使用你的解决方案将高度放入哈希中时,我在FF(OSX)中遇到了问题。FF似乎一直在无限循环中加载getDocumentHeight()函数?Safari没问题。 - FFish
有趣。我添加了一个检查,如果已经有值,则防止设置哈希。如果您正在使用哈希值加载Help.php(例如<iframe src="../Help.php#introduction" />),则可能需要进行微调。 - Andrew
顺便说一下,假设您可以调整高度差异,您可能不需要使用哈希来在 iframe 外部进行通信。如果您确实使用哈希方法,在 Help.php 中放置 sleep(5) 也是测试任何竞争条件的好方法。如果 iframe 在 onDOMReady 之前以某种方式触发了 onLoad,它应该会显示在这里。 - Andrew

26

我发现以下内容适用于Chrome、Firefox和IE11:

$('iframe').load(function () {
    $('iframe').height($('iframe').contents().height());
});

当Iframes内容加载完成后,事件将触发并将IFrames的高度设置为其内容的高度。这仅适用于与IFrame相同域内的页面。


代码可以正常工作,但是为了宽度我必须这样做,否则内容会被裁剪:$('iframe').width($('iframe').contents().width()+30); - Geomorillo
@AminGhaderi 在我的 Firefox 40.0.3 中运行良好。 - mixkat
@mixkat,我通过这个解决方案加载了一个网站到iframe中,但对我来说不起作用!我认为这些解决方案只适用于单个页面,当我们将整个网站加载到iframe中时就不起作用了。 我的英语很糟糕,希望你能理解。 - Amin Ghaderi
@AminGhaderi 如果我理解正确,您希望这适用于站点中的每个页面,但是当然,这不会对所有页面起作用,因为它仅在加载框架时运行一次。因此,它将在第一页上正常工作,但是如果您希望它在更长的页面上工作,则必须再次执行它,要么通过使用新页面重新加载框架,要么通过在流程的某些其他点调用contents.height。 - mixkat

10

现在不使用jQuery来完成这个任务的代码非常简单:

const frame = document.querySelector('iframe')
function syncHeight() {
  this.style.height = `${this.contentWindow.document.body.offsetHeight}px`
}
frame.addEventListener('load', syncHeight)

取消事件绑定:

frame.removeEventListener('load', syncHeight)

5
简洁明了!不幸的是,这对于跨域iframe无效 :( - TimoSolo
3
你运气不太好。我会利用iframe-resizer库来实现这个功能。当然,为了使其正常工作,你需要控制两个域名。 - cchamberlain

6
你不需要在iframe内部使用jquery来做到这一点,但我使用它是因为代码更简单...将此代码放入iframe内的文档中即可。
$(document).ready(function() {
  parent.set_size(this.body.offsetHeight + 5 + "px");  
});

为了消除在较小的窗口上出现的滚动条,已经添加了五个以上的内容。但是这并不完美适用于所有的屏幕尺寸。

同时,将此代码嵌入到您的父文档中。

function set_size(ht)
{
$("#iframeId").css('height',ht);
}

如果您在 iframe 中显示 PDF,则这也不起作用。 - Jason Foglia
1
抱歉,但你的示例 "inside frame" 明显是基于 jQuery 的。 - T-moty

5

这是一个简单的一行代码,它从默认的最小高度开始增加到内容的大小。

<iframe src="http://url.html" onload='javascript:(function(o){o.style.height=o.contentWindow.document.body.scrollHeight+"px";}(this));' style="height:200px;width:100%;border:none;overflow:hidden;"></iframe>


4

这是对我有用的正确答案。

$(document).ready(function () {
        function resizeIframe() {
            if ($('iframe').contents().find('html').height() > 100) {
                $('iframe').height(($('iframe').contents().find('html').height()) + 'px')
            } else {
                setTimeout(function (e) {
                    resizeIframe();
                }, 50);
            }
        }
        resizeIframe();
    });

4

2
这是我的ES6友好的无jQuery版本。
document.querySelector('iframe').addEventListener('load', function() {
    const iframeBody = this.contentWindow.document.body;
    const height = Math.max(iframeBody.scrollHeight, iframeBody.offsetHeight);
    this.style.height = `${height}px`;
});

1
这是一个不需要jQuery的解决方案,可以与iframe内的SPA一起使用。
document.getElementById('iframe-id').addEventListener('load', function () {
  let that = this;
  setTimeout(function () {
    that.style.height = that.contentWindow.document.body.offsetHeight + 'px';
  }, 2000) // if you're having SPA framework (angularjs for example) inside the iframe, some delay is needed for the content to populate
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接