uhyohyo.net

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

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

このページの最終更新日:

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

getElementsByTagName

getElementsByTagNameというメソッドがあります。これはdocumentやノードが持つメソッドです。これは引数に要素名を渡すと、その要素の一覧のNodeListを返します。NodeListについては、二章第三回を参照して下さい。NodeListの重要な特徴は、木構造の変化が反映されるという点です。つまり、getElementsByTagNameを呼び出してから木構造に追加された要素も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 "t"
    • strong
      • #text "es"
    • #text "t"
  • #text
  • p
    • strong
      • #text "t"
    • #text "e"
    • strong
      • #text "st"
  • 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要素"を代入しています。今回のHTMLでは、3つのstrong要素全てにおいて、firstChild(最初の子ノード)は全てテキストノードです。というより、子が1つしかありませんね。本当は、中がテキストノードだけでない可能性もあるのでちゃんと処理したほうがいいのですが、今回は面倒なのでしませんでした。

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

したがって、動作の結果として、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ですね。

このように要素ノードはその種類に応じて、属性に対応するプロパティを持っています。これは基本的に書き換えることで属性を変更可能になっています。ほとんどは属性名と同じ名前のプロパティですが、たまに違う場合があります(先ほどのclassNameプロパティがいい例です)。

さて、このままでは作ったa要素に中身がないので、中身のテキストノードも作ります。この流れは前回と同じですね。

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

a
  • #text "Google"

となります。

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

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

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

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

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

p
  • #text ←これ
  • strong
    • #text
  • #text

です。その直前だから、

p
  • ←ここ
  • strong
    • #text
  • #text

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

p
  • a
    • #text
  • strong
    • #text
  • #text

となったのです。

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