IFrameオブジェクトは、その取得方法によって異なるオブジェクトとなります。
取得方法 | 返されるオブジェクト |
---|---|
Window.frames[] | Window |
Name (name属性の値) | |
Document.getElementById( ID ) | IFrame |
Document.getElementsByTagName( 'iframe' ) | |
ID (id属性の値で宣言されたグローバル変数) ※1 [非標準] |
IFrameオブジェクトとして取得しないと、このページで解説する方法を適用できません。もしWindowオブジェクトが必要ならば、IFrameオブジェクトからでも
IFrame.contentWindow
IFrame.contentDocument.defaultView
(IE9より前は非対応
defaultView property (Internet Explorer) | MSDN
互換性 - document.defaultView - Web API インターフェイス | MDN | MSDN)
のいずれかの方法で取得できます。
型 | プロパティ | 内容 |
---|---|---|
Document | contentDocument | iframe要素のHTMLドキュメント |
Window | contentWindow | iframe要素のウィンドウ |
String | src | iframe要素のsrc属性の内容 |
String | width | |
String | height | |
String | frameBorder |
IE8より前はcontentDocumentをサポートしないため、それにも対応させるためにはIFrame.contentWindow.document
を使用します。よってクロスブラウザとするには、
var contentDocument = IFrame.contentDocument || IFrame.contentWindow.document;
とします。contentDocument property (Internet Explorer) | MSDN
IFrameのbody要素へは、Iframe.contentDocument.body
でアクセスできます。
contentDocumentは、IFrameオブジェクトがドキュメントに追加されるまではnullを返します。
var iframe = document.createElement( 'iframe' ); console.log('1:' + iframe.contentDocument); iframe.src='/'; console.log('2:' + iframe.contentDocument); iframe.onload = function(e) { console.log('3:' + iframe.contentDocument); } document.body.appendChild(iframe); console.log('4:' + iframe.contentDocument); // 1:null // 2:null // 4:[object HTMLDocument] // 3:[object HTMLDocument]
contentDocumentへのアクセスには同一起源ポリシーによる制約を受けます。そのためiframeにより埋め込まれた外部サイトの内容を、スクリプトで改変するようなことはできません。
外部サイトのcontentDocumentを読み込もうとすると、ブラウザごとに下表のような反応を示します。
ブラウザ | |
---|---|
Internet Explorer 11 | 例外が発生する。
|
Chrome | 例外が発生する。
|
Firefox |
|
この制約はフレーム内のウィンドウに対しても同様で、srcプロパティで外部サイトを指定した場合、その外部サイトからwindow.parentを介してアクセスされることはありません。
このプロパティを変更すると、フレーム内に新しいドキュメントが読み込まれます。ただしX-Frame-Optionsヘッダが出力されるページは表示できません。
srcプロパティはただの文字列であるStringオブジェクトであり、Locationオブジェクトではありません。
onloadイベントは、src属性により指定されたリソースの読み込み完了時に発生します。しかしHTMLで記述したiframe要素が読み込まれるタイミングは予測できないため、HTMLの属性としてハンドラを記述するのが確実です。
<iframe onload="alert( '完了' )" src="http://example.com"></iframe>
なお、ハンドラ内でのthisキーワードはWindowオブジェクトです。
iframeの内容を動的に読み込み、その読み込み完了時に何らかの処理をする場合を考えます。このときiframeのonloadイベントに設定するだけでは、ページの読み込み時にもイベントが発生してしまいます。よってWindow.onloadイベント発生時に、IFrame.onloadイベントを設定するようにします。
<iframe name="frameName" id="frameId"></iframe> <form target="frameName" action="sample.htm" method="get"> <input type="submit" value="読み込む" /> </form> <script type="text/javascript"> window.onload = function() { var iframe = document.getElementById( 'frameId' ); iframe.onload = function() { alert( '読み込み完了' ); } } </script>
iframeではerrorイベントを捕捉できません。javascript - How can I handle errors in loading an iframe? - Stack Overflow
iframe要素内から、他のiframe要素内へアクセスする場合を考えます。それらの要素は、
<iframe id="frame1" src="frame1.htm"></iframe> <iframe id="frame2" src="frame2.htm"></iframe> <div> parent Window <input type="text" id="text" readonly="readonly" /> </div>
のように配置されているものとします。また読み込まれるフレーム内には、
frame1<input type="text" id="text" value="" />
の記述があるものとします。このとき1つ目のiframe内で、
// 親ウィンドウのドキュメントを取得する var parentDocument = window.parent.document; // 親ウィンドウのドキュメント内で、他のiframeをIDから取得する var frame2 = parentDocument.getElementById( 'frame2' ); // 他のiframeのドキュメントを取得する var otherDocument = frame2.contentWindow.document; otherDocument.getElementById( 'text' ).value = 'TEST';
とすることで、2つ目のiframe内の要素にアクセスできます。
frame1、frame2のテキストボックスへの入力を、それぞれ他方へコピーします。また同時に、親となるウィンドウのテキストボックスへもコピーします。
親ウィンドウとiframe要素内のウィンドウが同一起源ポリシーを満足していないと、このように親ウィンドウを介してアクセスすることはできません。
フレーム内のコンテンツがフレームより大きいとスクロールしなければ閲覧できず、一方でフレームより小さいと無駄な余白が生じます。これをフレーム内のコンテンツのサイズに合わせて、フレーム自身のサイズを調整する方法を考えます。
コンテンツのサイズはリソースの読み込み後に確定するため、onloadイベントで処理します。
iframe.onload = function() { var contentDocument = this.contentDocument || this.contentWindow.document; this.width = contentDocument.documentElement.scrollWidth; this.height = contentDocument.documentElement.scrollHeight; }
なおこの方法はcontentDocumentへのアクセスを伴うため、外部サイトのドキュメントに対しては適用できません。