DOMおれおれAdvent Calendar 2015 – 10日目

2015-12-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>

参照ノードの次がないとき nextSiblingnull になりますが、その場合 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>

参考