uhyohyo.net

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

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

前回、木構造の操作の基本を解説しました。他にもさまざまなメソッドがあるので、解説します。

getElementsByTagName

getElementsByTagNameというメソッドがあります。これはdocumentやノードが持つメソッドです。これは引数に要素名を渡すと、その要素の一覧のNodeListを返します。NodeListについては、二章第三回を参照して下さい。

documentが持つgetElementsByTagNameの場合、文書全てから探します。ノードが持つgetElementsByTagNameの場合、そのノードより下(子、子の子、そのまた子…)から探します。

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

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>

    <p>t<strong>es</strong>t</p>
    <p><strong>t</strong>e<strong>st</strong></p>

    <script type="text/javascript">
      var nodelist = document.getElementsByTagName('strong');

      console.log(nodelist.length);
    </script>
  </body>
</html>
        

「3」と表示されました。

document.getElementsByTagNameは、今回の場合、文書全てからstrong要素を探し、それをNodeListとして返します。ここで、今回の文書の木構造は、bodyから下を見てみると、

body
|
├―― p
|   |
|   ├――#text
|   |
|   ├――strong
|   |   |
|   |   └――#text
|   |
|   └――#text
├――#text
|
├――  p
|   |
|   ├――strong
|   |   |
|   |   └――#text
|   |
|   ├――#text
|   |
|   └――strong
|       |
|       └――#text
├――#text
|
└――script
    |
    └――#text
        

となっています。bodyの子ノードのうち、pとpの間の#textと、pとscriptの間の#textは改行です。

strongは3箇所あるため、このNodeListには3つの要素が含まれていることになります。そのため、nodelist.lengthを表示すると3になるのでした。

これは、同じ種類の要素をまとめて処理するときなどに使うことができます。次のサンプルを見てみます。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>

    <p>t<strong>es</strong>t</p>
    <p><strong>t</strong>e<strong>st</strong></p>

    <script type="text/javascript">
      var nodelist = document.getElementsByTagName('strong');

      for(var i=0; i<nodelist.length; i++){
        var node = nodelist.item(i);
        node.firstChild.nodeValue = "strong要素";
      }
    </script>
  </body>
</html>
        

このサンプルは、今までの知識を組み合わせれば何をしているのか分かります。

まず、変数nodelistに3つのstrong要素が入ったNodeListを代入しています。

その次からはfor文です。変数iが0から(nodelist.length-1)になるまで、繰り返します。

次の行では変数nodeにnodelistのi番目のノードを代入しています。nodelistのノードは、0番目から(nodelist.length-1)番目まであるため、nodelistの全てのノードに対して処理ができるというわけです。

その次の行では、node.firstChild.nodeValueに"strong要素"を代入しています。3つのstrong要素全てにおいて、firstChild(最初の子ノード)は全てテキストノードです。というより、子が1つしかありませんね。本当は、中がテキストノードだけでない可能性もあるのでちゃんと処理したほうがいいのですが、今回は面倒なのでしませんでした。

そのnodeValueを書き換えているため、strong要素の中の文字列が書き換わるということです。

したがって、動作の結果として、3箇所の強調部分(strongなので大抵は太字で)が全て「strong要素」となります。

HTMLElementのプロパティ

次に、HTMLElementなら、どの要素でも持っている汎用的なプロパティがあります。それについて解説します。

idプロパティ

idというプロパティがあります。これは、そのままその要素のid属性を表します。

<!doctype html>
<html>
  <head>
    <title>test</title>
  </head>
  <body>

    <p id="fff">test</p>

    <script type="text/javascript">
    console.log(document.body.getElementsByTagName('p').item(0).id);
    </script>
  </body>
</html>
        

全て1行にまとまっていて長いので、1つずつ読み解いていきましょう。

document.bodyとは、body要素のHTMLElementでした。HTMLElementが持つgetElementsByTagNameで、body要素より下のp要素の一覧のNodeListを作っています。

といっても、今回の場合は1つだけです。そして、itemメソッドで0番目のノードを取得し、そのidプロパティを表示しています。よって、idの"fff"が表示されます。

また、getElementsByTagName特別な使い方として、タグ名の代わりに"*"を引数とすると、全ての要素を取得できます。

classNameプロパティ

classNameプロパティは、その要素のclass属性を表示します。大抵のプロパティは属性名とそれを取得できるプロパティ名が同じですが、これは珍しく違うため注意が必要です。

class属性は、スタイルシートで要素をタグ名とは別にグループ分けするためのものですが、JavaScriptにも同様のことがいえます。そういう点でなかなか汎用的なプロパティです。

ちなみにclass属性を扱う方法はもうひとつ存在します。そちらは第十二章第一回で解説します。

titleプロパティ

titleプロパティは、その要素のtitle属性を表示します。

title属性は、その要素の補足情報を表すものです。

ほかにもありますが、このくらいがメジャーなところです。

insertBefore

次に、insertBeforeというメソッドを紹介します。これは、前回のappendChildと似ていて、appendChildは子ノードの最後にしか追加できませんでしたが、insertBeforeならどこにでも追加できるというものです。appendChildと同様に、ノードが持つメソッドです。

追加する位置を指定するために、引数が追加するノードの他にもう1つあります。

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

    <script type="text/javascript">
      var a = document.createElement('a');
      a.href = "http://www.google.com/";

      var textnode = document.createTextNode("Google");
      a.appendChild(textnode);

      var p = document.getElementById('aaaaa');
      p.insertBefore(a, p.firstChild);
    </script>
  </body>
</html>
        

p要素の先頭にa要素が追加されたのが分かります。

最初の2行では、a要素を作っています。まずcreateElementでa要素を作り、aに代入しています。a要素のHTMLElementは、HTMLAnchorElementといいます。

このHTMLAnchorElementは多くのプロパティを持っています。その1つが、次の行で代入されているhrefです。

これはそのままhref属性で、書き換えもできます。つまり、a要素のhref属性を設定しています。この場合GoogleのURLですね。

しかし、このままではやはり<a></a>のように中身がないから、中身のテキストノードも作ります。この流れは前回と同じですね。

"Google"というテキストノードを作り、aの子ノードに追加しています。つまり、

 a
|
└――#text
          

となります。

今回は、これをp要素に追加します。そこで、次の行で、getElementByIdを使ってp要素を取得しています。

次の行で、insertBeforeが使われています。引数が、1つめは追加するノードである変数aで、もうひとつはp.firstChildです。

これはどういうことかというと、この2つめの引数には、親となるノード(この場合p要素)の子ノードのうちのどれかを渡す必要があります。

そうした場合、その子ノードのに新しいノードを追加します。

つまり、今回は、p.firstChild、つまり

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

です。その直前だから、

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

に追加されます。その結果、

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

となったのです。

自由な位置にノードを追加できるので、なかなか便利です。