
javascript DOM:WEBサイトデータをブラウザ上で変更できる機能
javascript DOMはブラウザ上のWEBデータ(Documentオブジェクト)に対して様々な変更を加える事ができるものです。
WEBページの階層構造や各ノードを軸にして特定個所を検索し、追加や変更・削除などを実行する事が可能です。
javascript DOMには様々なメソッドがあり、それを覚える事で様々な変化をさせる事ができます。
javascript DOMとは何か?
本記事はJavaScript初心者の方向けに、ブラウザにおけるJavaScript開発の基礎となるDOMについて解説します。
JavaScriptの一番の役目は、描画されたWEBページの表示を用途に応じて変化させる事です。
WEBページの記述をJavascriptによって変更するためには、DOMの知識が必須となります。
DOMを知る事がJavascriptコード書く際の指針になると言えるでしょう。
DOMとは
DOMとは「Document Object Model」の略で、先述した通りJavascriptでhtmlソースコードを操作するための仕組みです。
ブラウザに表示される文字の大きさや色等の表現は、前もってHTMLとCSSで構成されたものですよね。
設置されたHTMLとCSSで指定された内容通りに、WEBページが描画される訳です。
WEBページの表示を変えたい
ただし時には、描画内容を後から変更したい場合が出てきます。
例えば条件によって文字の色を変えたり大きくしたり、内容を追加したり消したり等、その用途は様々です。
これらは全てページを閲覧しているユーザーのためです。視覚的変化が全く起きないWEBページではユーザーを満足させる事はできません。
ユーザーの要望に応えるWEBページとなるために、WEBページ表示の変更機能は必須でしょう。
構成ファイルは変更できない
ところがサーバーにアップされているHTMLやCSSファイルは構成が固定されているため、変更を加える事はできません。
この時HTMLやCSSファイルを変更せず、出力されたブラウザ上のデータに直接変更を加えるのがDOMです。
データの変更対象箇所(Aの部分)を決めて(Bに変更する)変更処理を掛ける事ができます。
ブラウザがWEBページを表示する仕組み
まずはブラウザがWEBページを読み込む仕組みを簡単にご紹介しましょう。
ブラウザはまず、WEBサーバーから受け取ったHTMLとCSSを解析してDOMと呼ばれるデータ構造に変換します。
このDOMデータが画面にレンダリングされる訳です。
生成データを変換・格納
つまりHTMLとCSSとで構成されたデータを、ブラウザの中にあるDOMというデータに変換・格納した状態です。
これは、HTML・CSSファイルとは別の位置にデータが生成・格納されている事になります。
Javascriptを使ってブラウザ内部にあるこのDOMにアクセスし、その内容を書き換えることができる訳です。
DOMが書き換えられると、新たなDOMに応じて瞬時に画面内容が再描画される仕組みで、ページ遷移の必要がなく描画自体が変わってくれるのが特徴です。
DOMデータのある場所
Windowオブジェクトの中にある
DOMデータは、Windowオブジェクトの中の一項目に存在します。
Windowオブジェクトとはブラウザが持っている情報丸ごとを指します。
Windowオブジェクトは、今開いているブラウザタブが持つあらゆる情報を格納しています。
Documentオブジェクト
このWindowオブジェクトの中には様々な項目プロパティがありますが、中でも重要なのが「documentプロパティ」です。
このdocumentプロパティの中に入っているのが、WEB生成データである「Documentオブジェクト」になります。
Documentオブジェクトは、構成されたHTMLのコンテンツ情報を全て保持する役割を持っています。
ブラウザ全体の情報…Windowオブジェクトが保有
WEBサイトに関する情報…Documentオブジェクトが保有
HTMLとCSSで生成されたWEBページのデータは、このDocumentオブジェクトの中に入っている訳ですね。
DOMは、このDocumentオブジェクト内にあるデータに対して要素の取得・操作などを実行します。
反映されたデータがブラウザに表示される事になります。
HTML上の道しるべ「階層構造」
ではDOMはどのようにして「Aの場所をBに変更する」という命令を実行するのでしょうか。
もちろんページを視覚的にみている訳ではありません。私たちユーザーとは見方が違うのです。
DOMはツリー構造で見ている
DOMは、HTMLによって出力された要素の関係を「ツリー構造」で見ています。
HTML文章を画面に表示すると、上記の様なツリー構造になっている事がわかります。
要素は必ず別の要素の内側か外側か同位置、いずれかに属する事になりますね。
この階層構造が、Javascriptによって変更を加える際の「道しるべ」になる訳です。
場所を特定するために、プログラム側としては階層構造を導線にする必要があるのです。
HTML側でも受ける準備
逆に言えばきちんとした階層構造でHTMLを構築しておく必要がありますね。
でないとJavascriptが目印をつける時に迷ってしまい、正常に稼働しない場合があります。
ですのでJavascriptで後から変更を加える事を前提として、HTML側で準備しておく必要があります。
各要素やタグを示す「ノード」
目印となる階層構造とともに重要なのが、要素の指定の仕方です。
上の図にあるように、HTML上の要素やタグ自体のことを「ノード」と呼びます。
ノードには様々な呼び方・分類の仕方があります。
親・子・兄弟ノード
ノードを、階層の位置関係によって家族名称をつけて呼ぶ事があります。
そのためには基準となるノードを指定します。基準が変われば親子関係も変わりますからね。
・親ノード
・子ノード
・兄弟ノード
指定されたノードに対し、その上位階層にあるノードを「親ノード」と呼び、その配下にあるノードを「子ノード」と呼びます。
また同一階層にあるノードのことを「兄弟ノード」と表現します。
要素・テキストノード
家族間でノードを示す以外にも、大きく2つのノード分類ができます。
・要素ノード
・テキストノード
「要素ノード」はHTML要素自体を示し、それぞれに属性やstyle情報が付与されています。
「テキストノード」は要素や属性を持っていないテキスト部分を指します。
JavascriptでDOMのデータを書き換えるためには、ブラウザ上のDOMから特定のノード情報(目印)を取得しなければなりません。
先程も言いましたがWEBページの表面を見ている訳ではないので、階層構造とノードを頼りに場所を特定する必要があります。
DOMにより取得したノード情報を書き換える事で、ブラウザ上のWEBページ表示を変える事ができる訳です。
DOMは言われた事しかしませんから、希望する変更結果になるようにHTMLを整備する必要がありますね。
ノードの検索・取得
まずは変更する箇所を特定する事が先決です。そのためには階層構造上のノードを検索する必要があります。
対象を検索するメソッドには様々なものがあります。
・getElementById
・querySelector
・querySelectorAll
id名やclass名、あるいは親子関係などを使って、対象とする箇所を検索・特定していきます。
id属性の検索
getElementById
「getElementById」は、id属性を指定する最も有名な命令です。
<h1 id="check1"></h1>
上記のh1タグ内id=""の中に入った「check1」がid属性ですね。
getElementByIdは、DOM全体から指定されたid属性を持つ要素ノードを検索し、見つからなければnullを返します。
<script> const h1 = document.getElementById("check1"); console.log(h1); </script>
これで、check1というidを持った要素を丸ごと取得してきます。
Consoleに表示を切り替えると、h1タグで囲まれたすべてが取得されているのが確認できます。
セレクタによる検索
querySelector
「querySelector」は、セレクタ文字列を検索・指定します。
セレクタ文字列とは、HTML上のdivやh1-6、p、sectionなどの要素タグを示します。
「querySelector」は「getElementById」と同じように、単一の要素ノードを返します。
一致する要素がDOM中に複数ある場合は、HTML上一番上に書かれている要素が取得され、見つからない場合はnullを返します。
<script> const check = document.querySelector('#check1'); </script>
上記の場合、idがcheck1になっているセレクタ(HTMLタグ)を一つ指定する事になります。
querySelectorAll
「querySelectorAll」は、セレクタに合致する複数の要素を返します。
具体的には、NodeListオブジェクトが返され、見つからない場合は空のNodeListが返されます。
<script> const checks = document.querySelectorAll('.check'); </script>
上記の場合、クラス名にcheckがついているセレクタを全て探すことになります。
※返されるNodeListはノードが複数集まった集合体で、配列のようなイメージと考えて下さい。
特定ノード範囲からの検索
documentがHTML全体から要素を検索するのに対し、特定の要素範囲から指定のセレクタを検索することもできます。
<div class="box"> <p class="btn">クリックして下さい</p> </div>
<script> const box = document.querySelector('.box'); const btn = box.querySelector('.btn'); </script>
上記の場合、boxクラス名を付与された要素内からbuttonクラスのついたノードを返します。
親要素からの取得
さらに階層構造を活かした検索も可能です。
例えばある要素の親要素の場合、parentNodeプロパティからアクセスできます。
<div class="box"> <p class="btn">クリックして下さい</p> </div>
<script> const btn = document.querySelector('.btn'); const box = btn.parentNode; </script>
上記の場合、buttonセレクタの親要素ノード「div」を取得しています。
子要素からの取得
childNodesやchildrenプロパティを使えば、子要素を取得できます。
childNodes
<ul> <li>Red</li> <li>Blue</li> <li>Green</li> </ul>
<script> const list = document.querySelector('ul'); const listItems = list.childNodes; </script>
childNodesプロパティは、子要素の一覧を表すNodeListにのみアクセスでき、孫やそれ以降のノードは含まれません。
RedやBlueのテキスト部分(テキストノード)も含んで丸ごと対象になります。
children
同様の効果を持つchildrenプロパティは、HTML要素のみの一覧を返すためテキストノードは含みません。
<script> const listItems = list.children; </script>
兄弟要素からの取得
ある要素の兄弟、つまり隣り合った要素を取得する方法もあります。
nextSibling
nextSiblingプロパティは、同列にあるノードを返します。
<p id="item1">Red</p> <p id="item2">Blue</p> <p id="item3">Green</p>
<script> const one = document.querySelector('#item1'); console.log(one.nextSibling); </script> 空白のノードが返る
上記の場合、2つ目の<p id="item2">blue</p>の部分が返るはずですが、実はそうはならず空白のテキストノードが返されます。
これはなぜかというと、コード上の改行やホワイトスペースも、テキストノードの形でDOMの一部に組み込まれるためです。
つまり「改行部分」が、2つ目としてカウントされていることになりますね。
nextElementSibling
ここで「nextElementSibling」プロパティを使えば、改行やスペースなどのテキストノードを除いた次の要素を返します。
<script> const one = document.querySelector('#item1'); console.log(one.nextElementSibling); </script> <p id="item2">Blue</p>が取得される
属性の取得と更新
属性値の操作
要素の属性値は、getAttributeやsetAttributeメソッドで取得したり更新したりします。
DOMにおいては、付与された属性を取得して操作する事が基本になります。
属性値の取得
<script> const content = element.getAttribute('content'); </script>
属性値の更新
<script> element.setAttribute('title', 'content'); 属性値titleがcontentに代わる </script>
クラス属性の操作
クラス属性は値を複数持つため、classListプロパティを使って操作します。
クラスを追加する
<script> element.classList.add('check1'); class=""にcheck1が追加される </script>
クラスを削除する
<script> element.classList.remove('check1'); </script>
クラスの有無を切り替える
<script> element.classList.toggle('check1'); 実行されるたびつけ外しがされる </script>
クラス属性のあり・なし確認
<script> element.classList.contains('check1'); あればtrue、なければfalse </script>
カスタムデータ属性
開発者がHTML要素にオリジナルの属性を設定する場合は、data-で始まる命名を用いるのが標準仕様です。
<div id="item" data-my-name="Red">...</div>
これらの属性はカスタムデータ属性と呼ばれます。
Javascriptの場合、datasetプロパティから以下のように値にアクセスできます。
<script> const element = document.querySelector('#item'); console.log(element.dataset.myName); ここが現在は「Red」 element.dataset.myName = 'Brue'; 「Blue」に変更 </script>
カスタムデータ属性は、Javascriptとの連携が主な目的となります。
ある要素に、その要素特有のデータを持たせる事ができ、idやclassとは違います。
idは文書の中である要素を1つ特定するための属性であり、classは要素を複数特定してグループ化する属性です。
これに対してカスタムデータ属性は、要素にアプリケーション固有の設定値を与えることができます。
変更を前提とするデータについては前もってカスタムデータとしておき、JavascriptでDOM変更を加えるのが主流になります。
DOMの生成・追加
新しいDOMを生み出す
Javascriptを使えば、最初のDOM上に存在していない要素を生み出す事もできます。
<p>テキスト1</p> <p>テキスト2</p>
pタグの「テキスト1・2」ありますが、ここにもう1つpタグを作成して追加してみましょう。
要素を生成するには、createElementメソッドを用います。
要素内のテキストを生成するには、createTextNodeメソッドを用います。
<script> const p = document.createElement('p'); const text = document.createTextNode("テキスト3"); </script>
しかしこのままではまだ「テキスト3」の入ったpタグが、どの親要素の下につくかを指定していません。
ですので実行してもまだ追加はされないのですね。
DOMを新しく追加する
ですので「要素3」をブラウザで表示させるためには、既存の要素のどれかを親要素に指定し、子要素として追加する必要があります。
appendChild
特定の親要素の下に子要素を追加するためのメソッドが、appendChildメソッドです。
bodyタグを親として指定し、作ったp要素を子要素として追加してみます。
<p>要素1</p> <p>要素2</p>
<script> const p = document.createElement('p'); const text = document.createTextNode("テキスト3"); document.body.appendChild(p).appendChild(text); </script>
挿入後
<p>要素1</p> <p>要素2</p> <p>要素3</p>
その他の追加メソッド
また他にも、要素を挿入する方法はたくさんあります。
innerHTMLプロパティ
insertAdjacentElementメソッド
insertBeforeメソッド
DOMを削除する
removeメソッドを用いれば、既存のDOM上の要素を削除する事もできます。
removeメソッド
<script> element.remove(); </script>
ただしIEでは動作しないため、ポリフィルを読み込むか以下の方法で実現しましょう。
一度親要素を取得してから removeChild を実行する
<script> const parent = element.parentNode; parent.removeChild(element); </script>
以上本記事では、JavaScriptの超基礎講座として、DOMの操作方法を見ていきました。
DOMとは何か、そして要素の検索・取得・作成・追加・削除という基本操作を紹介しました。
本記事は単なるさわりの部分でしかなく、他にDOMメソッドはたくさん用意されています。色々調べて見て下さい。