DOMツリー

HTML文書は、その階層構造にしたがったDOM(Document Object Model)ツリーを構成し、HTML文書全体を指す html 要素から木の枝をたどるように JavaScript オブジェクトとしてアクセスすることができる。

HTML要素とツリーの例

次のようなHTML文書を考えよう。

dom-simple.html

dom-simple.html

<!DOCTYPE html>
<html lang="ja">
<head>
<title>簡単なHTML文書</title>
<!-- その1 -->
</head>

<body>
<h1>簡単なHTML文書</h1>
<p>ア行には</p>
<ul>
 <li>あ</li>
 <li>い</li>
 <li>う</li>
 <li>え</li>
 <li>お</li>
</ul>
<p>の5つがあります。</p>
<!-- その2 -->
</body>
</html>

要素の関連を樹形図で表すと次のようになる。

HTML文書のツリー構造

HTML文書から呼び出される JavaScript プログラムでは、文書ツリー全体をグローバル変数 document.documentElement にて取得できる。HTML 文書中の各要素は要素を表現する Element インタフェースのメソッドを通じてアクセスできる。たとえば 図「HTML文書のツリー構造」の全体から html 要素にアクセスできたとすると、 そこから始めて各要素のすべての子要素を階層的に調べていくことですべての要素を たどることができる。

まず、HTML文書を構成する要素をたどって要素名を表示するプログラムを示す。

dom-seekall.js

function dom_seekall(elm, level) {
    var elmstring = "| ".repeat(level) + "▼" + elm.tagName + "要素\n";
    if (elm.children) {		// 子となる要素があるならば
	for (let i=0; i<elm.children.length; i++) {
	    // 1つずつ取り出してさらに dom_seekall() する。
	    elmstring += dom_seekall(elm.children[i], level+1);
	}
	// for (let i of elm.children)		/* このようにしてもよい */
	//   elmstring += dom_seekall(i, level+1);
    }
    return elmstring;
}
alert(dom_seekall(document.documentElement, 0));

このプログラム(dom-seekall.js)を呼ぶ、

<script type="text/javascript" src="dom-seekall.js" charset="utf-8"></script>

の記述を dom-simple.html の「その1」と「その2」の2箇所に挿入して実行させると、 「その1」部分からの実行結果は

▼HTML要素
| ▼HEAD要素
| | ▼TITLE要素
| | ▼SCRIPT要素

となり、「その2」部分からの実行結果は

▼HTML要素
| ▼HEAD要素
| | ▼TITLE要素
| | ▼SCRIPT要素
| ▼BODY要素
| | ▼H1要素
| | ▼P要素
| | ▼UL要素
| | | ▼LI要素
| | | ▼LI要素
| | | ▼LI要素
| | | ▼LI要素
| | | ▼LI要素
| | ▼P要素
| | ▼SCRIPT要素

となる。重要なのは、script 要素で JavaScript プログラムがロードされているときには、それまで読み込んだ HTML 文書の部分集合だけがオブジェクト化されているという点である。

DOMの要素関連追跡

HTML文書中の要素を指すオブジェクトは Element インタフェースを満たす。 このオブジェクトが持つプロパティで、 文書の装飾をするためなどに有用なものを抜粋して示す。

プロパティ意味インタフェース
children子要素のリストElement
childNodes子要素とテキストノードのリスト Node
parentNode親ノードNode

また次のプロパティは、要素の持つ属性へのアクセスに利用できる。

プロパティ意味インタフェース
tagName要素名Element
nodeNameノード名Node
id要素のid値Element
innerHTML 要素の内容のマークアップ言語表現の文字列Element
style 要素のstyle属性HTMLElement

styleプロパティでスタイルシート値にアクセスできる。 この値を操作することにより、動的にWebページの見栄えを変えることができる。 この方法については後述する。

DOM要素を検索するメソッド

木構造の根からたどるのではなく、検索によって HTML 文書要素を取得するメソッドを示す。

