DOMでは、要素を丸ごとコピーするcloneNodeメソッドが規定されています。複雑なHTMLをダイナミックに変化させるようなWebアプリケーションでは非常に重宝するメソッドです。
HTML上にまったく存在していなかった要素を、DOMメソッドを使って一から作り込むのは面倒です。これまで見てきたサンプルは非常に簡単なものばかりでした。そのため、DOMのメソッドを使って一から作成しましたが、実際には、非常に階層が深いHTMLを扱わなければいけなくなります。
事前に、HTML内にDOMで扱うHTMLタグの塊をひな型として記述しておき、スタイルシートを使ってそのタグ全体を見えなくしておくという方法がよくとられます。ある特定のアクションが発生したときに、そのひな型となるHTMLの塊をコピーして、必要に応じて加工し、所定の場所に差し込むのです。
サンプルを見る前に、cloneNodeメソッドの使い方を学んでおきましょう。このメソッドには1つの引数を与えます。コピー元の要素ノードの子要素を含めるかどうかを、trueもしくはfalseで指定します。もしtrueを与えれば、子要素も一緒にコピーしてくれます。falseを与えると子要素はコピーされず、指定した最上位の要素だけがコピーされます。実際のシーンでは、falseを指定することはまれでしょう。
var newNode = orgNode.cloneNode(true);
orgNodeは、コピー元の要素ノードオブジェクトです。cloneNodeメソッドは、コピーした要素をノードオブジェクトとして返します。上の例では、newNodeにそれが格納されたことになります。ただし、newNodeには親要素が存在しないことに注意してください。parentNodeメソッドをnewNodeに対して適用するとnullが返ります。
では、実践的なサンプルを見てみましょう。
cloneNode.html <!-- コンテンツを挿入したい場所--> <div id="contents"></div> <!-- 表示ボタン--> <input type="button" name="dispBtn" id="dispBtn" value="表示" onclick="dispContents()" /> <!-- ひな型となるHTMLタグ--> <div id="tmpl" class="box" style="display:none"></div> <!-- ひな型のスタイル--> <style type="text/css"> .box { border: 1px solid #4c4c4c; background-color: #F0F0E8; margin: 10px; padding: 10px; width: 200px; } </style> <script type="text/javascript"> /*コンテンツとして表示させたい内容のテキスト*/ var textArray = new Array(); textArray[0] = 'コンテンツ0。コンテンツ0。コンテンツ0。'; textArray[1] = 'コンテンツ1。コンテンツ1。コンテンツ1。'; textArray[2] = 'コンテンツ2。コンテンツ2。コンテンツ2。'; /*コンテンツ表示フラグ*/ var displayFlag = false; /*コンテンツ表示用関数*/ function dispContents() { /*コンテンツ表示フラグをチェック*/ /*もし表示されていれば終了*/ if(displayFlag == true) { return; } /*コンテンツを表示させたい領域のタグ要素ノードオブジェクト*/ var contentsNode = document.getElementById('contents'); /*ひな型となるHTMLタグの要素ノードオブジェクト*/ var tmplNode = document.getElementById('tmpl'); /**/ for(var i=0; i<textArray.length; i++) { /*ひな型の要素ノードオブジェクトを複製*/ var newNode = tmplNode.cloneNode(true); /*スタイルを変更し可視化する*/ newNode.style.display = ''; /*id属性値を変更*/ newNode.id = 'box' + i; /*コンテンツを挿入*/ newNode.appendChild( document.createTextNode(textArray[i]) ); /*新ノードを追加*/ contentsNode.appendChild(newNode); } /*表示ボタンを無効化*/ document.getElementById('dispBtn').disabled = true; /*表示フラグをtrueにセット*/ displayFlag = true; } </script>
このサンプルは、「表示」ボタンを押すと、3つのボックスにそれぞれのテキストが挿入され表示されます。表示されると「表示」ボタンは無効となります。
<!-- コンテンツを挿入したい場所--> <div id="contents"></div> <!-- 表示ボタン--> <input type="button" name="dispBtn" id="dispBtn" value="表示" onclick="dispContents()" />
コンテンツを挿入したい場所をあらかじめ用意しておきます。サンプルでは、id属性値に"contents"をセットしたDIVタグとして用意してあります。中身は空です。
次に、「表示」ボタンをINPUTタグで用意します。ただし、ボタンが押されたらdispContents()関数が実行されるように、onclick属性をセットしておきます。
<!-- ひな型となるHTMLタグ--> <div id="tmpl" class="box" style="display:none"></div> <!-- ひな型のスタイル--> <style type="text/css"> .box { border: 1px solid #4c4c4c; background-color: #F0F0E8; margin: 10px; padding: 10px; width: 200px; } </style>
次に、複数のコンテンツを格納するためのボックスとなるHTMLタグを用意します。このタグは、JavaScript内でコンテンツを表示する際に使うひな型のHTMLタグとなります。ここで注目して欲しいのが、style属性で"display:none"をセットしている点です。これにより、雛形としてのHTMLタグは、ブラウザ上には表示されません。また、class属性に"box"をセットしてあります。これはスタイルシートを適用するために使います。
ひな型のボックスには、デコレーション用のスタイルを定義しておきます。ここでは簡単に、境界線、背景色、マージン(外側の余白)、パディング(内側の余白)、幅を定義してあります。
ひな型のボックスは複製して使うため、スタイルの適用にclass属性を使っている点にも注目してください。
以上でHTML側の準備が終わりました。次に、JavaScriptコードを見ていきましょう。
/*コンテンツとして表示させたい内容のテキスト*/ var textArray = new Array(); textArray[0] = 'コンテンツ0。コンテンツ0。コンテンツ0。'; textArray[1] = 'コンテンツ1。コンテンツ1。コンテンツ1。'; textArray[2] = 'コンテンツ2。コンテンツ2。コンテンツ2。'; /*コンテンツ表示フラグ*/ var displayFlag = false;
複数のボックス内に表示するためのテキストを事前にセットしておきます。サンプルでは3つのボックスを表示しますので、それぞれの内容を定義し、Arrayオブジェクトの配列に格納しておきます。
いったんコンテンツが表示されたら、そのあとに動作しないようにするために、すでにコンテンツを表示したかどうかを識別するフラグを初期化しておきます。ここでは、変数displayFlagにfalseをセットしておきます。
では、「表示」ボタンが押されると実行されるdispContents()関数を見ていきましょう。
if(displayFlag == true) { return; }
最初にdisplayFlagを調べて、もしtrue、つまりすでにコンテンツが表示されているのであれば、処理を中断します。
var contentsNode = document.getElementById('contents');
var tmplNode = document.getElementById('tmpl');
コンテンツを表示したいエリアとなるDIVタグの要素ノードオブジェクトを事前に用意しておき、変数contentsNodeにセットします。また、同様に、コンテンツ1つを格納するボックスとなるひな型のHTMLの要素ノードオブジェクトも、変数tmplNodeに格納しておきます。
for(var i=0; i<textArray.length; i++) { /*ひな型の要素ノードオブジェクトを複製*/ var newNode = tmplNode.cloneNode(true); /*スタイルを変更し可視化する*/ newNode.style.display = ''; /*id属性値を変更*/ newNode.id = 'box' + i; /*コンテンツを挿入*/ newNode.appendChild( document.createTextNode(textArray[i]) ); /*新ノードを追加*/ contentsNode.appendChild(newNode); }
コンテンツのテキストを格納した配列をfor文で繰り返し処理します。
まず、cloneNodeメソッドを使って、ひな型のHTMLをコピーし、その要素ノードオブジェクトを変数newNodeにセットします。ところがcloneNodeメソッドは、属性も一緒にコピーします。したがって、新たに複製した要素ノードにも、style属性に"display:none"がセットされたままです。そのため、可視化するために、displayの値を削除してしまいます。さらに、コピーした新ノードにはid属性も引き継がれています。HTML上でid属性値の重複は許されませんので、newNodeのid属性を変更しておきます。
これでコンテンツを格納するHTMLが完成しましたので、appendChildとcreateTextNodeを使って、コンテンツの内容をセットします。最後にappendChildメソッドを使って、複製・加工された新ノードをcontentsNodeに追加します。
/*表示ボタンを無効化*/ document.getElementById('dispBtn').disabled = true; /*表示フラグをtrueにセット*/ displayFlag = true;
コンテンツの表示が終わったら表示ボタンを無効化し、表示フラグdisplayFlagにtrueをセットして終了です。
なんでもかんでも、一からゴリゴリとDOMメソッドを使ってHTMLを作り込む必要はありません。このサンプルのように、できる限り楽に目的を果たす方法をつねに考えていきたいものです。
Copyright © ITmedia, Inc. All Rights Reserved.