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

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

原文由 nsilva 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 749
2 个回答

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

留言

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

要接收消息,请为消息事件创建一个事件监听器。

 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 可以将其高度发布到“*”,因为我们可能有多个父域。但是,检查传入消息是否来自 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 ,它允许你观察 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 溢出 body 标签,这个函数就可以工作。

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

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

这是IE9版本,很长的IE8版本看这个 答案

如果你确实溢出了身体并且你不能修复你的代码来阻止它,那么使用 offsetHeightscrollHeight 属性 document.documentElement .两者都有利有弊,最好只是测试一下,看看哪个适合你。

其他事宜

其他需要考虑的事情包括,页面上有多个 iFrame,CSS :Checkbox 和 :Hover 事件导致页面大小调整,避免在 iFrames 的 body 和 html 标签中使用 height auto,最后调整窗口大小。

IFrame 调整器库

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

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

这适用于 IE8+。

原文由 David Bradshaw 发布,翻译遵循 CC BY-SA 3.0 许可协议

设置间隔

这只要 (由于浏览器技术的进步而更正,请参阅 David Bradshaw 的回答 使用 iframe 实现此目的的向后兼容方法是使用 setInterval 并自己关注 iframe 的内容。当它改变高度时,您会更新 iframe 的大小。不幸的是,没有这样的事件可以让您轻松收听。

_一个基本示例_,仅当大小已更改的 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);
});

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

跨域问题

您会发现的问题是,由于浏览器安全性,如果 iframe 位于与主页不同的主机上,它不会让您访问 iframe 的内容,因此实际上您无能为力,除非您有办法添加出现在 iframe 中的 html 的任何脚本。

阿贾克斯

其他一些人建议尝试通过 AJAX 使用第三方服务,除非该服务支持这种方法,否则您不太可能让它工作——特别是如果它是最有可能需要的预订服务通过 https/ssl 操作。

看起来您可以完全控制 iframe 内容,您可以选择所有选项,带有 JSONP 的 AJAX 将是一个选项。但是,请注意一个字。如果您的预订系统是多步骤的,您需要确保您有一个设计良好的 UI——可能还有一些历史/片段管理代码——如果您要走 AJAX 路线。这一切都是因为您永远无法判断用户何时会决定在他们的浏览器中向前或向后导航(iframe 会在合理范围内自动处理)。设计良好的 UI 会分散用户的注意力。

跨域通信

如果您可以控制双方(这听起来像您所做的),您还可以使用 window.postMessage 进行跨域通信选项 - 有关更多信息,请参见此处 https://developer.mozilla.org/en-US /docs/DOM/window.postMessage

原文由 Pebbl 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题