1. ホーム
  2. javascript

[解決済み] クロスドメインiframeのリサイズ

2023-05-10 21:16:51

質問

別ドメインのiframeをリサイズするには?

-編集

下にスクロールして、いくつかの解決策をご覧ください。

何時間もコードをハックした後、結論は、iframe 内のすべてのものは、私のドメインで表示されるスクロールバーでさえも、アクセスできない、ということです。多くのテクニックを試しましたが、無駄でした。

時間を節約するために、このルートを通らなくても、クロスドメイン通信のために sendMessages を使用してください。 私が使用しているHTML < 5のプラグインがあります-素敵な例のために一番下まで行ってください :)


過去数日間、私はサイトに iframe を統合しようとしていました。これは、相手側が API を開発している間の短期的な解決策です(数ヶ月かかるかもしれません...)。 そして、これは短期的なソリューションであるため、我々はeasyXDMを使用したいと思いました-私は他のドメインにアクセスできますが、そのままではp3pヘッダーを追加するように頼むのは難しいです....

3つのiframe

私が見つけた最も近い解決策は3つのiframeでしたが、それはクロームとサファリの精神に行くので、私はそれを使用することはできません。

クロームで開く

http://css-tricks.com/examples/iFrameResize/crossdomain.php#frameId=frame-one&高さ=1179

スクロールバーを計測する

私は、フォームのサイズを変更しようとするためにscrollheightを使用する方法についての別の記事を見つけました。理論的にはそれはうまく動作しますが、私はiframeのスクロール高さを使用して適切にそれを適用できませんでした...。

document.body.scrollHeight

これは明らかにボディの高さを使用しています(これらのプロパティにアクセスすることはできません 100%は、X-domainsのドキュメントの高さではなく、クライアントのディスプレイのキャンバスに基づきます)。

私はiframeの高さを取得するためにjqueryを使用してみました。

$('#frameId').Height()

$('#frameId').clientHeight

$('#frameId').scrollHeight

は、クロームとIEで異なる値を返すか、まったく意味をなしません。 問題は、フレーム内のすべてのものが拒否されることです - スクロールバーでさえも。

計算されたスタイル

しかし、私はiframeのクロームで要素と検査すると、それは私にiframe内のドキュメントの寸法をブラッディ表示されます(iframe.heighを得るためにjquery x -ドメインを使用 - アクセス拒否)。 計算されたCSSには何もありません

さて、クロームはどのようにこれを計算するのでしょうか? (編集 - ブラウザは内蔵のレンダリングエンジンを使ってページを再レンダリングし、これらの設定をすべて計算します - しかしクロスドメイン詐欺を防ぐためにどこにも添付されていません。)

HTML4

HTML4.xの仕様書を読むと、document.elementで読み取り専用の値を公開するように書かれていますが、jqueryでアクセス拒否されています。

プロキシフレーム

私は、サイトをプロキシングして計算するというルートを辿りましたが、これは問題ありません。しかし、ユーザーが iframe を通してログインすると、プロキシは実際のコンテンツではなくログインページを取得します。また、ページを 2 回呼び出すことは許容されない人もいます。

http://www.codeproject.com/KB/aspnet/asproxy.aspx

http://www.johnchapman.name/aspnet-proxy-page-cross-domain-requests-from-ajax-and-javascript/

ページを再レンダリングする

私はここまでやりませんでしたが、ソースを見て、ソースファイルに基づいてページを再レンダリングするjscriptエンジンがあります。 しかし、それらのjscriptをハックする必要があります... そしてそれは営利団体にとって理想的な状況ではありません... 。 また、純粋なJavaアプレットやサーバーサイドレンダリングを使用するものもあります。

http://en.wikipedia.org/wiki/Server-side_JavaScript

http://htmlunit.sourceforge.net/ <-java not jscript

http://maxq.tigris.org/


編集 09-2013 アップデイト

これらはすべてHTML5ソケットで行うことができます。しかし、easyXDMは、非HTML5の苦情ページに対する素晴らしいフォールバックです。

解決策1 非常に素晴らしい解決策です。

easyXDMの使用

