DOM

JavaScriptは、HTMLの内容を書き換えることができます。

本ページでは、DOM(Document Object Model)について説明します。

DOMとは

DOMは、プログラムから文書へアクセスするための方法を取り決めたものです。

DOMでは、HTMLの要素をオブジェクトとして扱います。例えば、段落を示すp要素がオブジェクトになります。オブジェクトのため、プロパティやメソッドを使ってHTMLの内容を読み書きしたり、操作したりできます。

DOMの概要

例えば、p要素の"テスト"というテキストを"変更"に書き換えたり、文字の色を赤に変えたりできます。

DOMは、JavaScriptからHTMLへアクセスするためだけのものではありませんが、ここではJavaScriptとHTMLに限定して説明します。

ノード

HTMLの要素をオブジェクトとして扱うと説明しましたが、これらはノードと呼ばれます。ノードには、以下があります。

要素ノード
pなどのHTML要素
テキストノード
p要素などに含まれる文字列

pの子要素としてspanがある場合、spanは子ノードと呼ばれます。また、p要素に記述したテキストも子ノードになります。

DOMインターフェース

スクリプトは、DOMインターフェースを介してノードにアクセスできます。DOMインターフェースは、プロパティやメソッドを定義したコンストラクタ関数です。

DOMインターフェース

例えば、img要素はHTMLImageElementインターフェースが使えます。そこには、srcプロパティが定義されていて、その値を変えると表示される画像ファイルが切り替わります。

HTMLImageElementのプロトタイプは、HTMLElementです。このため、HTMLElementで定義されたプロパティやメソッドは、継承によってimg要素にアクセスするために使えます。

このプロトタイプチェーンは、以下のように示されます。

DOMインターフェースのプロトタイプチェーン

ここで理解すべきことは、DOMインターフェースを使ってノードのプロパティを変更したり(例:文字の色を赤に変える)、メソッドによってノードを追加したり(例:p要素を追加)することができるということです。

その際、img要素に用意されたプロパティやメソッドだけでなく、プロトタイプチェーン上にあるプロパティやメソッドも、継承できるものはすべて使えるということです。

ノードの取得

JavaScriptからHTMLへアクセスするためには、まずノードの取得が必要です。ノードを取得する方法は、何種類かあります。以下に、例を示します。

【ノードの取得例】
<p id="id1" class="class1">テスト
<span>です。</span>
</p>

<script>
//セレクタを使って1つのノードを取得
const a = document.querySelector("#id1 span");

//セレクタを使って複数のノードを取得
const b = document.querySelectorAll(".class1");

//IDを指定してノードを取得
const c = document.getElementById("id1");

//クラスを指定して複数のノードを取得
const d = document.getElementsByClassName("class1");

//要素を指定して複数のノードを取得
const e = document.getElementsByTagName("span");
</script>

上記は、すべてDocumentインターフェースで用意されています。以下は、利用方法です。

querySelector
querySelectorは、CSSセレクタと同じ書き方で、要素を特定します。セレクタが使えるため、汎用的に要素を特定できます。複数一致する場合は、最初の1つめの要素になります。
querySelectorALL
querySelectorAllもセレクタと同じ書き方で、要素を特定します。複数一致しても、すべて取得できます。取得したノードは、b[0]などと指定が必要です。0が最初のノードです。次はb[1]になります。
getElementById
getElementByIdは、IDを指定して要素を特定します。
getElementsByClassName
getElementsByClassNameは、クラスを指定して要素を特定します。クラスは複数要素で同じ名前が使えるため、取得したノードはd[0]やd[1]などと指定が必要です。
getElementsByTagName
getElementsByTagNameは、要素名を指定します。同じ要素名が複数箇所で使えるため、取得したノードはe[0]やe[1]などと指定が必要です。

ノードを取得した後は、a.プロパティやb[0].メソッドなどで値を取得・書き換えたり、操作したりできます。次からは、その利用方法を説明します。

テキストノードの更新

テキストノードを更新するためには、Nodeインターフェースで用意されているtextContentプロパティが使えます。以下は、利用例です。

【textContentプロパティの利用例】
<p id="test">テスト</p>

<script>
const x = document.querySelector("#test");
x.textContent = "書き換え";
</script>

これで、p要素は"書き換え"と表示されます。もし、テキストを最後に追加したい時はx.textContent = x.textContent + "書き換え"とします。これで、"テスト書き換え"となります。

