iframe在内容更改时自动调整高度

时间:2013-01-15 08:59:30

标签: javascript jquery html iframe

我可以在以下链接中看到iframe; -

http://one2onecars.com

iframe是屏幕中央的在线预订。我遇到的问题是虽然iframe的高度在页面加载时是可以的,但是我需要它以某种方式在页面内容调整时自动调整高度。例如,如果我在在线预订中进行邮政编码搜索,则会创建一个下拉菜单,然后使“下一步”按钮无法查看。

我需要做的是,当在线预订的内容发生变化时,iframe会自动调整到iframe的新高度(动态),因为它没有加载任何其他页面。

我已尝试使用jquery尝试解决此问题的几个不同的脚本,但它们似乎只是在页面首次加载时自动调整iframe的高度,而不是作为iframe的内容变化。

这甚至可以吗?

目前我的代码目前设定的高度为: -

        <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;
}

如果有人可以帮助我,我将不胜感激!

4 个答案:

答案 0 :(得分:25)

<强>的setInterval

only (由于浏览器技术的进步而更正,请参阅David Bradshaw's answer向后兼容的方法,以使用iframe实现此目的是使用{{1并亲自关注iframe的内容。当它更改其高度时,您将更新iframe的大小。没有这样的事件,你可以倾听,这将很容易让它变得容易。

一个基本示例,只有在大小已更改的iframe内容是主页面流的一部分时,此方法才有效。如果元素浮动或定位,则必须专门定位它们以寻找高度变化。

setInterval

显然,根据您的需要,您可以修改此代码的透视图,使其从iframe开始工作,而不是期望成为主页的一部分。

跨域问题

你会发现问题是,由于浏览器的安全性,它不会让你访问iframe的内容,如果它在主页的不同主机上,所以除非你有一个,否则你实际上没有任何东西可以做将任何脚本添加到iframe中显示的html的方法。

<强> AJAX

其他一些人建议尝试通过AJAX使用第三方服务,除非服务支持这种方法,否则你很可能无法使用它 - 特别是如果它是预订最有可能需要通过https / ssl运行的服务。

由于您可以完全控制iframe内容,因此您可以选择完整的选项,使用带有JSONP的AJAX。但是,一句警告。如果你的预订系统是多步的,你需要确保你有一个设计良好的用户界面 - 可能还有一些历史/片段管理代码 - 如果你要沿着AJAX路线走下去。所有这些都是因为你永远无法分辨用户何时决定在他们的浏览器中向前或向后导航(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); }); 进行跨域通信选项 - 有关详细信息,请参阅此处https://developer.mozilla.org/en-US/docs/DOM/window.postMessage

答案 1 :(得分:20)

现代浏览器和部分IE8都有一些新功能,使这项任务比以前更容易。

PostMessage的

postMessage API提供了一种在iFrame与其父级之间进行通信的简单方法。

要向父页面发送消息,请按以下方式调用它。

parent.postMessage('Hello parent','http://origin-domain.com');

在另一个方向,我们可以使用以下代码将消息发送到iFrame。

var iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello my child', 'http://remote-domain.com:8080');

要接收消息,请为消息事件创建事件listerner。

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);

这些示例使用origin属性来限制发送消息的位置并检查消息的来源。可以指定*以允许发送到任何域,在某些情况下,您可能希望接受来自任何域的邮件。但是,如果您这样做,您需要考虑安全隐患,并对传入的消息实施您自己的检查,以确保它包含您的期望。在这种情况下,iframe可以将其高度发布到&#39; *&#39;,因为我们可能有多个父域。但是,检查传入的消息来自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

更现代的broswers的另一个进步是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();
}

计算出准确的高度

获得iFrame的准确高度并不像应该的那样简单,因为您可以选择六种不同的属性,但是没有一种能够给出正确的答案。我提出的最佳解决方案是,只要您不使用CSS来溢出正文标记,此函数就可以正常工作。

function getIFrameHeight(){
    function getComputedBodyStyle(prop) {
        return parseInt(
            document.defaultView.getComputedStyle(document.body, null),
            10
        );
    }

    return document.body.offsetHeight +
        getComputedBodyStyle('marginTop') +
        getComputedBodyStyle('marginBottom');
}

这是IE9版本,对于很长的IE8版本,请参阅此answer

如果您确实溢出了正文并且无法修复代码以阻止此操作,那么使用offsetHeightscrollHeight document.documentElement属性是最佳选择。两者都有利弊,最好只测试两者,看看哪些适合你。

其他问题

要考虑的其他事项包括:在页面上有多个iFrame,CSS:Checkbox和:导致页面调整大小的悬停事件,避免在iFrame中使用高度自动&#39; body和html标签,最后是调整大小的窗口。

IFrame Resizer Library

我已将所有这些包装在一个简单的无需依赖的库中,它还提供了一些此处未讨论的额外功能。

https://github.com/davidjbradshaw/iframe-resizer

这适用于IE8 +。

答案 2 :(得分:7)

我写了这个脚本,它对我来说非常合适。随意使用它!

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");
        }
    }
}

您可以在循环内调用该函数:

<script>
jQuery(document).ready(function() {
    // Try to change the iframe size every 2 seconds
    setInterval(function() {
        ResizeIframeFromParent('iframeid');
    }, 2000);
});
</script>

答案 3 :(得分:0)

使用此脚本:

$(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';
    });
  }
});

注意:在网络服务器上使用它。