Node appendChild( Node newChild );Node.appendChild - DOM | MDN
追加するnewChildがすでにドキュメントに存在している場合には、それが新しい位置へ移動させられます。このnewChildにnull
を指定することは認められません。
またこのappendChild()は追加するノードnewChildを返すため、そのノードにさらにノードを追加する、
node0.appendChild( node1 ); node1.appendChild( node2 );
のような処理は、次のように続けて記述できます。
node0.appendChild( node1 ).appendChild( node2 );
これはリストに連続してノードを追加するような処理を、簡潔に記述できます。
var list = document.createElement( 'ul' ); list.appendChild( document.createElement( 'li' ) ).appendChild( node1 ); list.appendChild( document.createElement( 'li' ) ).appendChild( node2 );
ところでappendChild()は、ドキュメント ツリーの最後にノードを追加します。一方でドキュメント ツリーの最初にノードを追加するには、
node.insertBefore( newChild, node.firstChild );
のように、ノードの最初の子の直前に追加するようにします。
ドキュメント ツリーの指定要素の直前にノードを追加します。
Node insertBefore( Node newChild, Node refChild );Node.insertBefore - DOM | MDN
このノードのchildNodes[]配列のrefChildの直前にnewChildを追加し、newChildを返します。
null
の場合 … appendChild()と同様に、ツリーの最後に追加されるnode.parentNode.insertBefore( newChild, node );
親要素のメソッドを利用し、自身の直前にノードを追加するようにします。
指定要素の直後にノードを追加するメソッドは用意されていませんが、指定要素の直後のノードをnextSiblingで取得し、その直前にinsertBefore()をすることで所望の動作を実現できます。このとき指定要素が最後の場合にはnextSiblingはnull
を返しますが、insertBefore()の第2引数にnull
を渡した場合にはドキュメント ツリーの最後にノードが追加されるため、このようなときも正しく処理されます。
node.insertBefore( newChild, refChild.nextSibling );
基本的に、前述のノード自身の直前へ追加する方法と同じです。違いは追加する場所を、ノード自身の直後のノードの直前とすることです。
node.parentNode.insertBefore( newChild, node.nextSibling );
要素を子として追加するならばappendChild()で簡単に実現できますが、親として追加するには工夫が必要です。nodeに親となる要素parentを追加する場合を考えると、
parent.appendChild( node.parentNode.replaceChild( parent, node ) );
となります。これは、
// nodeの親ノードからnodeを削除し、parentを追加する。 // 結果として削除されたnodeが返される。 node = node.parentNode.replaceChild( parent, node ); // parentにnodeを追加する。 parent.appendChild( node );
のように処理しています。
スクリプトを実行している場所にHTML要素を追加で解説しています。
指定のノードを削除します。
Node removeChild( Node oldChild );Node.removeChild - Web API リファレンス | MDN
削除するoldChildはこのノードの子でなければならず、さもなくばNotFoundError例外が発生します。よってノードが存在するか不明瞭ならば、先にcontains()でその存在を確認します。
ノードが削除されたときにはそのノード、つまりoldChildが返されます。
すべての子ノードを削除するには、子ノードが存在しなくなるまでノードの削除をくり返します。
while( node.hasChildNodes() ) { node.removeChild( node.firstChild ); }
hasChildNodes()メソッドで子ノードを持つか確認できます。子ノードがあるならばremoveChild()メソッドで、最初の子ノード (firstChild) を削除します。この処理を子ノードがなくなるまで、whileループでくり返します。
またはノードが子を持たない場合はnull
を返すのを利用して、
while( node.firstChild ) { node.removeChild( node.firstChild ); }
のようにも記述できます。
Element.innerHTMLは、要素内に含まれるHTMLテキストを表します。よってこれに空文字を設定することでも、子ノードをすべて削除できます。
node.innerHTML = '';
しかしこの方法は、Internet Explorerでは予期せぬ挙動を示すために注意が必要です。次のコードを用いて実験してみます。
var a = document.createElement( 'div' ); var b = document.createElement( 'div' ); var c = document.createElement( 'div' ); a.appendChild( b ); // aの子ノードにbを追加 b.appendChild( c ); // bの子ノードにcを追加 alert( b.firstChild ); // *1 a.innerHTML = ''; alert( b.firstChild ); // *2
2か所のalert()では、下表のように表示されます。
コードの場所 | Firefox / Chrome | IE6 / IE7 | IE8 |
---|---|---|---|
*1 | object HTMLDivElement | object | object HTMLDivElement |
*2 | object HTMLDivElement | null | null |
このことからIEでは、innerHTML = ''
で削除した子ノードの子ノードまで削除されてしまうことがわかります。
ノード自身の削除は、親ノードの子ノードから削除することで実現できます。
node.parentNode.removeChild( node );
たとえば、
<div>BBB<span id="a">AAA</span></div>
のようなHTMLのコードがあるとき、次のようにノードを削除すると、
var node = document.getElementById( 'a' ); node.parentNode.removeChild( node );
削除後には、
<div>BBB</div>
となります。
前項の方法では、ノードを削除するときその子要素も削除されます。たとえば、
<div>BBB<span id="a">AA<b>X</b></span></div>
のようなHTMLで、id="a"の要素を削除すると、
<div>BBB</div>
となります。これが期待する動作ならば問題ありませんが、子要素を残したいならば少し工夫が必要です。
var node = document.getElementById( 'a' ); var parent = node.parentNode; while( node.firstChild ) { // 指定要素の子要素を、親要素の子要素となるように移動 parent.insertBefore( node.firstChild, node ); } // 指定要素を削除 parent.removeChild( node );
この方法では指定要素のすべての子要素を、親要素の子要素、つまり指定要素の兄弟要素となる位置に移動しています。そして最後に指定要素だけを削除することで、子要素が削除されないようにしています。この結果は、次のようになります。
<div>BBBAA<b>X</b></div>
ちなみにこの方法では、子要素に登録されたイベントハンドラも削除されません。
Node cloneNode( boolean deep );Node.cloneNode | MDN
ノードの複製を取得できます。そのとき引数にtrueを指定すると、その派生ノードも含みます。
Elementノードを対象とした場合には、そのすべての属性も複製されます。ただしイベントハンドラは複製されません。
cloneNode()ではid属性も複製されるため、複製したノードをドキュメントに追加すると、ドキュメント内でidが重複する恐れがあります。
var link = document.createElement( 'a' ); link.style.color = 'red'; link.appendChild( document.createTextNode( 'Click ' ) ); link.onclick = function() { alert( 'OK' ); }; // イベントハンドラ document.body.appendChild( link ); document.body.appendChild( link.cloneNode( true ) ); document.body.appendChild( link.cloneNode( false ) );
複製元のノードと、それを複製したノード2つの合計3つのノードを、以下に並べて表示します。2つ目のノードはクリックに反応せず、3つ目のノードは派生ノードを持たないため表示されないはずです。
Node replaceChild( Node newChild, Node oldChild );Node.replaceChild - Web API リファレンス | MDN
指定のノードを削除し、新しいノードに置換します。削除するoldChildは、このノードの子でなければなりません。戻り値では削除されたノード、つまりoldChildが返されます。
置換するのがTextなどのCharacterDataの実装ならば、そのdataプロパティを書き換えるだけで内容を置換できます。
たとえば処理の進捗を表示するのに、次のようにreplaceChild()を使用できます。このとき必ず置き換えられるノード (前述のoldChild) を指定しなくてはならないため、あらかじめ「 」などの要素を設定しておきます。
<p><span id="node"> </span></p> <script type="text/javascript"> for( var i = 0; i <= 100; i++ ) { var node = document.getElementById( 'node' ); var newNode = document.createTextNode( i ); node.replaceChild( newNode, node.firstChild ); // innerHTMLで記述するならば、 // node.innerHTML = i; } </script>
ノードがElementオブジェクトのとき、そのタグ名 (タグの種類) を変更する場合を考えます。たとえば、
<div><a id="a">ABC</a></div>
のようなHTMLのコードがあったとき、これを
<div><b id="a">ABC</b></div>
に変更する場合です。そのためには、
var oldNode = document.getElementById( 'a' ); var newNode = document.createElement( 'b' ); newNode.id = oldNode.id; newNode.appendChild( oldNode.firstChild.cloneNode( true ) ); oldNode.parentNode.replaceChild( newNode, oldNode );
とします。変更するタグ (この場合は<a id="a">
) に複数の子要素があることを考慮するならば、
var oldNode = document.getElementById( 'a' ); var newNode = document.createElement( 'b' ); newNode.id = oldNode.id; for( var i = 0; i < oldNode.childNodes.length; i++ ) { newNode.appendChild( oldNode.childNodes[ i ].cloneNode( true ) ); } oldNode.parentNode.replaceChild( newNode, oldNode );
とします。一方でinnerHTMLを使用するならば、子要素の数と無関係に
var oldNode = document.getElementById( 'a' ); var newNode = document.createElement( 'b' ); newNode.id = oldNode.id; newNode.innerHTML = oldNode.innerHTML; oldNode.parentNode.replaceChild( newNode, oldNode );
と記述できます。
appendChild()とinsertBefore()では、追加するノードがすでにドキュメントに存在している場合には、それが新しい位置へ移動させられます。これを利用することでノードを移動できます。
var node1 = document.createElement( 'div' ); var node2 = document.createElement( 'div' ); var node3 = document.createElement( 'div' ); node1.id = '1'; node2.id = '2'; node3.id = '3'; document.body.appendChild( node1 ); document.body.appendChild( node2 ); document.body.appendChild( node3 ); document.body.insertBefore( node3, node1 ); // <div id="3"></div> // <div id="1"></div> // <div id="2"></div>
insertBefore()を共通の親を持つノードに適用することで、ノードの順番を並べ替えることができます。それはたとえば、
<div id="list"><b>0</b><b>1</b><b>2</b><b>3</b><b>4</b></div>
のようなノードがあり、これが
のように表示されるとき、
var list = document.getElementById( 'list' ); list.insertBefore( list.childNodes[ 2 ], list.childNodes[ 1 ] );
このようにinsertBefore()で[1]の要素の直前に[2]の要素を追加することで、
のように、ノードの順番を並べ替えられることを意味します。もしこのとき、
list.insertBefore( list.childNodes[ 3 ], list.childNodes[ 1 ] );
のように[1]の直前に[3]を追加するならば、
の順番となります。
あるノードを基準として、それと親子関係にあるノードを取得する方法について解説します。それがElementオブジェクトならば、id属性やname属性から取得する方法もあります。またInternet Explorer 8以降などの新しいブラウザを対象とするならば、CSSの構文を用いられるセレクタAPIでもノードを取得できます。
関係 | プロパティ | 内容 |
---|---|---|
親 | parentNode | 親ノード |
兄弟 | previousSibling | 直前のノード |
nextSibling | 直後のノード | |
子 | childNodes | すべての子ノード |
firstChild | 最初の子ノード | |
lastChild | 最後の子ノード |
ノードがHTMLCollectionオブジェクトを返すプロパティを持つならば、これとは異なる方法でノードを参照できます。
下記の構造のドキュメントを例に、id="B2"
を基準としたときの各プロパティが参照するノードを示します。ただし次項で示すように、Internet Explorer以外ではこのような結果となりません。
<div id="A"> // parentNode <div id="B1"></div> // previousSibling <div id="B2"> // 基準 <div id="C1"></div> // childNodes[ 0 ] および firstChild <div id="C2"></div> // childNodes[ 1 ] <div id="C3"></div> // childNodes[ 2 ] および lastChild </div> <div id="B3"></div> // nextSibling </div>
前述のドキュメントに対して次のコードを実行し、ブラウザごとの相違を調査します。
<pre> <script type="text/javascript"> var element = document.getElementById( 'B2' ); document.writeln( element.parentNode.id ); document.writeln( element.previousSibling.id ); document.writeln( element.nextSibling.id ); document.writeln( element.firstChild.id ); document.writeln( element.lastChild.id ); </script> </pre>
ブラウザ | コードの実行結果 | childNodesの値 |
---|---|---|
IE6 |
A B1 B3 C1 C3 |
|
IE7 | ||
IE8 | ||
Firefox 3 |
A undefined undefined undefined undefined |
(Firebugによる取得結果) |
Chrome 4 |
A undefined undefined undefined undefined |
(Developer Toolsによる取得結果) |
このような違いは、空白や改行をノードとして認識するかどうかによって生じます。よって、
<div id="A"><div id="B1"></div><div id="B2"><div id="C1"></div><div id="C2"></div><div id="C3"></div></div><div id="B3"></div></div>
のように空白などを含まない表記とすれば、ブラウザによる相違は発生しません。
一方で、新しくElementに実装されたプロパティ (Element Traversal Specification) を用いれば、空白などを除外してノードを取得できます。
関係 | プロパティ | |
---|---|---|
Node | Element | |
親 | parentNode | - |
兄弟 | previousSibling | previousElementSibling |
nextSibling | nextElementSibling | |
子 | childNodes | children |
firstChild | firstElementChild | |
lastChild | lastElementChild |
contains()で確認できます。
boolean node.contains( otherNode )Node.contains - Web API インターフェイス | MDN
ノードの子孫にotherNodeがあるならば、trueが返されます。
nodeTypeプロパティで確認できます。Node.nodeType - Web APIs | MDN
Constant | Value | Description |
---|---|---|
Node.ELEMENT_NODE | 1 | An Element node such as <p> or <div>. |
Node.TEXT_NODE | 3 | The actual Text of Element or Attr. |
Node.PROCESSING_INSTRUCTION_NODE | 7 | A ProcessingInstruction of an XML document such as <?xml-stylesheet ... ?> declaration. |
Node.COMMENT_NODE | 8 | A Comment node. |
Node.DOCUMENT_NODE | 9 | A Document node. |
Node.DOCUMENT_TYPE_NODE | 10 | A DocumentType node e.g. <!DOCTYPE html> for HTML5 documents. |
Node.DOCUMENT_FRAGMENT_NODE | 11 | A DocumentFragment node. |
Constant | Value | Description |
---|---|---|
Node.ATTRIBUTE_NODE | 2 | An Attribute of an Element. The element attributes are no longer implementing the Node interface in DOM4 specification. |
Node.CDATA_SECTION_NODE | 4 | A CDATASection. Removed in DOM4 specification. |
Node.ENTITY_REFERENCE_NODE | 5 | An XML Entity Reference node. Removed in DOM4 specification. |
Node.ENTITY_NODE | 6 | An XML <!ENTITY ...> node. Removed in DOM4 specification. |
Node.NOTATION_NODE | 12 | An XML <!NOTATION ...> node. Removed in DOM4 specification. |
textContentにより、そのノードおよびその子孫のテキストへアクセスできます。このプロパティはInternet Explorer 9以降でサポートされます。Node.textContent - Web API インターフェイス | MDN