プログラミング初心者必見!DOMを理解するとHTMLページが思い通りに動かせる!
DOMとは?
WEBページを作成するうえで避けては通れない知識「DOM」本記事ではプログラミング初心者の方が躓くポイントであるDOMを丁寧にわかりやすく解説します。この記事を読むことで、動的ページを自由自在に作成することができるようになります。是非最後まで目を通し、実際に手を動かして習得していただければ幸いです。
環境設定
実際に手を動かして挙動を確認したい方は以下の環境設定をお願いします。
- VisualStudioCode(コードエディター)
https://azure.microsoft.com/ja-jp/products/visual-studio-code/ - GoogleChrome
https://www.google.co.jp/chrome/?brand=RPHE&gclid=Cj0KCQiAsqOMBhDFARIsAFBTN3dUVNqcF4gIyJsnpzcZTBeoFgLN16AGGeey6e5k7N8KAc44-1pq0RgaAsNLEALw_wcB&gclsrc=aw.ds
DOMの構造
DOMとはDocument Object Model (ドキュメント オブジェクト モデル)の略で HTML や XML 文書のためのプログラミングインターフェイスです。ページを表現するため、プログラムが文書構造、スタイル、内容を変更することができます。DOM は文書をノードとオブジェクトで表現します。つまり、DOMを理解することで、ブラウザに表示されるテキストの内容を変更したり、背景色を変更することが可能になります。
具体的なDOMの使用方法はHTMLファイルの「ここからここまで」に「このような処理をしたい」という取り決めを行うことをいいます。「ここからここまで」という取り決めを「ノード」と呼びます。ノードを正しく理解することで、JavaScriptを使った動的ページを作ることができるようになります。
初心者A子さん
マチコ先生
【ノードの種類】
- 要素ノード…HTMLタグを表します。DOMでは、HTMLタグのことを「要素」と呼びます。
- テキストノード…タグ内に記述されている属性を表します。Aタグのhref属性やIMGタグのsrc属性などが該当します。
- コメントノード…コメントを表すオブジェクト
- ドキュメントノード…HTML文書全体を表します。JavaScriptでは、documentオブジェクトがドキュメントノードを参照します。
この4種類以外にもいくつか種類がありますが、「要素ノード」と「テキストノード」の2種類を意識しておけばOKです。
DOMツリーとは
先ほどのDOMの種類を理解していくうえでDOMツリーという知識が必要です。DOMツリーとはHTMLドキュメントやXMLドキュメントをプログラムから利用するための集合体として階層のことを指します。つまりノードを階層分けしたものがDOMツリーということです。
実際にコードを見ながら、解説していきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>たいとる</title>
<meta chareset="utf-8">
</head>
<body>
<h1>h1見出し</h1>
<!-- 本文が入る -->
<p id="text">こんにちは!</p>
</body>
</html>
上記のコードをDOMツリーで表してみましょう。
document *d
└ html *a
├ head *a
│ ├ 空白 *b
│ ├ title *a
│ ├ 空白 *b
│ ├ meta *a
│ └ 空白 *b
├ 空白 *b
└ body *a
├ 空白 *b
├ h1 *a
│ └ たいとる *b
├ 空白 *b
├ コメント(本文が入る) *c
├ 空白 *b
├ p *a
│ └ こんにちは! *b
└ 空白 *b
*a: 要素ノード
*b: テキストノード
*c: コメントノード
*d: ドキュメントノード
コードを見る限り、「空白」は無いように見えますが、DOMツリーでは空白はテキストと扱われます。 (インラインボックスの要素の場合、前後に空白がある場合、1つの半角スペースがあるかのように振舞います)そして「空白」は空白ノードというテキストノードの1種に分類されるので注意しましょう。
そしてノードには親子関係があり、bodyタグはh1タグの親ノード、htmlタグの子ノードのように位置関係によって呼び方が変わります。ここでは見ている階層によって各要素の呼び方が変わるということを覚えておいてください。
初心者A子さん
マチコ先生
DOMの取得方法
概念としてDOM、ノード、DOMツリーは理解できたかと思います。続いてはJavaScriptで動かすためにDOMを取得する必要があります。
※JavaScriptの文法知識が必要になります。
環境設定
VSCodeを開いてhtmlファイルを作成しましょう。拡張子をhtmlとし、以下のコードをコピー&ペーストしてください。
VSコードのファイルをGoogleChromeのタブにドラッグ&ドロップすることで、画像のようなページが見えるはずです。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>見出し</h1>
<p id="title1">おはよう</p>
<p id="title2">こんにちは</p>
<p id="title3">こんばんわ</p>
<script>
</script>
</body>
</html>
ID属性による検索
JavaScriptで使用するgetElementById
はどんな入門書にも最初に出てくるメソッドではないでしょうか。引数に指定された id 属性を持つ要素ノードを、DOM 全体から検索します。実際にコードを書くと以下のようになります。
<script>タグ内を以下のように書き換えてください。
const ans = document.getElementById('title1');
console.log(ans);
ブラウザ(GoogleChrome)で検証画面を開き、確認しましょう。
※検証画面はブラウザ上を右クリックして「検証」もしくは「Shift+Ctrl+i」で開くことができます。
Consoleタブをクリックすると、idがtitle1の要素が返ってきているのがわかります。
※検索して見つからなければnullが返ります。
セレクターによる検索
querySelector
による検索は、セレクター文字列を引数に取り、合致する要素を検索します。このセレクター文字列は、CSS で用いるセレクターと同じです。querySelector
は getElementById
と同じように、単一の要素ノードを返却します。セレクターに合致する要素が文書中に複数存在する場合は、HTML 的に一番上に書かれている要素が取得されます。
<script>タグ内を以下のように書き換えてください。
const ans = document.querySelector('#title1');
console.log(ans);
さきほどとほぼ同じですが、検索対象が(‘#title’)となっています。セレクターによる検索では文字列を引数にとるので指定してあげないといけません。ちなみに「#」はidを表す記号、クラスなら「.」になります。
検索して見つからなければnullが返ります。
要素名から検索
指定した要素ノードへの参照を格納したHTMLCollectionを返します。ワイルドカード(*
)の使用が可能で、要素ノードから本メソッドの実行が可能です。
<script>タグ内を以下のように書き換えてください。
const ans = document.getElementsByTagName("p");
console.log(ans);
getElementById
と似ていますが、こちらはElementsと複数形になっています。なぜかというと、以下の画像からもわかるように取れる要素が複数あるからです。
今回のコードでは<p>タグが3つあるので、要素も3つ取得できています。
- 指定した要素ノードへの参照を格納したHTMLCollectionを返します。
- ワイルドカード(
*
)の使用が可能です。 - 要素ノードから本メソッドの実行が可能です。
親要素の取得
ある要素の親要素は、parentNode
プロパティから取得することができます。取得したい親要素の一つ下の階層のノードを指定します。idがtitle1の親要素を取得してみましょう。<script>タグ内を以下のように書き換えてください。
const text = document.getElementById("title1");
const parent = text.parentNode;
console.log(parent);
id=title1の親要素は,<body>なので、ちゃんと親要素がとれていることがわかります。
子要素の取得
親要素取得と同じように、子要素も取得することができます。childNodes
や children
プロパティから取得できます。parentNode
プロパティ と違う点はchildNodes
プロパティは、子要素の一覧を表す NodeList
にアクセスできます。
※孫やそれ以降のノードは含まれません
<script>タグ内を以下のように書き換えてください。
const lists = document.querySelector('body');
const listItems = lists.childNodes;
console.log(listItems);
bodyタグの子要素をすべて取得することができました。複数の要素が取得できるため、childNodesと複数形になっている点に注意してください。
兄弟要素の取得
続いては親でも子でもない同一階層の兄弟要素の取得方法になります。DOMツリーで見ると隣り合うノードになります。
今回使用しているコードでは<h1><p><p><p>タグが同一階層の兄弟要素になるので<h1>タグの次の要素である<p>タグを取得してみましょう。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>見出し</h1>
<p id="title1">おはよう</p>
<p id="title2">こんにちは</p>
<p id="title3">こんばんわ</p>
<script>
const siblings = document.querySelector('h1');
console.log(siblings.nextSibling);
</script>
</body>
</html>
同一階層にあることがわかったので、取得方法はnextSibling
プロパティで取得します。h1タグの次の兄弟要素である<p>タグを取得します。
おや、おおかしですね。<p id=”title1″>おはよう</p>ではなく、#textが返ってきてしまいました。
初心者A子さん
マチコ先生
nextElementSibling
プロパティつまり「次の兄弟要素」を使えば、テキストノードを除いて次の要素を得られます。
<script>タグ内を以下のように書き換えてください。
const siblings = document.querySelector('h1');
console.log(siblings.nextElementSibling);
これで同一階層の次の要素である <p id="title1">おはよう</p>
が返ってくるはずです。
プロパティ一覧
紹介したプロパティ一覧になります。適宜使い分けてみてください。
プロパティ名 | 概要 |
---|---|
parentElement | 親要素ノードへの参照。(親要素ノードがない場合はnull) |
children | 子要素ノードへの参照を格納するHTMLCollection |
firstElementChild | 最初の子要素ノード。(子要素ノードがない場合はnull) |
lastElementChild | 最後の子要素ノード。(子要素ノードがない場合はnull) |
nextElementSibling | 兄弟要素ノードの中で次の要素ノード。(次の兄弟要素ノードをもたない場合はnull) |
previousElementSibling | 兄弟要素ノードの中で1つ前の要素ノード。(前の兄弟要素ノードをもたない場合はnull) |
childElementCount | 子要素ノードの数。(= children.length) |
複数要素の配列変換方法
配列変換方法
getElementsByTagName
やchildNodes
で取得した複数の要素を配列に変換することで、Array型のメソッドで自由に呼び出すことができます。
<script>タグ内を以下のように書き換えてください。
const p = document.getElementsByTagName('p');
// pの要素をすべて「p」という変数に代入
const listItems = Array.prototype.slice.call(p, 0);
// sliceメソッドを用いて配列に変換
console.log(listItems[1]);
// 配列の2番目の要素を出力
ループ処理方法(For文)
先ほどと同様に複数形の要素をリスト化してループ処理をしてみましょう。
<script>タグ内を以下のように書き換えてください。
const listItems = document.getElementsByTagName('p');
for (let i = 0; i < listItems.length; i++) {
console.log(listItems[i].textContent);
}
pタグの要素をすべて配列に格納し、for文をつかってすべての要素のtextContentを返しています。
for文の詳細は以下「MDNWebDocsページ」をご確認ください。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for
リストのループ処理方法(Foreach文)
結果としてはfor文とほぼ変わりませんが、ループの条件を指定しなくてもよいので配列内の要素すべてを出力したい場合に有効です。
<script>タグ内を以下のように 書き換えてください。
const list = document.querySelector('body');
const listItems = list.children;
Array.prototype.forEach.call(listItems, item => {
console.log(item.textContent);
});
今回はpタグではなく、bodyタグの子要素のtextContentをすべてconsole.logで出力しています。
ちなみに4行目のitem.textContent
をitem.id
に変更するとidを指定して出力することができるので、適宜使い分けてみてください。
forEach文の詳細は以下「MDNWebDocsページ」をご確認ください。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
DOMを使った要素の書き換え
DOM要素の検索、取得、リスト化までできるようになりました。ここから取得した要素を書き換える処理を行っていきます。
初心者A子さん
マチコ先生
まずはコードを紹介します。以下のコードをコピー&ペーストして実際に触ってみてください。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>今日のあいさつ文</h1>
<hr/>
<div id="changeText"></div>
<form name="form1" id="id_form1" action="">
<input name="textBox1" id="id_textBox1" type="text" value="" />
<input type="button" value="送信" onclick="onButtonClick();" />
</form>
<script>
function onButtonClick() {
target = document.getElementById("changeText");
target.innerText = document.forms.id_form1.id_textBox1.value;
}
</script>
</body>
</html>
いかがでしょうか。フォームに文字を入力し、送信ボタンを押すことで、<hr>タグの上に入力した内容が反映されたかと思います。流れとしては、フォームにテキストを入力し、送信ボタンを押すことで、JavaScriptのイベントが発火し、取得したDOM要素を書き換えるという処理になります。
まとめ
いかがだったでしょうか。HTMLとDOMの基礎知識は習得できたと思いますので、「JavaScript DOM」や「DOM操作方法」などを検索し、さらに知見を深めることで、もっと自由にHTMLファイルを変化させることができるようになります。知識だけではなく、実際に手を動かすことがなによりも大事なので、面倒くさがらずご自身でいろいろと試していただけると幸いです。ここまで読んでいただきありがとうございました。