プログラミング初心者必見!DOMを理解するとHTMLページが思い通りに動かせる!

2024.01.04
プログラミング初心者必見!

DOMとは?

WEBページを作成するうえで避けては通れない知識「DOM」本記事ではプログラミング初心者の方が躓くポイントであるDOMを丁寧にわかりやすく解説します。この記事を読むことで、動的ページを自由自在に作成することができるようになります。是非最後まで目を通し、実際に手を動かして習得していただければ幸いです。

環境設定

実際に手を動かして挙動を確認したい方は以下の環境設定をお願いします。

DOMの構造

DOMとはDocument Object Model (ドキュメント オブジェクト モデル)の略で HTML や XML 文書のためのプログラミングインターフェイスです。ページを表現するため、プログラムが文書構造、スタイル、内容を変更することができます。DOM は文書をノードとオブジェクトで表現します。つまり、DOMを理解することで、ブラウザに表示されるテキストの内容を変更したり、背景色を変更することが可能になります。

具体的なDOMの使用方法はHTMLファイルの「ここからここまで」に「このような処理をしたい」という取り決めを行うことをいいます。「ここからここまで」という取り決めを「ノード」と呼びます。ノードを正しく理解することで、JavaScriptを使った動的ページを作ることができるようになります。

DOMってそんなに難しいの!?心折れそうです・・・。

初心者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子さん

マチコ先生

いい質問ね。空白ノードのせいで要素を取得したいときに検索しにくくなってしまうのよ。 [1,空白、2、空白]というリストの2を取得したいときに3番目を指定しないといけないようなイメージよ。

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が返ってきてしまいました。

注意点
コード上の改行やホワイトスペースも、テキストノードの形で DOM の一部に組み込まれてしまいます。 h1要素の次の要素は空白要素になるので、#textが返ってきています。
なるほど!これが空白ノードの厄介なところですね!

初心者A子さん

マチコ先生

そうなの!ただ、nextElementSibling プロパティを使えばテキストノードを除くことができるわ

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番目の要素を出力
配列変換方法のイメージ
pタグの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.textContentitem.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ファイルを変化させることができるようになります。知識だけではなく、実際に手を動かすことがなによりも大事なので、面倒くさがらずご自身でいろいろと試していただけると幸いです。ここまで読んでいただきありがとうございました。

\プログラミングスクールを比較/

DMM WEBCAMP

COACHTECH

RUNTEQ

DMM WEBCAMP COACHTECH RUNTEQ
目指せる姿 WEBエンジニアへの転職
フリーランスエンジニア WEBエンジニアへの転職
分割払い
補助金 ×
転職保証 × ×
受講期間 12週間〜 3ヶ月〜 5ヶ月〜
特徴 【IT業界の転職を一番に考えたい方向け】
大手DMMが運営のプログラミングスクール
転職成功率98.8%
豊富なキャンペーンや補助金制度あり
【フリーランスを目指したい方向け】
フリーランスのエンジニアを最短で目指す
エンジニアと共に実際の案件開発を担当
【とことん勉強してから転職したい方向け】
1,000時間(約9カ月)のカリキュラムでしっかり勉強
企業の求める即戦力のWEBエンジニアを目指す
料金 329,350円〜
※給付金適用後
42万9,000円~ 55万円

公式HP

公式HP

公式HP

関連記事

資料請求

  • 短期集中で最速エンジニア転職を実現-転職成功者インタビュー一覧

    DMM WEBCAMPでは転職成功率98%を実現しています。本資料では、元警察官や元ラーメン屋など様々なバックグラウンドを持つ卒業生の声をお届けします。

    資料をダウンロードする
  • IT技術がもたらす3つの変化と身につけるべきスキル

    IT技術の発展により、今後10~20年程度で47%の仕事がなくなると言われています。どのような変化が訪れ、私達はどのようなスキルを身につけるべきかを解説します。

    資料をダウンロードする
  • 未経験がフリーランスエンジニアになる方法-年収アップで自由な働き方を手に入れる

    働き方改革やリモートワークの影響でフリーランスという働き方の人気は高まりつつあります。フリーランスエンジニアとして活躍するために必要な情報をお届けします。

    資料をダウンロードする

© 2024 WEBCAMP MEDIA Powered by AFFINGER5