サーバ上で、以下のような形式のページをセットアップします。

<html>
<head>
<script src="scripts/easyXDM.js" type="text/javascript"></script>
<script type="text/javascript" language="javascript">

    var transport = new easyXDM.Socket(/** The configuration */{
    remote: "http://www.OTHERDOMAIN.com/resize_intermediate.html?url=testpages/resized_iframe_1.html",

    //ID of the element to attach the inline frame to
    container: "embedded",
    onMessage: function (message, origin) {
        var settings = message.split(",");
        //Use jquery on a masterpage.
        //$('iframe').height(settings[0]);
        //$('iframe').width(settings[1]);

        //The normal solution without jquery if not using any complex pages (default)
        this.container.getElementsByTagName("iframe")[0].style.height = settings[0];
        this.container.getElementsByTagName("iframe")[0].style.width = settings[1];
    }
});

</script>

</head>

<body>
    <div id="embedded"></div>
</body>

そして、呼び出し側のドメインでは、同じ場所にintermiedate_frame htmlとeasyXDM.jsを追加する必要があるだけです。親フォルダのように - そして、相対的なディレクトリまたはあなただけのために含まれるフォルダにアクセスすることができます。

オプション1

すべてのページにスクリプトを追加したくない場合は、オプション2を見てください!

そうすれば、リサイズを必要とする各ページの末尾に単純なjscriptを追加するだけでよいのです。これらのページのそれぞれにeasyxdmを含める必要はありません。

 <script type="text/javascript">
            window.onload = function(){ parent.socket.postMessage( (parseInt(document.body.clientHeight)) + "," + ( document.body.clientWidth ) );  };
        </script>

送信されるパラメータを変更しました。もし、幅が正しく動作するようにしたいのであれば、他のドメインのページでは、どこか似たようなスタイルでページの幅を含める必要があります。

<style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                background-color: rgb(75,0,85);
                color:white;
                width:660px
            }
            a {
            color:white;
            visited:white;
            }
        </style>

これは私にとっては素晴らしい動作です。幅が含まれていない場合、フレームは少し奇妙な動作をし、それが何であるかを推測しようとするようです。

オプション 2

中間フレームを変更し、変更をポーリングする

中間フレームは次のようなものになります。

    <!doctype html>
<html>
    <head>

        <title>Frame</title>
        <script type="text/javascript" src="easyXDM.js">
        </script>
        <script type="text/javascript">
            var iframe;
            var socket = new easyXDM.Socket({
                //This is a fallback- not needed in many cases
                swf: "easyxdm.swf",
                onReady: function(){
                    iframe = document.createElement("iframe");
                    iframe.frameBorder = 0;
                    document.body.appendChild(iframe);
                    iframe.src = "THE HOST FRAME";
            iframe.onchange = messageBack();

                },
                onMessage: function(url, origin){
                    iframe.src = url;
                }
            });

            //Probe child.frame for dimensions.
            function messageBack(){
                socket.postMessage ( iframe.contentDocument.body.clientHeight + "," + iframe.contentDocument.body.clientWidth); 
            };

            //Poll for changes on children every 500ms.
            setInterval("messageBack()",500); 

        </script>
        <style type="text/css">
            html, body {
                overflow: hidden;
                margin: 0px;
                padding: 0px;
                width: 100%;
                height: 100%;
            }

            iframe {
                width: 100%;
                height: 100%;
                border: 0px;
            }
        </style>
    </head>
    <body>

    </body>
</html>

500msごとにメッセージを送信するのではなく、サイズが変更されたかどうかをチェックし、サイズが変更された場合のみ送信するようにすれば、より効率的な間隔になるでしょう。このチェックを実装すれば、ポーリングは50ミリ秒まで変更可能です。


ブラウザをまたいで動作し、高速です。素晴らしいデバッグ機能!

Excellent Work to  Sean Kinsey  who made the script!!!


解決策2 (動作はしますが、あまりよくありません)

基本的には、相手ドメインと相互に合意している場合は、sendmessageを処理するためのライブラリを追加することができます。 もし、他のドメインにアクセスできない場合は...。もっと多くのハックを探し続けてください - なぜなら、私はこれらを見つけることができなかったし、完全に正当化することもできなかったからです。

