こんにちは、SD部の秦(はた)です。

前回、DOM操作の基本についてご紹介させて頂きました。

【JavaScript】今更聴けない!?DOM操作(1)

今回はもう一歩踏み込んだ操作についてご紹介します。

DOMツリー

DOM操作とは、DOMによってツリー構造を持ったオブジェクトへとパースされた、
ツリー状のオブジェクトを操作することでした。

実際にどのようなツリー構造になるかと言いますと、
このようなHTMLがあった場合、

HTML

<html>
<head>
  <meta charset="utf8">
  <title>DOMツリー</title>
</head>
<body>
  <div id="contents">
    <h1>サンプル</h1>
    <p>これはサンプルです。</p>
  </div>
</body>
</html>

以下の様なツリー構造になります。

※クリックで拡大
dom_tree

さてここで「ツリー構造」という点に着目すると、
ツリーには親と子の関係がありますよね。

この関係を利用して操作を行うことができるんです。

相対的なDOM操作

前回ご紹介したgetElementById()のような絶対的な操作の方法を
「ダイレクトアクセス」と言います。

これに対して相対的な操作の方法を「ノードウォーキング」と言います。

ここで「ノード」という言葉が出てきましたが、
DOMで扱うオブジェクトのことをノード(Node)と言います。

「ノード間を渡り歩く」ので「ノードウォーキング」というわけです。

では、実際のコードを見てみましょう。

JavaScript

var contents = document.getElementById('contents');
var h1 = contents.children[0];
alert(h1.textContent);

h1要素の「サンプル」という文字が表示されます。

「children」プロパティは全ての子要素を保持しています。
似たようなプロパティで「childNodes」というプロパティがありますが、
こちらはテキストノードを含むものになりますので、
通常はchildrenを使うことをオススメします。

childrenで取得した場合

[h1, p]

childNodesで取得した場合

[text, h1, text, p, text]

子要素のルーティング

子要素の取得は連続して行えますので、例えば

JavaScript

var body = document.getElementsByTagName('body')[0];
var h1 = body.children[0].children[0];

このような書き方もできます。

子要素の取得方法は他にもあり、最初の子要素、最後の子要素、
といった指定方法もあります。

最初の子要素の取得には「firstChild」プロパティを使います。
最後の子要素の取得には「lastChild」プロパティを使います。

JavaScript

var body = document.getElementsByTagName('body')[0];
var contents = body.children[0];
var h1 = contents.firstChild;
var p = contents.lastChild;

console.log(h1.textContent);
console.log(p.textContent);

ここで注意が必要なのが、タグの後に改行を入れている場合は、
ノードリストにテキストノードが含まれて改行が取れてしまう、ということです。

改行を含まない場合

HTML

<body><div id="contents"><h1>サンプル</h1><p>これはサンプルです。</p></div></body>

実行結果

サンプル
これはサンプルです。

改行を含む場合

HTML

<body>
  <div id="contents">
    <h1>サンプル</h1>
    <p>これはサンプルです。</p>
  </div>
</body>

実行結果


改行を含んでいるため、firstChild、lastChildでは
先ほどの「childNodesで取得した場合」の
[text, h1, text, p, text]
の1番目と5番目のノードが取得されます。
これらはテキストノードなので、実行結果には何も表示されていません。

これを回避するには「nodeType」の判定を行う必要があります。

JavaScript

var contents = document.getElementsById('contents')[0];
var child = contents.firstChild;

if (child.nodeType == 1) {
  console.log('要素ノードです');
} else {
  console.log('要素ノードではありません');
}

例えば、子要素ノードの一覧を出したい場合は以下のようにします。

JavaScript

var contents = document.getElementById('contents');
var children = contents.childNodes;

var i;

for (i=0; i<children.length; i++) {
	var n = children[i];
	if (n.nodeType == 1) {
		console.log(n.nodeName);
	}
}

実行結果

H1
P

親要素のルーティング

子があれば親もある、ということで親要素も取得してみましょう。

親要素の取得には「parentNode」プロパティを使います。
先ほどのh1要素の取得にparentNodeを加えてみましょう。

var body = document.getElementsByTagName('body')[0];
var h1 = body.children[0].children[0];
var contents = h1.parentNode;

これでh1要素の親であるdiv(id=”contents”)要素が取得できました。

このように、ダイレクトアクセスを使って基点となる要素を取得して子や親にノードウォーキングする、
という流れが多いのではないかと思います。

まとめ

今回のまとめです。

全ての子要素を取得

テキストノードを含まない

node.childlen;

テキストノードを含む

node.childNodes;

最初の子要素を取得

node.firstChild;

最後の子要素を取得

node.lastChild;

親要素を取得

node.parentNode;

以上でDOM操作の第2回目を終わります。

参考リンク

http://hakuhin.jp/js/dom.html