uhyohyo.net

JavaScript初級者から中級者になろう

二章第七回 木構造の操作:さまざまな機能2

兄弟ノード

DOMには、兄弟ノードを取得する方法もあります。

ここで、兄弟ノードとは、同じ親を持つノードのことです。例えば、

AAA
|
├――BBB
|
├――CCC
|
└――DDD
        

という木構造があったとき、BBB,CCC,DDDは全て、同じAAAという親を持つ兄弟ノードです。

あるノードの兄弟ノードを取得するには、プロパティpreviousSiblingnextSiblingを使います。

previousSiblingはそのノードの1つ前の兄弟、nextSiblingは1つ後の兄弟です。

実際のサンプルで見てみましょう。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p><strong>a</strong><em id="aaa">b</em><ins>c</ins></p>

    <script type="text/javascript">
      var aaa = document.getElementById('aaa');

      var prev = aaa.previousSibling;
      var next = aaa.nextSibling;

      alert(prev.tagName);
      alert(next.tagName);
    </script>
  </body>
</html>
        

このサンプルの木構造はこうです。

 p
|
├――strong
|  |
|  └――#text
|
├――em
|  |
|  └――#text
|
└――ins
   |
   └――#text
        

ここで、変数aaaには、"aaa"というidを持つ要素、つまりem要素のノードを代入しています。

prevとnextには、それぞれpreviosSiblingとnextSiblingが代入されています。

つまり、

 p
|
├――strong    ←previousSibling
|  |
|  └――#text
|
├――em
|  |
|  └――#text
|
└――ins      ←nextSibling
   |
   └――#text
          

このようになっているから、prevにはstrong要素のノード、nextにはins要素のノードが代入されているはずです。

それを確かめているのが次の2行で、tagNameを表示しています。予想通り、「STRONG」と「INS」が表示されるはずです。

ちなみに、兄弟ノードを全てまとめて(NodeListの形で)取得することは、今までの知識でもできます。aaa.parentNode.childNodesですね。

replaceChild

replaceChildは、ノードが持つプロパティで、そのノードが持つある子ノードを、別のノードに置き換えます

実際のサンプルを見てみましょう。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="aaaaa">t<strong>es</strong>t</p>

    <script type="text/javascript">
      var p = document.getElementById('aaaaa');

      var newnode = document.createElement('em');
      newnode.appendChild(document.createTextNode('置き換えるノード'));

      p.replaceChild(newnode, p.firstChild);
    </script>
  </body>
</html>
        

このサンプルでは、P要素の最初の子ノードと、新しくつくったem要素を置き換えています。

まず、getElementByIdで

 p       ←これ
            |
            ├――#text
            |
            ├――strong
            |   |
            |   └――#text
            |
            └――#text
        

を取得します。

その後、新しいem要素をcreateElementで作り、newnodeに代入しています。その後、そのem要素にdocument.createTextNodeで作ったテキストノードを子として追加しています。このように返り値を直接引数として渡すことで、テキストノードをいちいち変数に代入しなくてもよくなります。

つまり、

em
|
└――#text    "置き換えるノード"
          

を作ったということですね。

その後、いよいよp.replaceChildを呼び出しています。1つめの引数が新しく作ったノードで、2つめの引数は、firstChild、つまり

 p
|
├――#text       ←これ
|
├――strong
|   |
|   └――#text
|
└――#text
        

ですね。

実は、1つめの引数が置き換え後のノードで、2つめの引数が置き換え前のノードです。

つまり、p.firstChildをnewnodeに置き換えるという処理をしているわけです。つまり、次のようになります。

 p
|
├――#text       "t"
|
├――strong
|   |
|   └――#text   "es"
|
└――#text       "t"

↓↓↓

 p
|
├―――em
|   
|   └――#text   "置き換えるノード"
|
├――strong
|   |
|   └――#text   "es"
|
└――#text       "t"
        

画面の実行結果をみても、この通りになっていることが分かります。

cloneNode

ノードは、cloneNodeというメソッドを持っています。これは、ノードをコピーするためのものです。

というのも、ノードもオブジェクトの一種だから、var b = a;のようにしてしまうと、bとaは同じものを指してしまい、うまくいきません。しかし、既にあるノードと全く同じノードがもう1つ欲しいということはあると思います。そういう場合につかうのが、cloneNodeです。

サンプルを見てみましょう。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <p id="aaaaa">t<strong>es</strong>t</p>

    <script type="text/javascript">
      var p = document.getElementById('aaaaa');

      var newnode = p.cloneNode(true);

      document.body.appendChild(newnode);
    </script>
  </body>
</html>
        

やっていることは簡単で、変数pにp要素を代入し、pのcloneNodeで同じノードをもう1つつくってnewnodeに代入し、それをbody要素にappendChildで追加しています。

その結果、

body
|
├―― p
|  |
| (省略)
|
(省略)
          

body
|
├―― p
|  |
| (省略)
|
(省略)
|
 └―― p
     |
    (省略)

        

のようになって同じpが2つできました。

それでは、cloneNodeの引数であるtrueは何なのでしょう。これを、trueの逆であるfalseに変えてみると、動作が変わります。

実は、この引数にtrueを指定すると、子ノードも全てコピーします。対して、falseを指定すると、そのノードしかコピーしません。例えば、<p></p>の部分だけコピーするようなものです。用途に応じて使い分けましょう。