というわけで、他ドメインではこれらをHeadタグに含めることになります。

<script src="scripts/jquery-1.5.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery.postmessage.min.js" type="text/javascript"></script>
<script src="scripts/club.js" type="text/javascript"></script>

club.jsには、リサイズのためのカスタムコールとincludes.があります。

 $(document).ready(function () {   
    var parent_url = decodeURIComponent( document.location.hash.replace( /^#/, '' ) ),link;
//Add source url hash to each url to authorise callback when navigating inside the frame.Without this clicking any links will break the communication and no messages will be received
$('a[href]').each(function(){ 
     this.href = this.href + document.location.hash ;
});
//Get the dimensions and send back to calling page.
var h1 = document.body.scrollHeight;
var w1 = document.body.scrollWidth;
$.postMessage({ if_height: h1, if_width: w1 }, parent_url, parent );
  });

そして、あなたのページはすべてのハードワークを行い、素敵なスクリプトを持っています...

  //This is almost like request.querystring used to get the iframe data
  function querySt(param, e) {
         gy = e.split("&");
         for (i = 0; i < gy.length; i++) {
             ft = gy[i].split("=");
             if (ft[0] == param) {
                 return ft[1];
             }
         }
     }


     $(function () {
         // Keep track of the iframe dimensions.
         var if_height;
         var if_width;
         // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
         // passed via query string or hard coded into the child page, it depends on your needs).
         src = 'http://www.OTHERDOAMIN.co.uk/OTHERSTARTPAGE.htm' + '#' + encodeURIComponent(document.location.href),
         // Append the Iframe into the DOM.
         iframe = $('<iframe " src="' + src + '" width="100%" height="100%" scrolling="no" frameborder="0"><\/iframe>').appendTo('#iframe');

         // Setup a callback to handle the dispatched MessageEvent event. In cases where
         // window.postMessage is supported, the passed event will have .data, .origin and
         // .source properties. Otherwise, this will only have the .data property.
         $.receiveMessage(function (e) {
             // Get the height from the passsed data.
             //var h = Number(e.data.replace(/.*if_height=(\d+)(?:&|$)/, '$1'));
             var h = querySt("if_height", e.data);
             var w = querySt("if_width", e.data);


             if (!isNaN(h) && h > 0 && h !== if_height) {
                 // Height has changed, update the iframe.
                 iframe.height(if_height = h);
             }
             if (!isNaN(w) && w > 0 && w !== if_width) {
                 // Height has changed, update the iframe.
                 iframe.width(if_width = w);
             }
             //For debugging only really- can remove the next line if you want
             $('body').prepend("Recieved" + h + "hX" + w + "w .. ");
             // An optional origin URL (Ignored where window.postMessage is unsupported).
           //Here you must put the other domain.com name only! This is like an authentication to prevent spoofing and xss attacks! 
         }, 'http://www.OTHERDOMAIN.co.uk');
     });


オプション3

クロスドメイン iFrame のサイズ変更を管理するための小さな JS ライブラリです。iFrame に JavaScript が少し含まれている必要がありますが、これは 2.8k (765 bytes Gzipped) のネイティブ JS で、依存関係がなく、親ページから呼び出されるまで何も行いません。これはつまり、他の人のシステムの素敵なゲストであるということです。

このコードは DOM の変更を検出するために mutationObserver を使用し、iFrame がコンテンツに合わせた大きさを保つように、resize イベントにも目を光らせています。IE8+ で動作します。

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

どのように解決するのですか?

あるドメインのドキュメントから別のドメインのドキュメントに計算された高さを取得する必要があるため、これにはクロスドメインメッセージングを使用する以外の方法はないということです。

ですから、これを postMessage を使うか (すべてのモダンブラウザで動作)、5 分かけて リサイズ iframe の例 を5分かけて適応させることもできます。

相手は本当にいくつかのファイルを自分のドメインにコピーし、1行のコードを自分のドキュメントに追加するだけでよいのです。