web-dev-qa-db-ja.com

コンテンツの変更に応じてiframeで高さを自動調整

次のリンクからわかるように、iframeを持っています;-

http://one2onecars.com

Iframeは、画面の中央にあるオンライン予約です。私が抱えている問題は、ページの読み込み時にiframeの高さは問題ありませんが、ページコンテンツの調整時に何らかの方法で高さを自動調整する必要があることです。たとえば、オンライン予約で郵便番号検索を行うと、ドロップダウンメニューが作成され、[次のステップ]ボタンが表示されなくなります。

発生する必要があるのは、オンライン予約のコンテンツが変更されると、iframeは他のページをロードしていないため、iframeの新しい高さに(動的に)自動調整することです。

私はjqueryを使用してこの問題を解決しようといくつかの異なるスクリプトを試しましたが、ページが最初にロードされたときにiframeの高さを自動調整し、notの内容としてのみ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;
}

誰かがこれで私を助けることができるなら、私は大歓迎です!

19
nsilva

setInterval

の のみ (ブラウザ技術の進歩により修正、 David Bradshaw's answer )を参照してください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に表示されるHTMLへのスクリプト。

ajax

他の人の中には、AJAX経由でサードパーティのサービスを使用することを提案している人もいますが、サービスがこのメソッドをサポートしていない限り、特に必要な可能性が最も高い予約サービスの場合、このメソッドを使用することはできませんhttps/sslで操作する。

Iframeコンテンツを完全に制御できるように見えるため、完全なオプションを利用できます。AJAXがオプションになります。ただし、警告が1つあります。予約システムがマルチステップの場合AJAXルートを下る場合は、適切に設計されたUI(およびおそらく履歴/フラグメント管理コード)があることを確認する必要があります。ユーザーはブラウザ内を前後に移動することを決定します(iframeが自動的に処理します)。適切に設計されたUIにより、ユーザーはこれを実行できなくなります。

クロスドメイン通信

両方のコントロールがある場合(あなたのように聞こえます)window.postMessageを使用したクロスドメイン通信オプションもあります-詳細についてはこちらを参照してください https://developer.mozilla.org/en -US/docs/DOM/window.postMessage

26
Pebbl

最新のブラウザと一部の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

より近代的なブラウザのもう1つの利点は MutationObserver です。これにより、DOMの変更を監視できます。そのため、setIntervalで絶えずポーリングする必要なく、iFrameのサイズに影響を与える可能性のある変更を検出できるようになりました。

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の正確な高さを取得するのはそれほど簡単ではありません。チェックできる6つの異なるプロパティがあり、どれも常に正しい答えを出すことができないためです。私が思いついた最良の解決策は、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バージョンについては、これを参照してください answer

本文をオーバーフローさせてコードを修正してこれを停止できない場合は、document.documentElementoffsetHeightまたはscrollHeightプロパティを使用するのが最適なオプションです。どちらにも長所と短所があり、両方をテストして、どちらが適切かを確認するのが最善です。

その他の問題

その他の考慮事項としては、ページに複数のiFrameを配置すること、CSS:Checkboxおよび:Hoverイベントによりページのサイズ変更を行い、iFrameの本文およびHTMLタグでの高さ自動の使用を回避し、最後にウィンドウのサイズを変更します。

IFrame Resizerライブラリ

このすべてを単純な依存関係のない無料のライブラリにまとめました。このライブラリには、ここで説明していない追加機能もいくつか用意されています。

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

これはIE8 +で機能します。

20
David Bradshaw

このスクリプトを作成しましたが、私にとっては完璧に機能しています。気軽に使用してください!

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>
7
Bram Verstraten

次のスクリプトを使用します。

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

注: Webサーバーで使用します。

0
Jai