Iframe Auto Adjust Height при изменении содержимого

У меня есть 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;
}

Если кто-нибудь может мне помочь, я буду очень благодарен!

Ответ 1

setInterval

only (исправлено из-за успехов в технологии браузера, см. ответ Дэвида Брэдшоу), совместимый с обратной стороной способ достижения этого с помощью 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, если он находится на другом хосте на главной странице, поэтому на самом деле вы ничего не можете сделать, если у вас нет способ добавления любого script в html, который появляется в iframe.

Ajax

Некоторые другие предлагают использовать сторонний сервис через AJAX, если служба не поддерживает этот метод, маловероятно, что вы сможете заставить его работать - особенно если это заказ служба, которая, скорее всего, будет работать через https/ssl.

Как оказалось, у вас есть полный контроль над содержимым iframe, у вас есть полные возможности для вас, AJAX с JSONP будет вариантом. Однако одно слово предупреждения. Если ваша система бронирования многоэтапная, вам необходимо убедиться, что у вас есть хорошо разработанный интерфейс - и, возможно, какой-то код управления историей/фрагментом - если вы хотите спуститься по маршруту AJAX. Все, потому что вы никогда не сможете сказать, когда пользователь решит перемещаться вперед или назад в своем браузере (который iframe автоматически обрабатывал, в пределах разумного). Хорошо спроектированный пользовательский интерфейс может отвлечь пользователей от этого.

междоменная связь

Если у вас есть контроль над обеими сторонами (что похоже на то, что вы делаете), у вас также есть опция перекрестного домена, используя window.postMessage - см. здесь дополнительную информацию https://developer.mozilla.org/en-US/docs/DOM/window.postMessage

Ответ 2

В современном браузере и частично в 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');

Чтобы получить сообщение, создайте событие события для события сообщения.

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

Другой прогресс в более современных браузерах 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 см. этот ответ.

Если вы переполняете тело, и вы не можете исправить свой код, чтобы остановить это, то использование лучших offsetHeight или scrollHeight свойств document.documentElement. У обоих есть плюсы и минусы, и лучше всего проверить их и посмотреть, что работает для вас.

Другие вопросы

Другие вещи, которые следует учитывать, включают в себя более одного iFrame на странице CSS: Checkbox и: события Hover, вызывающие изменение размера страницы, избегая использования высоты auto в тегах тела iFrames и html-тегах и, наконец, изменяя размер окна.

Библиотека фильтров IFrame

Я обернул все это в простой бесплатной библиотеке без зависимостей, которая также предоставляет некоторые дополнительные функции, которые здесь не обсуждаются.

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

Это работает с IE8 +.

Ответ 3

Я написал этот script, и он отлично работает для меня. Не стесняйтесь использовать его!

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>

Ответ 4

используйте этот 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';
    });
  }
});

Примечание. используйте его на веб-сервере.