メソッド働き返却値
getElementById(id) id属性に id を持つ要素 見付かった要素(Elementオブジェクト)または見付からない場合 null
getElementsByTagName(name) 要素名が name である要素一覧 見付かった要素のリスト(NodeCollection)
querySelector(expr) CSSセレクタ expr にマッチする要素のうち最初のもの 見付かった要素(Element)
querySelectorAll(expr) CSSセレクタ expr にマッチする要素を集めた配列 見付かった要素のリスト(StaticNodeList)

id属性は文書中唯一のものであるから getElementById は合致する単一の要素オブジェクトを返すいっぽう、getElementsByTagName は、たとえ見付かったものが0個や1個でもリストを返す。0個、 つまり見付からない場合の判定は length で個数を調べればよい。つまり、以下のようにする。

var tbl_list = document.getElementsByTagName("table");
if (tbl_list.length == 0) {
  // 見付からない場合の処理
} else {
  for (let i of tbl_list) {		// 見付かったtable要素を順次iに入れ、
    i.style.backgroundColor = "white";	// 背景色を白に変える
  }
}

querySelectorAll(), querySelector() にはCSSファイルに書くような、たとえば "ul.menu" あるいは "ul p" のような規則を指定できる。

要素の属性操作

DOM要素の属性を直接取得または代入することができる。

メソッド働き返却値
getAttribute(attr) 属性 attr の値 属性値
setAttribute(attr, newval) 属性 attrnewval に設定する なし
removeAttribute(attr) 属性 attr の値を除去する なし

要素に関連した値の取得が特別に用意されている属性もある。 たとえばinput要素の value 属性や、スタイルシート用のclass属性である。

input要素の値は value プロパティーで設定する。

class属性の操作は classList プロパティを経由して 以下のメソッドを使用する。

メソッド働き返却値
classList.add(token, ...) 引数に与えた1個以上のクラス名(トークン)をその要素の classリストに追加するなし
classList.remove(token, ...) 引数に与えた1個以上のクラス名(トークン)をその要素の classリストから削除するなし
classList.toggle(token[, force]) 引数に与えたクラス名(トークン)をトグルする。 第2引数に true または false を与えるとそれぞれ設定 または 削除 するtoken がリストに存在するか

スタイルシートの操作

上述の例にもあるように、要素を保持するオブジェクトの style プロパティにてアクセスできる。スタイルシートとしてのプロパティ名のうち ハイフンを含むものは、ハイフンを取り除き、その次の文字を大文字にしたものが JavaScript でのプロパティ名となる。たとえば CSS で次のように定義している要素を考える。

sample.css

table {
  background-color: white;
  margin-left: {4em;}
}  

CSSプロパティ background-colormargin-left はそれぞれ JavaScript オブジェクトプロパティでは backgroundColor および marginLeft という名前となる。

たとえばHTML文書中にある id="foo" の属性を持つ table 要素の背景色と左マージンを操作したいときは以下のようにする。

var target = document.getElementById("foo");
if (target && target.style) {
  // 「要素オブジェクト.style」でCSSプロパティにアクセスできる
  let s = target.style;
  s.backgroundColor = "silver";		// 背景色をsilverに
  s.marginLeft	    = "4em";		// 左マージンを 4em に
}

練習問題

問題

HTML文書の本文のどこかをクリックするとすべての p(パラグラフ)要素の文字サイズが 200%になるようなものを作成せよ。詳細は以下のとおりとする。

解答例

JavaScript プログラム例を示す。

dbl.js

// 例: フォント二倍化
function dblSize() {
    var pElements = document.getElementsByTagName('p');
    if (pElements.length == 0) {
	alert('p要素はこの文書にありません。');
    } else {
	for (let i of pElements) {
	    i.style.fontSize = '200%';
	}
    }
}
document.addEventListener("DOMContentLoaded", function(e) {
    document.body.addEventListener("click", dblSize);
});

実行例