Javascript iframe随着内容的变化自动调整高度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14334154/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iframe Auto Adjust Height as content changes
提问by nsilva
I have an iframe as you can see on the following link;-
您可以在以下链接中看到我有一个 iframe;-
The iframe is the online booking in the centre of the screen. The problem I have is that although the height of the iframe is okay as the page loads, I need it to somehow auto adjust the height as the page content adjusts. For example, if I do a postcode search in the online booking it creates a dropdown menu and then makes the 'Next Step' button not viewable.
iframe 是屏幕中央的在线预订。我遇到的问题是,虽然 iframe 的高度在页面加载时没问题,但我需要它在页面内容调整时以某种方式自动调整高度。例如,如果我在在线预订中进行邮政编码搜索,它会创建一个下拉菜单,然后使“下一步”按钮不可见。
What I need to happen is that when the content of the online booking changes, the iframe auto adjusts to the new height of the iframe (dynamically) as it is not loading any other pages.
我需要做的是,当在线预订的内容发生变化时,iframe 会自动调整到 iframe 的新高度(动态),因为它没有加载任何其他页面。
I have tried several different scripts using jquery to try resolving this issue, but they all only seem to auto adjust the height of the iframe when the page first loads and notas the contents of the iframe changes.
我已经尝试使用 jquery 尝试了几种不同的脚本来尝试解决这个问题,但它们似乎都只在页面首次加载时自动调整 iframe 的高度,而不是随着 iframe 的内容发生变化。
Is this even possible to do?
这甚至可以做到吗?
The code I have at the moment is with a set height at the moment:-
我目前拥有的代码目前具有设定的高度:-
<div id="main-online-booking">
<iframe id="main-online-frame" class="booking-dimensions" src="http://www.marandy.com/one2oneob/login-guest.php" scrolling="no" frameborder="0"></iframe>
</div>
#main-online-booking {
height: 488px;
border-bottom: 6px #939393 solid;
border-left: 6px #939393 solid;
border-right: 6px #939393 solid;
z-index: 4;
background-color: #fff;
}
.booking-dimensions {
width: 620px;
height: 488px;
}
If anybody can help me with this I would be much appreciated!
如果有人能帮我解决这个问题,我将不胜感激!
回答by Pebbl
setInterval
设置间隔
The only(corrected due to advances in browser tech, see David Bradshaw's answer)backwards compatible way to achieve this with an iframe is to use setIntervaland keep an eye on the iframe's content yourself. When it changes its height, you update the size of the iframe. There is no such event you can listen out for that will make it easy unfortunately.
这 只要(由于浏览器技术的进步而更正,请参阅David Bradshaw 的回答)使用 iframe 实现此目的的向后兼容方法是自己使用setInterval并密切关注 iframe 的内容。当它改变高度时,你会更新 iframe 的大小。不幸的是,没有这样的事件你可以听出来,这会让事情变得容易。
A basic example, this will only work if the iframe content that has changed in size is part of the main page flow. If the elements are floated or positioned then you will have to target them specifically to look for height changes.
一个基本示例,这仅在大小已更改的 iframe 内容是主页流的一部分时才有效。如果元素是浮动的或定位的,那么您必须专门针对它们来查找高度变化。
jQuery(function($){
var lastHeight = 0, curHeight = 0, $frame = $('iframe:eq(0)');
setInterval(function(){
curHeight = $frame.contents().find('body').height();
if ( curHeight != lastHeight ) {
$frame.css('height', (lastHeight = curHeight) + 'px' );
}
},500);
});
Obviously depending on what you want you can modify the perspective of this code so that it works from the iframe, on itself, rather than expecting to be part of the main page.
显然,根据您的需要,您可以修改此代码的透视图,使其从 iframe 本身开始工作,而不是期望成为主页的一部分。
cross-domain issue
跨域问题
The problem you will find is that due to browser security it wont let you access the content of the iframe if it is on a different host to the main page, so there isn't actually anything you can do unless you have a way of adding any script to the html that appears in the iframe.
您会发现的问题是,由于浏览器的安全性,如果 iframe 位于与主页不同的主机上,它不会让您访问 iframe 的内容,因此除非您有添加的方法,否则实际上您无能为力出现在 iframe 中的 html 的任何脚本。
ajax
阿贾克斯
Some others are suggesting trying to use the third-party service via AJAX, unless the service supports this method it will be very unlikely you'll be able to get it to work -- especially if it is a booking service that will most likely need to operate over https/ssl.
其他一些人建议尝试通过 AJAX 使用第三方服务,除非该服务支持这种方法,否则您不太可能使其工作 - 特别是如果它是最有可能需要的预订服务通过 https/ssl 操作。
As it appears you have full control over the iframe content, you have full options open to you, AJAX with JSONP would be an option. However, one word of warning. If your booking system is multistepped you need to make sure you have a well designed UI -- and possibly some history/fragment management code -- if you are to go down the AJAX route. All because you can never tell when a user will decide to navigate forward or back in their browser (which an iframe would automatically handle, within reason). A well designed UI can detract users from doing this.
看起来您可以完全控制 iframe 内容,您可以选择所有选项,AJAX 和 JSONP 将是一个选项。然而,一个警告。如果您的预订系统是多步骤的,您需要确保您有一个设计良好的 UI —— 可能还有一些历史/片段管理代码 —— 如果你要沿着 AJAX 路线走下去。这一切都是因为您永远无法判断用户何时决定在浏览器中向前或向后导航(iframe 会在合理范围内自动处理)。设计良好的用户界面可能会影响用户这样做。
cross-domain communication
跨域通信
If you have control of both sides (which it sounds like you do) you also have the cross domain communication option using window.postMessage- see here for more information https://developer.mozilla.org/en-US/docs/DOM/window.postMessage
如果您可以控制双方(听起来像您这样做),您还可以使用跨域通信选项window.postMessage- 请参阅此处了解更多信息https://developer.mozilla.org/en-US/docs/DOM/window。留言
回答by David Bradshaw
Modern browser and in part IE8 have some new features that make this task easier than it use to be.
现代浏览器和部分 IE8 具有一些新功能,使这项任务比以前更容易。
PostMessage
留言
The postMessageAPI provides a simple method for comunicating between an iFrame and it's parent.
所述的postMessageAPI提供了一个iFrame和它的父之间comunicating的简单方法。
To send a message to the parent page you call it as follows.
要向父页面发送消息,请按如下方式调用它。
parent.postMessage('Hello parent','http://origin-domain.com');
In the other direction we can send the message to the iFrame with the following code.
在另一个方向,我们可以使用以下代码将消息发送到 iFrame。
var iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello my child', 'http://remote-domain.com:8080');
To recevie a message create an event listerner for the message event.
要接收消息,请为消息事件创建一个事件侦听器。
function receiveMessage(event)
{
if (event.origin !== "http://remote-domain.com:8080")
return;
console.log(event.data);
}
if ('addEventListener' in window){
window.addEventListener('message', receiveMessage, false);
} else if ('attachEvent' in window){ //IE
window.attachEvent('onmessage', receiveMessage);
These examples uses the origin property to limit where the message is sent to and to check where it came from. It is possible to specify *to allow sending to any domain and you may in some cases you may want to accept messages from any domain. However, if you do this you need to consider the security implications and implement your own checks on the incoming message to ensure it contains what your expecting. In this case the iframe can post it's height to '*', as we might have more than one parent domain. However, it's a good idea to check incoming messages are from the iFrame.
这些示例使用 origin 属性来限制消息发送到的位置并检查消息的来源。可以指定*允许发送到任何域,并且在某些情况下您可能希望接受来自任何域的邮件。但是,如果您这样做,您需要考虑安全隐患并对传入的消息实施您自己的检查以确保它包含您期望的内容。在这种情况下,iframe 可以将其高度发布到“*”,因为我们可能有多个父域。但是,检查传入消息是否来自 iFrame 是个好主意。
function isMessageFromIFrame(event,iframe){
var
origin = event.origin,
src = iframe.src;
if ((''+origin !== 'null') && (origin !== src.substr(0,origin.length))) {
throw new Error(
'Unexpect message received from: ' + origin +
' for ' + iframe.id + '. Message was: ' + event.data
);
}
return true;
}
MutationObserver
突变观察者
The other advance in more modern broswers is MutationObserverwhich allows you to watch for changes in the DOM; so it is now possible to detect changes that could effect the size of the iFrame without having to constantly poll with setInterval.
更现代的浏览器的另一个进步是MutationObserver,它允许您观察 DOM 中的变化;因此现在可以检测可能影响 iFrame 大小的更改,而无需经常使用 setInterval 进行轮询。
function createMutationObserver(){
var
target = document.querySelector('body'),
config = {
attributes : true,
attributeOldValue : false,
characterData : true,
characterDataOldValue : false,
childList : true,
subtree : true
},
observer = new MutationObserver(function(mutations) {
parent.postMessage('[iframeResize]'+document.body.offsetHeight,'*');
});
log('Setup MutationObserver');
observer.observe(target, config);
}
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
if (MutationObserver){
createMutationObserver();
}
Working out an accurate height
计算出准确的高度
Getting an accurate height for the iFrame is not as simple as it should be, as you have a choice of six different properties that you can check and none of them give a constantly right answer. The best solution I've come up with is this function that works so long as you don't use CSS to overflow the body tag.
获得 iFrame 的准确高度并不像它应该的那么简单,因为您可以选择六个不同的属性来检查,但没有一个总是给出正确的答案。我想出的最佳解决方案是只要您不使用 CSS 溢出 body 标签,这个函数就可以工作。
function getIFrameHeight(){
function getComputedBodyStyle(prop) {
return parseInt(
document.defaultView.getComputedStyle(document.body, null),
10
);
}
return document.body.offsetHeight +
getComputedBodyStyle('marginTop') +
getComputedBodyStyle('marginBottom');
}
This is the IE9 version, for the much long IE8 version see this answer.
这是 IE9 版本,对于很长的 IE8 版本,请参阅此答案。
If you do overflow the body and you can't fix your code to stop this, then using either the offsetHeightor scrollHeightproperties of document.documentElementare your best options. Both have pros and cons and it best just to test both and see which works for you.
如果确实溢出了主体并且无法修复代码以阻止这种情况发生,那么使用offsetHeight或scrollHeight属性document.documentElement是您的最佳选择。两者都有优点和缺点,最好只是测试两者,看看哪个适合你。
Other issues
其他事宜
Other things to consider include, having more than one iFrame on the page, CSS :Checkbox and :Hover events causing page resize, avoiding the use of height auto in the iFrames' body and html tags and lastly the window being resized.
其他需要考虑的事情包括,页面上有多个 iFrame,CSS :Checkbox 和 :Hover 事件导致页面调整大小,避免在 iFrame 的 body 和 html 标签中使用自动高度,最后调整窗口大小。
IFrame Resizer Library
IFrame Resizer 库
I've wrapped all this up in a simple dependancy free library, that also provides some extra functions not discussed here.
我将所有这些都打包在一个简单的无依赖库中,它还提供了一些这里没有讨论的额外功能。
https://github.com/davidjbradshaw/iframe-resizer
https://github.com/davidjbradshaw/iframe-resizer
This works with IE8+.
这适用于 IE8+。
回答by Bram Verstraten
I wrote this script and it's working perfectly for me. Feel free to use it!
我写了这个脚本,它非常适合我。随意使用它!
function ResizeIframeFromParent(id) {
if (jQuery('#'+id).length > 0) {
var window = document.getElementById(id).contentWindow;
var prevheight = jQuery('#'+id).attr('height');
var newheight = Math.max( window.document.body.scrollHeight, window.document.body.offsetHeight, window.document.documentElement.clientHeight, window.document.documentElement.scrollHeight, window.document.documentElement.offsetHeight );
if (newheight != prevheight && newheight > 0) {
jQuery('#'+id).attr('height', newheight);
console.log("Adjusting iframe height for "+id+": " +prevheight+"px => "+newheight+"px");
}
}
}
You can call the function inside a loop:
您可以在循环内调用该函数:
<script>
jQuery(document).ready(function() {
// Try to change the iframe size every 2 seconds
setInterval(function() {
ResizeIframeFromParent('iframeid');
}, 2000);
});
</script>
回答by Jai
use this script:
使用这个脚本:
$(document).ready(function () {
// Set specific variable to represent all iframe tags.
var iFrames = document.getElementsByTagName('iframe');
// Resize heights.
function iResize() {
// Iterate through all iframes in the page.
for (var i = 0, j = iFrames.length; i < j; i++) {
// Set inline style to equal the body height of the iframed content.
iFrames[i].style.height = iFrames[i].contentWindow.document.body.offsetHeight + 'px';
}
}
// Check if browser is Safari or Opera.
if ($.browser.safari || $.browser.opera) {
// Start timer when loaded.
$('iframe').load(function () {
setTimeout(iResize, 0);
});
// Safari and Opera need a kick-start.
for (var i = 0, j = iFrames.length; i < j; i++) {
var iSource = iFrames[i].src;
iFrames[i].src = '';
iFrames[i].src = iSource;
}
} else {
// For other good browsers.
$('iframe').load(function () {
// Set inline style to equal the body height of the iframed content.
this.style.height = this.contentWindow.document.body.offsetHeight + 'px';
});
}
});
Note :use it on webserver.
注意:在网络服务器上使用它。

