無料Wikiサービス | デモページ
Linuxなどのメモ書き

JavaScript インラインフレーム(iframe)関連


いろいろハマリがちなJavaScriptでインラインフレームを扱う場合のメモ。

特に断らない限りブラウザのバージョンは以下が前提。
IE6
FireFox1.5

1.iframeのwindow,documentオブジェクトの取得

iframeのwindow,documentの取得方法はIEとMozilla系(NN,FireFox)で異なる。

IEはframes配列のwindow,documentプロパティから取得できる。Mozilla系はiframeエレメントのcontentWindow,contentDocumentプロパティから取得できる。

IEでもMozilla系と同じくiframeエレメントのプロパティから取得することもできるが、contentDocumentについてはIEには存在しないので、documentはcontentWindow.documentとしてcontentWindow経由で取得しなければならない。


IE
(1) frames配列から取得する場合
frames['xxxx'].window;
frames['xxxx'].document;
xxxxはiframeのID値。

(2) iframeエレメントのプロパティから取得する場合
iframe = document.getElementById(id); // iframeエレメント
iframe.contentWindow;           //window
iframe.contentWindow.document;  //document
IEにはcontentDocumentプロパティは存在しないので注意。

Mozilla系
iframeエレメントのcontentWindow,contentDocumentプロパティから取得する
iframe = document.getElementById(id); // iframeエレメント
iframe.contentWindow;   // window
iframe.contentDocument; // document

2. iframeへのエレメントの追加

インラインフレームの中にappendChild()などでエレメントを挿入する場合、そのエレメントはインラインフレームのドキュメントで作成されていないといけない(以下の例参照)(*1)。

(*1) Mozilla系ではdocument.createElement()で作成したエレメントでもインラインフレームにappendChild()できるので一見大丈夫そうだが、IE6ではエラーとなる。

// インラインフレームのドキュメントを取得
var doc;
if (document.all) {
  // IE
  doc  = frames[id].document;
} else {
  // Mozilla
  doc = document.getElementById(id).contentDocument;
}

// インラインフレームのドキュメントでエレメント作成(*2)
var container = doc.createElement("div");

// インラインフレーム内に追加
doc.body.appendChild(container);
(*2) document.createElement("div")のように作ってしまうと、IE6ではiframe内のドキュメントにappendChild()するとエラーになる。

iframe内にDOMエレメントを追加するサンプル:
http://www.bit-hive.com/~tomita/JS/IframeAppend/

3. onloadイベント

iframe内のコンテンツの読み込みが完了したら何か処理を行う場合、以下のonloadイベントで実現できる。

<iframe src="frame.html" onload="alert('complete');">

JavaScriptでcreateElement()で動的に作成したiframeに対してonloadイベントを処理したい場合は、iframeエレメントのonloadプロパティにハンドラ関数を登録しておけばよい。Mozilla系はこれですんなり動作する。

ただし、IEの場合、onloadプロパティに関数を登録しておいてもなぜか関数は呼び出されなかった。このため、代わりにonreadystatechageを使って回避した。onreadystatechageイベントは読み込み状態を示すreadyStateが変化した時に発生する(IE固有)。イベントハンドラ内でreadyStateをチェックして"complete"になっていれば読み込みが完了している。

var iframe = document.createElement("iframe");
iframe.src = "frame.html";

if (document.all) {
  // IEでのonload代用処理
  iframe.onreadystatechange = function () {
    if (this.readyState == "complete") {
      alert("complete");
      this.onreadystatechange = null;
    }
  }
} else {
  iframe.onload = function () {
    alert("complete");
  }
}

document.body.appendChild(iframe);

4.作成直後のiframeへの書き込み

JavaScriptで動的にiframeを作成(createElement())して書き込みをする場合は、書き込み前にwriteln()で<body>タグを書き出すようにする。これがないとまだ、bodyタグがないため正常に書き込めない。

<html>
  <body>
    <script>
        var iframedoc;
      function onLoad() {
        var iframe = document.createElement("iframe");
        document.getElementById("frame").appendChild(iframe);

        if (document.all) {
          iframedoc = iframe.contentWindow.document;
        } else {
          iframedoc = iframe.contentDocument;
        }
        iframedoc.writeln("<body></body>");
        iframedoc.body.innerHTML = "Inline Frame";  // *1
      }

      window.onload = onLoad;
    </script>

    <div id="frame"></div>

  </body>
</html>
writeln()がない場合の動作のメモ
IEだと、iframeをappendChild()した直後に、まだiframeにbodyがないため(iframedoc.body == null)、(*1)でiframedoc.body.innerHTMLにアクセスした時点でエラーになってしまう。FireFoxだとエラーにはならないが、なぜか正しく出力されない。

writeln()でbodyを書き込まなくても、イベントハンドラ(上記の例だとonLoad())を一旦終了して、ブラウザに処理を戻してやれば、bodyは自動で作成される模様。3.のonreadystatechageイベントを使ってbodyが作られてから書き込みを行うこともできる。(面倒だけど)



最終更新 2007/03/22 11:07:24 - kztomita
(2006/06/21 15:18:41 作成)