クロスドメインでiframeを扱う
以前、iframeについていくつか記事を書かせて頂きましたが、その続編です。
iframeで別ページを読み込む際、同じドメインでないとエラーが発生し、iframe内の要素にアクセスすることができなくなってしまいます。
一例ですが、子ページと同じ大きさにiframeをリサイズすることができなくなってしまいます。 対処法をまとめます。
postMessageを使う
親ページ→子ページへのアクセスは禁じられていますが、window.postMessage()メソッドを用いて子ページ→親ページへメッセージを受け渡すことは可能になっています。
モダンブラウザ、IE8で実装済みです。
子ページ側(メッセージを送る側)
parent.postMessage('hello','*');
第一引数は送りたいメッセージ、第二引数には対象ドメインを指定します。
ここでは対象ドメインに「*(すべて可)」を指定していますが、本来はセキュリティ上、親ページのドメインを指定したほうがよいそうです。
ちなみに第一引数のメッセージですが、IE8では文字列のみ、モダンブラウザでは文字列およびオブジェクトが送信可能です。
ではIE8でもオブジェクトを送りたい場合(プロパティと値を結び付けたい場合)は、どうすればよいのか。
JSONオブジェクトを文字列化して送ります。
var size = {'width':100}; size = JSON.stringify(size); parent.postMessage(size,'*');
これを、ページが読み込まれた際に実行するように紐づけます。
親ページ側(メッセージを受ける側)
windowオブジェクトのmessageイベントで、送られたメッセージを受け取ることができます。
送られたメッセージは、次のようにして取得できます。
値の格納場所が異なるので注意。
/*jQueryの場合*/ $(window).on('message',function(e){ var size = JSON.parse(e.originalEvent.data); var _width = size.width; }); /*ネイティブなJavaScriptの場合*/ window.onmessage = function(e){ var size = JSON.parse(e.data); var _width = size.width; };
子ページで文字列化されたオブジェクトを、JSONオブジェクトに戻すところが重要です。圧縮→解凍のようなイメージでしょうか。
親ページのハッシュを利用する
以上はIE8までで実装可能な方法ですが、IE7以下でも異なるドメイン間でiframeを扱うにはどうすればよいでしょうか。
親ページのハッシュを利用するという、裏ワザを用います。
渡したい値を親ページのハッシュに与えます。
ハッシュならば親ページのリロードが発生しないためです。
子ページ側(メッセージを送る側)
parent.location.hash = 'width=' + width;
親ページはparentオブジェクトで参照可能です。
対する親ページは、ハッシュを常に監視し、ハッシュが変化したらその値を取得するという方法をとります。
setTimeoutで断続的に関数を実行します。
親ページ側(メッセージを受ける側)
var locationHash = location.hash; var resizeByHash = function(){ var _hash = location.hash; var timer = setTimeout(function(){ if(_hash != locationHash){ clearTimeout(timer); /*ハッシュに仕込まれた値を取り出す処理*/ }else{ resizeByHash(); } },50); }; resizeByHash();
親ページのリサイズに合わせてメッセージを送りたい
たとえば親ページのリサイズに合わせて、iframeを拡縮する際に効果を発揮します。
先ほどparentオブジェクトで親ページを参照できたことを利用します。
子ページ側
parent.onresize = function(){ /*postMessageを送る処理*/ }
親ページ側は、いちどonmessageに紐づく処理を書けば、すべてそこで受け取ってくれます。
注意
しかしながら、postMessageは同一ドメイン間で安全にメッセージングをするためのものなので、クロスドメインといってもhttpとhttpsとの間ではエラーが起こります。
クロスドメイン間の通信は、JSONPのほうが無難なのかもしれません。
また、postMessageを使用できるブラウザ判別は、Modernizrで調べたほうが無難でしょう。