JavaScriptでHTMLをダイナミックに書き換える 後編:DOMの基本を学ぼう(7)(3/3 ページ)
タグ要素を追加するテクニックに続き、要素の削除、置き換え、複製などの取り扱いを解説します。
まとめて更新を行う(DocumentFragment)
これまで、HTMLの要素をDOMを使って自由に操る方法を学んできました。基本はすでに身についていますので、あとは応用で、いろいろなWebアプリケーションを作ることができるはずです。しかし、Webアプリケーションを作り込むうえで、パフォーマンスという問題から逃れることはできません。
サーバー上で動作するアプリケーションの場合は、サーバーの負荷を軽減するためにさまざまな工夫をしますが、JavaScriptといえども例外ではありません。近年のWebアプリケーションにおいては、ブラウザ側で実行されるJavaScriptの役割が重要になり、複雑な処理が求められるようになってきました。JavaScriptの書き方によって、表示速度が大きく変わってしまうことがあります。この処理時間とは、ブラウザのレンダリング時間のことです。この点を考慮に入れてJavaScriptを組む必要があります。
appendChildメソッドは、既存の要素ノードに対して実行すると、その場でブラウザはHTML画面をレンダリングし直します。1つや2つ程度の追加であればまったく問題ないのですが、もし100個の要素を追加するとなると、レンダリング時間も無視できなくなります。要素を追加することで、ブラウザ上の表示レイアウトがずれる場合は、表示時間にさらに大きく影響を与えます。
これを解決するのが、DocumentFragmentと呼ばれるDOMインタフェースです。DocumentFragmentは、ノード要素を収容するための器とお考えください。本来であれば、HTML上に存在する要素ノードに対して、必要なノードを1つずつ追加していく手法でした。つまりブラウザは、ノードを追加するたびにレンダリングを行うのです。それに対してDocumentFragmentを使う場合は、DocumentFragmentで作った器に、追加したいすべてのノードを事前に入れておきます。最後に、DocumentFragmentの器をまるごと一気に実際のHTML上に追加するのです。こうすることで、ブラウザ側のレンダリング処理は1回で済むので、パフォーマンスの改善になります。
まずはこれまで学んできた手法で10個の要素を追加するサンプルを試しましょう。
DocumentFragment1.html <div id="frame" style="width:300px; color:white;"></div> <script type="text/javascript"> /*DIVタグのノードオブジェクト*/ var frameNode = document.getElementById('frame'); /*10回の繰り返し*/ for(var i=1; i<=10; i++) { /*DIVタグ要素を新たに生成*/ var newDivNode = document.createElement('div'); /*新たに生成したDIVタグ要素にスタイルを適用*/ newDivNode.style.width = '100%'; newDivNode.style.borderBottom = '1px solid #000000'; newDivNode.style.backgroundColor = 'rgb(0,' + (i*10+100).toString() + ',0)'; /*新たに生成したDIVタグ要素のテキストノードを追加*/ newDivNode.appendChild( document.createTextNode(i.toString()) ); /*frameNodeに、新たに生成したDIVタグ要素を追加*/ frameNode.appendChild(newDivNode); } </script>
このサンプルは、HTML上に初めから用意されていたDIVタグの中に、10個のDIVタグを追加します。追加するDIVタグには、グラデーション表示となるようにスタイルを適用しています。そして、1〜10のインデックス番号をテキストノードとして追加します。新たなDIVタグ要素ノードが完成した段階で、appendChildメソッドを使ってHTML画面上に反映させます。
では、このサンプルをDocumentFragmentを使って書き換えてみましょう。まず、DocumentFragmentインタフェースの使い方を学びます。DocumentFragmentインタフェースにはcreateDocumentFragmentメソッドが定義されています。実は、覚えるのはこのメソッドだけで大丈夫です。
var flgmntNode = document.createDocumentFragment();
createDocumentFragmentメソッドは、documentオブジェクトに対して定義されたメソッドですので、document.createDocumentFragment()という具合に使います。引数は必要ありませんので、なにも指定しないでください。document.createDocumentFragment()は呼び出されると、DocumentFragment型のオブジェクトを返します。とはいっても、空の要素ノードと思っていただいてかまいません。ここで新たに作ったDocumentFragmentを、要素ノードオブジェクトと同じように扱います。
では、実際の使い方を見てみましょう。
DocumentFragment2.html <div id="frame" style="width:300px; color:white;"></div> <script type="text/javascript"> /*DIVタグのノードオブジェクト*/ var frameNode = document.getElementById('frame'); /*DocumentFragmentを新たに生成*/ var flgmntNode = document.createDocumentFragment(); /*10回の繰り返し*/ for(var i=1; i<=10; i++) { /*DIVタグ要素を新たに生成*/ var newDivNode = document.createElement('div'); /*新たに生成したDIVタグ要素にスタイルを適用*/ newDivNode.style.width = '100%'; newDivNode.style.borderBottom = '1px solid #000000'; newDivNode.style.backgroundColor = 'rgb(0,' + (i*10+100).toString() + ',0)'; /*新たに生成したDIVタグ要素のテキストノードを追加*/ newDivNode.appendChild( document.createTextNode(i.toString()) ); /*frameNodeに、新たに生成したDIVタグ要素を追加*/ flgmntNode.appendChild(newDivNode); } /*DocumentFragmentをframeNodeに追加*/ frameNode.appendChild(flgmntNode); </script>
まず、10回の繰り返し処理の前に、器となるDocumentFragmentを作っておきます。
var flgmntNode = document.createDocumentFragment();
次に、for文による10回の繰り返し処理で、新たに追加するDIVタグ要素ノードを作るのですが、最後にappendChildメソッドで要素を追加する先が異なります。先ほどの例ではframeNodeに対して追加しましたが、ここではflgmntNodeに追加します。
flgmntNode.appendChild(newDivNode);
この段階では、flgmntNodeという器の中に要素を追加しただけですので、画面上には反映されません。まだ仮想的に作られているだけで、宙に浮いた状態です。for文の処理が完了した時点で新たに追加したいDIVタグがすべて完成しているのですが、あくまでもflgmntNodeに組み込まれただけにすぎません。
for文の処理が終わってから最後に、appendChildメソッドを使ってframeNodeに対してflgmntNodeを組み込みます。この時点で、初めてブラウザ上に反映されるのです。
このサンプルは非常に簡単なHTMLに対して適用していますので、パフォーマンスの違いはほとんどわかりません。ただ、実際のHTMLでは、表組みなどが入った複雑なレイアウト構造となっているはずです。そのようなHTMLにおいては効果が大きく表れる場合がありますので、テクニックの1つとしてぜひ覚えておいてください。
『標準DOMスクリプティング』の2章を転載した連載、「DOMの基本を学ぼう」は今回で終了です。7回にわたりご愛読ありがとうございました。
Copyright © ITmedia, Inc. All Rights Reserved.