22

postMessage を使用して正しい高さにサイズ変更されたクロスドメイン iframe を持つ Web サイトで作業しています。私が抱えている唯一の問題は、どの iframe がどの高さかを特定することです。私が現在設定している方法は、1 つの iframe がその高さを親に送信すると、すべての iframe の高さが変更されるというものです。

親:

var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

eventer(messageEvent, function(e) {
    $('iframe').height(e.data);
}, false);

iframe:

var updateHeight = function() {
    if(window.parent) {
        window.parent.postMessage($('.widget').outerHeight(), '*');
    }
};

messageイベントを送信した iframe を特定する方法はありますか?

4

6 に答える 6

23

はい、実行した IFRAME を特定できますpostMessage。さまざまな状況があります。

  • ソース IFRAME には、メッセージを受信するウィンドウと同じオリジン URL (例: ) があります。IFRAME は次を使用して識別されます。http://example.com/

    myIFRAME.contentWindow == event.source

  • ソース IFRAME には、親 HTML ページへの同じオリジンの相対 URL (例: ) があります。IFRAME は次を使用して識別されます。/myApp/myPage.html

    myIFRAME.contentWindow == event.source.parent

  • ソース IFRAME には、メッセージを受信するページ (例 ) とは異なるクロスオリジン URL (例) があります。上記の方法は機能しません (比較は常にエラーにつながるプロパティへのアクセスです)。元のドメインで。http://example.com/http://example.org/falseevent.sourceAccess Denied

    myIFRAME.src.indexOf(event.origin)==0

これら 3 つの異なる状況を管理するために、私は以下を使用しています。

var sourceFrame = null; // this is the IFRAME which send the postMessage
var myFrames = document.getElementsByTagName("IFRAME");
var eventSource = event.source; // event is the event raised by the postMessage
var eventOrigin = event.origin; // origin domain, e.g. http://example.com

// detect the source for IFRAMEs with same-origin URL
for (var i=0; i<myFrames.length; i++) {
    var f = myFrames[i];
    if (f.contentWindow==eventSource || // for absolute URLs
        f.contentWindow==eventSource.parent) { // for relative URLs
        sourceFrame = f;
        break;
    }
}

// detect the source for IFRAMEs with cross-origin URL (because accessing/comparing event.source properties is not allowed for cross-origin URL)
if (sourceFrame==null) {
    for (var i=0; i<myFrames.length; i++) {
        if (myFrames[i].src.indexOf(eventOrigin)==0) {
            sourceFrame = myFrames[i];
            break;
        }
    }
}

クロスドメイン URL の場合、event.origin複数の IFRAME に共通のドメインである場合、真のソースを区別できないことに注意してください。

===の代わりに使用する人も==いますが、この文脈では違いが見つからなかったので、最短のコンパレータを使用しています。

この実装はテスト済みで、次の環境で動作します。

  • MSIE 9
  • Firefox 17

別の方法として (Griffin が提案)、一意の識別子 (タイムスタンプなど) を持つ IFRAME src を使用できます。IFRAME の Web アプリケーションは、投稿されたメッセージでこの一意の識別子を返します。IFRAME の識別は簡単ですが、この方法では IFRAME の Web アプリケーションを変更する必要があります (常に可能とは限りません)。これは、セキュリティ上の問題にもつながる可能性があります (たとえば、IFRAME 化された Web アプリケーションは、他の IFRAME アプリケーションの一意の識別子を推測しようとします)。

于 2013-12-05T15:38:41.030 に答える
4

この問題を解決するアイデアがあります。iframe を作成するときに、iframe に名前/ID を付けます。.

そして、iframe内のスクリプトで、メッセージを次のようにオブジェクトとして送信します

window.parent.postMessage({"height" : $('.widget').outerHeight(), "frmname" : window.name}, '*');

親リスナーで、

eventer(messageEvent, function(e) {`enter code here`
    $(e.data.frmname).height(e.data.height);
}, false);
于 2015-03-10T00:49:43.060 に答える
1

ソース iframe が複数の親 iframe にネストされている場合は、各 iframe の window.frames プロパティを再帰的に処理し、それを messageEvent#source プロパティと比較する必要があります。

たとえば、この Dom の iframe#level3 によってメッセージが生成された場合。

<iframe Id=level1>
   <iframe Id=level2>
       <iframe Id=level3 />
   </iframe>
</iframe>

を使用して、現在のウィンドウで祖先 iframe のインデックスを見つけることができるはずです。

FindMe = event.source
FrameIndex = find(window)
frames[FrameIndex].frameElement ==     getElByTagName(iframe)[FrameIndex] 

function find(target){
    for (i=0; I< target.frames.length; i ++)
       if(target.frames[i] == FindMe ||   find(target.frames[i]))
           return i
    return false 
}

注意することが重要です

Window.frames プロパティは、クロス ドメイン ポリシーによって制限されません

この手法は、ソース iframe のネストの深さに関係なく機能します。

window.frames は、iframe 要素ではなく window オブジェクトのコレクションです。

window.frames コレクションのメンバーのプロパティへのアクセスは、Same Origin によって制限されています (つまり、window.frames[i] の frameElement または location プロパティにアクセスできない場合があります)。

于 2014-10-31T08:43:00.687 に答える