DOMおれおれAdvent Calendar 2015 – 10日目
作り方
各種と言いながら三種類だけだけど。
実例は挿入の方に。
要素ノード
createElement(tagName) で作ります。
子として作るなら innerHTML も使えます。
文字列ノード
createTextNode(text) で作ります。文字列ノードの文字列の内容は後から nodeValue で取得、設定できます。
子として作るなら textContent も使えます。
文書断片 (document fragment)
createDocumentFragment() で作ります。
使い方は後で。
複製して作成
cloneNode() を使うと、既存のノードを複製して新しいノードを作成する事ができます。
// elLabel = <label class="super-label"><input type="checkbox" checked>同意する</label> var elNewLabel = elLabel.cloneNode(); // elNewLabel = <label class="super-label"></label>
あ、ノードを複製するだけなので、子ノードは空です。子孫もまとめて複製する場合は引数でフラグを与えてやります。
// elLabel = <label class="super-label"><input type="checkbox" checked>同意する</label> var elNewLabel = elLabel.cloneNode(deep); // elNewLabel = <label class="super-label"><input type="checkbox" checked>同意する</label>
たくさんのノードを作るとき何度もDOM操作を繰り返すより、一度作って複製からの微調整、の方が高速かもね。まあそういうのはテンプレートエンジンに任せちゃった方が良いけれど。
あとは破壊的変更をしたいけど途中で(エラーとかで)中止するときとか。複製してからそっちを操作して、最後に差し替え。
挿入
末子として挿入
appendChild(el) で、自分の子要素の最後に挿入します。
// 親の要素ノードを作る
var elLabel = document.createElement('label');
// 要素ノードを作る
var elCheckbox = document.createElement('input');
elCheckbox.type = 'checkbox';
elCheckbox.checked = true;
// 文字列ノードを作る
var tLabel = document.createTextNode('同意する');
// 末子に挿入
elLabel.appendChild(elCheckbox);
elLabel.appendChild(tLabel);
// elLabel = <label><input type="checkbox" checked>同意する</label>
HTMLをまとめて挿入
innerHTML を使って、文字列から作成します。上↑と同じ結果になります。
// 親の要素ノードを作る
var elLabel = document.createElement('label');
// HTMLをまとめて挿入
elLabel.innerHTML = '<input type="checkbox" checked>同意する';
// elLabel = <label><input type="checkbox" checked>同意する</label>
(本当は checked のところがちょっと違うけども。)
要素を指定の位置に挿入
appendChild() だと常に最後に挿入されますが、最後じゃなくて途中に挿入する場合は insertBefore() を使います。
// 親の要素ノードを作る
var elLabel = document.createElement('label');
// 要素ノードを作る
var elCheckbox = document.createElement('input');
elCheckbox.type = 'checkbox';
elCheckbox.checked = true;
// 文字列ノードを作る
var tLabel = document.createTextNode('同意する');
// 先に末子にしたいノードを挿入してみる
elLabel.appendChild(tLabel);
// elLabel = <label>同意する</label>
// さっき挿入した要素の直前に挿入
elLabel.insertBefore(elCheckbox, tLabel);
// elLabel = <label><input type="checkbox" checked>同意する</label>
ちなみに insertAfter() はないです。参照ノードの次のノードが nextSibling で得られるので、これを使いましょう。
elLabel.insertBefore(elCheckbox, tLabel.nextSibling); // elLabel = <label>同意する<input type="checkbox" checked></label>
参照ノードの次がないとき nextSibling は null になりますが、その場合 insertBefore() は末子に挿入します。 appendChild() と同じになるという事ですね。やったね。
要素をまとめて挿入
文書断片 (document fragment) を使うとまとめて挿入できます。
// elList =
// <ul>
// <li>1</li>
// <li>2</li>
// <li id="reference">5</li>
// </ul>
// 挿入する要素を用意
var elItem3 = document.createElement('li');
elItem3.textContent = '3 (New!)';
var elItem4 = document.createElement('li');
elItem4.textContent = '4 (New!)';
// 文書断片を用意
var fragment = document.createDocumentFragment();
fragment.appendChild(elItem3);
fragment.appendChild(elItem4);
// まとめて挿入
var elReference = elList.querySelector('#reference');
elList.insertBefore(fragment, elReference);
// elList =
// <ul>
// <li>1</li>
// <li>2</li>
// <li>3 (New!)</li>
// <li>4 (New!)</li>
// <li id="reference">5</li>
// </ul>
基本的に挿入系APIは要素や文字列のノードに限らず、文書断片ノードでも使えます。文書断片の場合はそれ自体ではなく、それに格納されているノードが挿入されます。
差し替えて挿入
replaceChild() で既存の要素を任意の要素に差し替える事ができます。
// el = <div><img src="img1.png" /></div>
var elNewImg = document.createElement('img');
img.setAttribute('src', 'img2.png');
el.replaceChild(elNewImg, el.firstChild);
// el = <div><img src="img2.png" /></div>
参考
- document.createElement – Web API インターフェイス | MDN
- document.createTextNode – Web API インターフェイス | MDN
- Document.createDocumentFragment() – Web APIs | MDN
- DocumentFragment – Web API インターフェイス | MDN
- Node.cloneNode – Web API インターフェイス | MDN
- Node.appendChild – Web API インターフェイス | MDN
- Node.insertBefore – Web API インターフェイス | MDN
- Node.nextSibling – Web APIs | MDN
- Node.replaceChild – Web API インターフェイス | MDN