textContentは、タグを解釈しません。タグを解釈させたい場合は、Elementインターフェースで用意されているinnerHTMLプロパティを使います。

【innerHTMLプロパティの利用例】
<p id="test">テスト</p>

<script>
const x = document.querySelector("#test");
x.innerHTML = x.innerHTML + "<br>書き換え";
</script>

上記により、"テスト"の後に改行されて"書き換え"が表示されます。

要素ノードの追加

要素ノードは、Documentインターフェースで用意されているcreateElementメソッドで作成できます。また、作成した要素ノードをHTMLに追加するためには、Nodeインターフェースで用意されているappendChildメソッドが使えます。以下は、例です。

【createElementとappendChildメソッドの利用例】
<div id="test">
<p>テスト</p>
</div>

<script>
const x = document.createElement("p")
const y = document.querySelector("#test");
x.textContent = "追加";
y.appendChild(x);
</script>

createElement("p")で、p要素を作成しています。appendChild(x);で、IDがtestの要素の最後に作成した要素を追加しています。

このため、"テスト"と表示される段落の後に、"追加"の段落が追加されます。

もう1つの方法として、Elementインターフェースで用意されているinsertAdjacentHTMLメソッドが使えます。以下は、例です。

【insertAdjacentHTMLメソッドの利用例】
<p id="test">テスト</p>

<script>
const x = document.querySelector("#test");
x.insertAdjacentHTML("afterend", "<p>追加</p>");
</script>

上記の結果は、createElementで要素から作成した時と同じです。

insertAdjacentHTMLのキーワードは、以下が使えます。

【insertAdjacentHTMLで使えるキーワード】
キーワード 説明
beforebegin 指定ノードの直前に追加
afterbegin 指定ノード内の最初に追加
beforeend 指定ノード内の最後に追加
afterend 指定ノードの直後に追加

例えば、先ほどのスクリプトで最後の行をx.insertAdjacentHTML("afterbegin", "追加");とすると、p要素のコンテンツが"追加テスト"になります。

要素ノードの削除

要素ノードは、Elementインターフェースで用意されているremoveメソッドが使えます。以下は、例です。

【removeメソッドの利用例】
<p id="test">テスト</p>

<script>
const x = document.querySelector("#test");
x.remove();
</script>

これで、p要素が削除されます。ただし、removeメソッドは、Internet Explorerでサポートされていません。

Internet Explorerでもサポートされているメソッドとしては、Nodeインターフェースで用意されているremoveChildがあります。以下は、例です。

【removeChildメソッドの利用例】
<p id="test">テスト</p>

<script>
const x = document.querySelector("#test");
x.parentNode.removeChild(x);
</script>

属性の変更

属性を変更する例を2つ挙げます。1つめは、img要素のsrc属性です。これは、HTMLImageElementインターフェースで用意されているsrcプロパティを使って行えます。以下は、例です。

【srcプロパティの利用例】
<img id="test" src="image1.png" alt="">

<script>
const x = document.querySelector("#test");
x.src = "image2.png";
</script>

上記により、image2.pngの画像が表示されます。

もう1つの例は、style属性の変更です。これは、HTMLElementインターフェースで用意されているstyleプロパティを使って行えます。以下は、例です。

【styleプロパティの利用例】
<p id="test" style="color:red;">テスト</p>

<script>
const x = document.querySelector("#test");
x.style.color = "blue";
</script>

上記で、表示される色は青になります。

styleの後に指定するcolorなどのプロパティ名は、キャメルケースで記述が必要です。キャメルケースではハイフン(-)を使わずに、2つめの単語の先頭を大文字にします。例えば、background-colorプロパティを指定する時はbackgroundColorと記述します。

DOMツリー

以下のHTMLがあったとします。

【DOMツリーを説明するためのHTML】
<html>

<head>
<title>タイトル</title>
</head>

<body>
<section>
<h1>見出し</h1>
<p>段落</p>
</section>
</body>

</html>

このHTMLは、ノードが以下のようなツリー構造になります。

DOMツリー

これを、DOMツリーと呼びます。DOMツリーを利用して、要素にアクセスすることもできます。

例えば、const x = document.getElementsByTagName("section")[1].getElementsByTagName("p")[0];で取得した場合、2つめのセクションの最初の段落が取得できます。