HTML文書をプログラミング言語でアクセスするためのモデルが Document Object Modelである。
以下のHTML文書片を考える。
<body> <p>今回は<em>三権分立</em>がテーマです。</p> <ul> <li>司法</li> <li>立法</li> <li>行政</li> </ul> <p>の3つが…</p> </body>
この文書には、以下のような要素の木構造ができている。
+--「今回は」 | +-[p]--+-[em]--「三権分立」 | | | +--「がテーマです。」 [body]--+ | +-[li]--「司法」 | | +-[ul]-+-[li]--「立法」 | | | +-[li]--「行政」 | | +-[p]--「の3つが…」
図: 要素の木
これと全く同じ木構造が、HTMLユーザエージェントに付随するスクリ プト言語のオブジェクト(複合的な値)として生成される。これを規定したものが DOM (Document Object Model)である。
JavaScriptでは、javascriptプログラムを読み込んだときのHTML文書の あらゆる要素が、JavaScript言語の HTMLElement(の派生) オブジェクトとして 生成されている。「図:要素の木」が示す構造の場合、最初のbody要素を 意味するオブジェクトにアクセスできれば、その子孫の全ての要素オブジェクト にアクセスできる。また、HTML要素に付けられた属性や、スタイルシートの 特性値も自在に取得/設定できる。
documentオブジェクトは、HTML文書全体の情報を保持する。 スタイルシートの操作で必要になるのは、 HTML文書中の特定の要素を探し出す方法で、 そのための関数には以下のものがある。
document.getElementsByTagName(ELEM)
HTML文書中から、ELEM で指定した要素を全て探し、 それらを配列にしたものを返す。
document.getElementById(ID)
HTML文書中から、ID と同一の id 属性を持つ 要素を返す。id属性は文書中で唯一の値を持たせることが前提であるので 同じid属性値が見付かった場合の挙動は定義されていない。
たとえば、上記のHTML断片例で「全てp要素のうち2つ目にあるもの」は、 以下のように JavaScript 変数 p2 に得られる。
var p, p2; // 変数の使用を宣言する var p = document.getElementsByTagName("p"); // 全ての p 要素を得る if (p.length) { p2 = p[1]; // 添字1要素が2番目 }
また、CSSでのセレクタ指定を用いて一覧を得る関数もある。
document.querySelector(CSS-SELECTOR)
HTML文書中から、CSS-SELECTOR で指定した要素を全て探し、
それらのうち文書中最初に登場するものを返す。セレクタはたとえば
"p.shout"
のようなCSSセレクタ規則を指定する。
document.querySelectorAll(CSS-SELECTOR)
上記と同じだが、CSS-SELECTOR で指定した要素全ての リストを返す。
querySelectorによって得られた要素オブジェクトは、 StaticNodeListオブジェクトといい、その値に変更を加えてもDOMツリーには 影響が出ない。
特定の要素を持つオブジェクトから、その要素に設定された属性には、
getAttribute/setAttribute
を介してアクセスできる。例えば、以下のようなHTML要素記述があったとする。
<p>鳥海山:<img src="chokai.jpg" alt="Mt.Chokai"
width="400" height="266"></p>
このうち、img要素に設定された width, height 属性を半分にするスクリプトを作成してみる。JavaScriptプログラムから このimg要素を探しやすいように、id属性を追加し、画像クリックによって 関数が起動するように onclick 属性を追加し、以下のように書き換えておく。
<p>鳥海山:<img src="chokai.jpg" alt="Mt.Chokai"
id="photo01" onclick="hanbun();" width="400" height="266"></p>
getAttribute/setAttribute
を利用JavaScriptプログラムファイル chokai1.js
を開き、hanbun()関数を以下のように作成する。
function hanbun() { chokai = document.getElementById("photo01"); w = chokai.getAttribute("width"); h = chokai.getAttribute("height"); chokai.setAttribute("width", w/2); chokai.setAttribute("height", h/2); }
このスクリプトをロードするようHTML文書に以下のscript要素を追加する。
<p>鳥海山:<img src="chokai.jpg" alt="Mt.Chokai"
id="photo01" onclick="hanbun();" width="400" height="266"></p>
<script type="text/javascript" src="chokai1.js">
</script>
作成例(文書のソースを見よ)
JavaScriptプログラムファイル chokai2.js
を開き、hanbun()関数を以下のように作成する。
function hanbun() { chokai = document.getElementById("photo01"); w = chokai.width; h = chokai.height; chokai.width = w/2; chokai.height = h/2; }
作成例(文書のソースを見よ)
属性値はHTML文書で明示的に定義されていない場合、取得できない場合があ る。スクリプトで操作したい場合はHTML文書中であらかじめ値を与えておく よう注意する。
要素オブジェクトに属するstyleオブジェクトを介してスタイルシートの プロパティがアクセスできる。特性名にハイフンが含まれるものは ハイフンを取って、次の文字を大文字にして結合する。たとえば、
<div id="foo" style="background-color: yellow"> ... </div>
というdiv要素の場合は、以下のJavaScriptで background-color 特性値が 取得できる。
x = document.getElementById("foo"); x.style.backgroundColor;
この変数に代入することで、特性値を変更することもできる。
以下の例は、マウスが入ると赤に、出ると黄色に戻る枠を作成するものであ る。
<html> <head><title>Red and Yellow</title> <style type="text/css"> <!-- div#box { width: 200px; height: 100px; background-color: yellow; } --> </style> </head> <body> <p>マウスを入れると赤、出すと黄色。</p> <div id="box" onmouseover="red();" onmouseout="yellow();"> </div> <script type="text/javascript" src="redyellow.js"> </script> </body> </html>
function red() { document.getElementById("box").style.backgroundColor = "red"; } function yellow() { document.getElementById("box").style.backgroundColor = "yellow"; }
定義例: redyellow.html
CSSの特性値の場合も属性のときと同様、HTML+CSS文書であらかじめ 値を設定していない特性値はスクリプトからは取得できない(nullが返る)。
文書とスタイルの分離という観点からは、CSSの特性値を操作する この方法が最も望ましい。
ひとつの要素オブジェクトが見付かると その他の要素も見付けることができる。「図:要素の木」が示すように、 あらゆる要素は親、兄弟、子を持つ可能性がある。このような性質を持つものを 一般的にノードという。特定の要素をノードとみなし、木の 親兄弟を辿るいくつかの値が定義されている。
プロパティ | 意味 |
---|---|
parentNode | 親ノード |
childNodes | 全ての子ノードを収めたリスト |
firstChild | 最初の子ノード |
lastChild | 最後の子ノード |
previousSibling | ひとつ前の兄弟ノード |
nextSibling | ひとつ次の兄弟ノード |
また、見つかったノードそのものの情報にアクセスするための以下の値が利用できる。
プロパティ | 意味 |
---|---|
tagName | 要素の名前 |
id | 要素がid属性を持っている場合その値 |
innerHTML | 要素の内部のHTML文そのもの (代入すると文書を更新できる) |
style | 要素に施されているスタイルシートの集合 |
以下の例で考える。
<body>
<p id="top">今回は<em>三権分立</em>がテーマです。</p>
<ul>
<li>司法</li>
<li>立法</li>
<li>行政</li>
</ul>
<p>の3つが…</p>
</body>
1つ目のp要素は、id="top" とIDが振ってあるのでこれを足掛かりに、
parentNode
→ body要素
childNodes
→ 「今回は」から「がテーマです。」の全て
previousSibling
→ null(空っぽ)
nextSibling
→ ul要素
となる。これらを辿るプログラム例を示す(dom-demo.html)。
function domDemo() { // 全てのp要素一覧を p に得る var p = document.getElementsByTagName("p"); // 1つ目のp要素を p1 に得る var p1 = p[0]; // 必ずp要素が見つかる場合に限る // p1の親を body に得る var body = p1.parentNode; // p1の子要素を全て得る var pChildren = p1.childNodes; // bodyの背景色を黄色に設定する。 body.style.background = "yellow"; // p1 の子すべての文字色を赤にする for (var i=0; i<pChildren.length; i++) { if (pChildren[i].style) pChildren[i].style.color = "red"; } // body要素の子要素全てのうちulがあればborderを紺の二重枠にする var allChildren = body.childNodes, c; // 変数cもここで宣言 for (i=0; i<allChildren.length; i++) { c = allChildren[i]; // console.log(c.tagName); if (c.tagName && c.tagName.match(/ul/i)) { c.style.border = "navy 3px double"; } } } window.onload = domDemo;