- JavaScriptを勉強してコーダーとしてレベルアップしたい!
- jQueryには慣れてきたからvanilla jsも勉強したい!
当記事ではjQueryでは無く、素のJavaScriptのDOM操作について解説しています。
DOMの概念も解説しているので、ただコードをコピペするのではなく、「DOM操作とは何か」を理解出来るようになりますよ。
DOMとは?
DOMとは「Document Object Model」の略で、ブラウザーがHTMLを解析する際に生成するデータ構造のことです。各要素は階層構造(ツリー構造)で表現されます。
JavaScriptでHTMLを操作したいとき、ソースとなるHTMLそのものを操作するわけでなく、DOMにアクセスして操作します。
コーディング時に意識することはないですが、DOMにアクセスする際、裏側ではDOM APIが使われています(※DOM APIとは、クライアントサイド WebAPIの内のひとつです)。
下は動的にHTMLを操作しているサンプルです。
DOM操作の基本的な目的
DOM操作の基本的な目的は、HTMLの操作です。
Webページの見た目や構成を変更する際、JavaScript単体ではソースコード上から直接HTMLを取得することは出来ません。そこでDOMを通してHTMLを取得します。このことを「DOM操作」といいます。
ハンバーガーメニューのアイコン変化や、フォームに入力された内容のバリデーションなど、ユーザー操作にあわせて動的にWeb上の要素を追加・変化させる際にDOM操作が必要となります。
DOMツリーとは
DOMは、HTMLをツリー構造で格納しており、このツリー構造のことを、DOMツリーと呼びます。
DOMツリーは上の図ような流れで、HTMLのタグ・属性・テキストが階層構造で格納されています。階層構造は、HTMLのマークアップと同じ内容になります。
ツリーで構成される各要素を「ノード」と呼びます。
ノードとは
ノードとは、DOMツリーの階層構造を構成している個々の要素です。
ノード | 説明 | コード例 |
---|---|---|
ルートノード | DOMツリーの頂点のノード | <html> |
親ノード | 子要素を持つノードで、HTMLで親要素になっているタグ | <div> <p>↑親ノード</p> </div> |
子孫ノード | 他の要素に含まれているノードで、HTMLの子要素・孫要素 | <div> <p>子孫ノード</p> </div> |
兄弟ノード | 同じ階層にある兄弟要素 | <p>兄弟ノード</p> <p>兄弟ノード</p> |
テキストノード | HTMLタグに囲まれている文字 | <p>これがテキストノード</p> |
コメントノード | コメントのノード | <!– これがコメントノード –> |
HTMLタグはDOMの中で上記のいずれかのノードに当てはまる事になります。
DOM操作の際にJavaScriptは、DOMツリーのノードにアクセスして、HTMLタグの変更などを行います。
DOM操作を扱うための基礎知識
DOM操作をする前に、JavaScriptの基本的な知識について触れておきます。
オブジェクト・メソッド・プロパティの違い
JavaScriptはオブジェクト指向の言語なので、データをオブジェクトとして扱います。
オブジェクトとは、関連のあるデータとなる「プロパティ」の集合体です。
コーディングするときは、JavaScriptで用意されているWindowオブジェクトや、Documentオブジェクトなどを使用します。
オブジェクトを扱う過程で使用するのがメソッドとプロパティです。
オブジェクト | プロパティ | メソッド |
車 | 普通車 | エンジンを掛けてアクセルを踏んだら走る |
車の車種は属性を表すのでプロパティとなり、車を動かす方法は動作となるのでメソッドになります。
プロパティは、オブジェクト名の後に.(ドット)を付けて使用します。
例えば、WebページのURLを取得したい場合はlocation.href
と書きます。.href
の部分がプロパティです。
location.href;
続いてメソッドを見ていきます。メソッドは動作だと解説しましたが、その正体は関数です。オブジェクトの中に定義された関数のことをメソッドと呼びます。
メソッドは、オブジェクト名の後に.(ドット)を付けてさらにその後に()を付けます。
例えば、ページを更新するメソッドはwindow.reload()
と書きます。.reload()
の部分がメソッドです。
window.reload();
メソッドは、関数と同じように、何らかの処理を行ない、その結果を値として返します。
DocumentオブジェクトとWindowオブジェクト
実際にJavaScriptからDOMを取得するには、Documentオブジェクトを参照します。
DOMツリーはDocumentオブジェクトに格納されているため、Documentオブジェクトを通すことでHTMLが取得できます。
また、DocumentオブジェクトはWindowオブジェクトのプロパティです。
Windowオブジェクトは、ブラウザの情報を格納しているオブジェクトです。Documentオブジェクト以外に、ConsoleオブジェクトやEventオブジェクトをプロパティとして格納しています。
DocumentオブジェクトとWindowオブジェクトは、ブラウザの検証ツールから閲覧出来ます。
検証ツールのコンソールタブをクリックして、window
と入力し、Enterキーを押すとWindowオブジェクトが表示されます。
表示されたWindowオブジェクトの「▶︎」をクリックすると、Windowオブジェクトが展開され、メソッドとプロパティの一覧が表示されます。
この中にdocumentプロパティがあります。
documentプロパティを展開すると、さまざまなメソッドやプロパティが確認出来ます。
JavaScriptでDocumentオブジェクトのメソッドやプロパティを使用する際は、オブジェクトの文法のルールでwindow.
を付ける必要がありますが、Windowオブジェクトのみ省略出来ます。
例えば、指定したID属性を持ったHTML要素を取得するdocument.getElementById()
は、window.
を省略して使用できます。window.
を付けても使用できますが、基本的には省略して書きます。
// window有り
window.document.getElementById();
// window無し
document.getElementById();
他にも、JavaScriptでデバッグする際に使用するconsole.log
も、WindowオブジェクトのConsoleプロパティのメソッドですので、window.console.log()
となりますが、省略してconsole.log
と書きます。
// window有り
window.console.log();
// window無し
console.log();
DOM操作の頻出メソッド・プロパティ一覧
WindowオブジェクトとDocumentオブジェクトには、DOM操作をするためのメソッドとプロパティが定義されています。頻出のメソッドとプロパティを下記の表にまとめました。
メソッド
目的 | 内容 | メソッド |
---|---|---|
検索 | idで要素を検索 | document.getElementById(id) |
検索 | classで要素を検索 | document.getElementsByClassName(name) |
検索 | name属性で要素を検索 | document.getElementsByName(name) |
検索 | HTMLタグ名で要素を検索 | document.getElementsByTagName(name) |
検索 | セレクターで合致するはじめの要素のみ検索 | document.querySelector(selectors) |
検索 | セレクターで複数の要素を検索 | document.querySelectorAll(selectors) |
属性取得 | HTMLの属性を取得 | element.getAttribute(name) |
属性更新 | HTMLの属性を設定(上書き) | element.setAttribute(name, value) |
属性削除 | HTMLの属性を削除 | element.removeAttribute(name) |
挿入 | 対象要素の直前に挿入 | element.insertAdjacentElement(‘beforebegin’, object); |
挿入 | 対象要素の内部の最初に挿入 | element.insertAdjacentElement(‘afterbegin’, object); |
挿入 | 対象要素の内部の最後に挿入 | element.insertAdjacentElement(‘beforeend’, object); |
挿入 | 対象要素の直後に挿入 | element.insertAdjacentElement(‘afterend’, object); |
生成 | HTMLタグで要素を作成 | document.createElement(name) |
削除 | 要素を削除 | element.remove() |
削除 | 子要素を削除 | element.removeChild() |
プロパティ
内容 | プロパティ |
---|---|
親要素を取得 | parentNode |
最初の子要素を取得 | firstElementChild |
最後の子要素を取得 | lastElementChild |
子要素リストを取得 | children |
1つ前の要素を取得 | previousElementSibling |
1つ後の要素を取得 | nextElementSibling |
要素の高さを取得 | clientHeight |
要素の幅を取得 | clientWidth |
border-topの長さを取得 | clientTop |
border-leftの長さを取得 | ClientLeft |
複数の値を取得 | classList |
DOM要素の検索
HTMLの要素を検索するコードを紹介します。
IDで要素を検索
document.getElementById(id);
getElementById()
は、HTMLのID属性で要素を検索します。DOM操作の中でも使用頻度がかなり高いメソッドです。
classで要素を検索
document.getElementsByClassName(class);
getElementsByClassName()
は、HTMLのclass属性で要素を検索します。指定した、class名を持つ要素をすべて取得します。
複数要素を取得するメソッドは、HTMLCollectionとして返ります(これ以降解説するメソッドも共通です)。
HTMLCollectionとは
HTMLCollectionとは、要素の一般的なコレクションとして表示される配列のオブジェクトです。
また、HTMLファイル全体では無く、特定の要素内でclassの検索も出来ます。
document.getElementById().getElementsByClassName(class);
getElementById()
で取得した要素の中からclass属性を検索します。検索する範囲を絞れるので、特定の箇所のclassだけを取得したい場合に使えます。
nameで要素を検索
document.getElementsByName(name);
getElementsByName()
は、HTMLのname属性で要素を検索します。指定した、name属性を持つ要素をすべて取得します。
HTMLタグ名で要素を検索
document.getElementsByTagName(tagname);
getElementsByTagName()
は、HTMLのタグ名で要素を検索します。指定した、タグ名の要素をすべて取得します。
また、HTMLファイル全体ではなく、特定の要素内でタグの検索も出来ます。
// 指定したIDを持つ要素内でタグを検索する
document.getElementById(id).getElementsByTagName(tagname);
// 指定したclassを持つ要素内でタグを検索する
document.getElementsByClassName(class).getElementsByTagName(tagname);
このように検索範囲を絞れるので、特定の箇所のタグだけを取得したい場合などに使えます。
セレクタに合致する最初の要素のみ検索
document.querySelector(selectors);
querySelector()
は、指定したセレクタに合致する最初の要素を取得します。指定したセレクタが、複数存在しても、最初の要素しか取得しません。
querySelector()
は、CSSのセレクタと同じ書き方で、取得する要素を指定します。
// classを指定
document.querySelector('.test');
// IDを指定
document.querySelector('#test');
// タグを指定
document.querySelector('div');
// 親要素の中にある子要素を指定
document.querySelector('.test p');
CSSのセレクタと同じ書き方なので、直感的で分かりやすいのがメリットです。上で挙げた例以外の指定方法ももちろん出来ます。
セレクタで複数の要素を検索
document.querySelectorAll(selectors);
querySelectorAll()
はquerySelector()
の複数形で、合致するすべての要素を取得します。セレクタの書き方はCSSと同じです。
属性値を取得
DOM操作でHTML要素の属性の値を取得する方法を解説します。
HTMLの属性を取得
element.getAttribute(attribute);
getAttribute()
は、取得したい属性の名前で、HTML要素の属性の値を取得します。
classやidはもちろん、aタグのhref属性やimgタグのsrc属性の値も取得出来ます。
<div id="hoge"></div>
<div class="hoge"></div>
<a href="https://example.com/"></a>
<img src="img/picture.jpg">
// 要素のidを取得
const getId = document.getElementById('hoge');
getId.getAttribute('id');
// 結果:hoge
// 要素のclassを取得
const getClass = document.querySelector('.hoge');
getClass.getAttribute('class');
// 結果:hoge
// aタグのhref属性を取得
const getAnchor = document.querySelector('a');
getAnchor.getAttribute('href');
// 結果:https://example.com/
// imgタグのsrc属性を取得
const getSrc = document.querySelector('img');
getSrc.getAttribute('src');
// 結果:img/picture.jpg
なお、getAttribute()
はElementオブジェクトのメソッドなので、固有の要素の中から属性を取得します。
Documentオブジェクトのメソッドのように、HTMLファイル全体を対象に検索する事は出来ません。
HTMLの属性を設定(上書き)
element.setAttribute(name, value);
setAttribute()
は、指定した属性の値を上書きします。引数に値を上書きしたい属性と、上書きする属性の値の2つを指定します。
<a href="https://www.example.com"></a>
<img src="/img/picture.jpg" alt="">
<div></div>
// href属性の値を変更する
const getHref = document.querySelector('a');
getHref.setAttribute('href', 'https://www.hoge.com');
// src属性の値を変更する
const getSrc = document.querySelector('img');
getSrc.setAttribute('src', '/img/hoge.jpg');
// class属性を変更する
const getClass = document.querySelector('div');
getClass.setAttribute('class', 'hoge');
<!-- 結果 -->
<a href="https://www.hoge.com"></a>
<img src="/img/hoge.jpg" alt="">
<div class="hoge"></div>
指定した属性が要素に無い場合は、そのまま属性が追加されます。
HTMLの属性を削除
<div id="hoge" class="hoge">この要素から属性を削除します</div>
const getId = document.getElementById('hoge');
getId.removeAttribute('class');
// 結果:<div id="hoge">この要素から属性を削除します</div>
removeAttribute()
は、指定した属性をHTML要素から削除します。
HTML要素の生成・削除
DOM操作で、HTML要素を生成・削除する方法を解説します。
HTML要素の生成
document.createElement(name);
createElement()
は、指定したHTMLタグを新たに作ります。
// divタグを生成
document.createElement('div');
// pタグを生成
document.createElement('p');
// aタグを生成
document.createElement('a');
createElement()
で生成したHTMLタグには、属性が無いため、既に紹介したsetAttribute()
で属性を追加します。
// aタグを生成
const a = document.createElement('a');
// 生成したaタグにhref属性を追加
a.setAttribute('href', 'https://www.example.com');
// 結果:<a href="https://www.example.com"></a>
このようにしてcreateElement()
で生成するHTMLタグに、setAttribute()
で属性を追加出来ます。
HTML要素の削除
element.remove();
remove()
は、指定したHTMLタグを削除します。
<div>
<div id="hoge">この要素が削除されます</div>
</div>
// hogeというid属性を持つ要素を取得
const getId = document.getElementById('hoge');
// id='test'を持つ要素を削除する
getId.remove();
<!-- 結果 -->
<div>
</div>
メソッドの引数に削除するタグ名を指定するのではなく、削除したい要素を取得して、その要素本体に対してremove()
を実行します。
HTML要素の挿入
HTMLにJavaScript側から要素を挿入する方法を解説します。
element.insertAdjacentElement(position, element);
insertAdjacentElement()
は、指定の位置に、指定した要素を追加します。
追加する位置はJavaScript側で決められており、4ヶ所あります。
引数 | 説明 |
beforebegin | 対象要素の前に挿入する |
afterbegin | 対象要素の最初の子要素として挿入する |
beforeend | 対象要素の最後の子要素として挿入する |
afterend | 対象要素の後に挿入する |
対象要素の直前に挿入
<div id="hoge">対象要素です</div>
// 挿入先の要素を取得
const element = document.getElementByID('hoge');
// 挿入する要素を生成
const p = document.createElement('p');
p.textContent = 'この要素が前に挿入されます';
// 要素を挿入する
element.insertAdjacentElement('beforebegin', p);
insertAdjacentElement()
の第一引数にbeforebegin
を指定すると、対象となる要素の前に指定した要素が挿入されます。
<!-- beforebeginの実行結果 -->
<p>この要素が前に挿入されます</p>
<div id="hoge">対象要素です</div>
対象要素の最初の子要素として挿入
<div id="hoge">
<p>↑に要素が挿入されます。</p>
</div>
// 挿入先の要素を取得
const element = document.getElementByID('hoge');
// 挿入する要素を生成
const p = document.createElement('p');
p.textContent = 'この要素が最初の子要素として挿入されます';
// 要素を挿入する
element.insertAdjacentElement('afterbegin', p);
insertAdjacentElement()
の第一引数にafterbegin
を指定すると、対象となる要素の中に最初の子要素として指定した要素が挿入されます。
<!-- afterbeginの実行結果 -->
<div id="hoge">
<p>この要素が最初の子要素として挿入されます</p>
<p>↑に要素が挿入されます。</p>
</div>
対象要素の最後の子要素として挿入
<div id="hoge">
<p>↓に要素が挿入されます。</p>
</div>
// 挿入先の要素を取得
const element = document.getElementByID('hoge');
// 挿入する要素を生成
const p = document.createElement('p');
p.textContent = 'この要素が最後の子要素として挿入されます';
// 要素を挿入する
element.insertAdjacentElement('beforeend', p);
insertAdjacentElement()
の第一引数にbeforeend
を指定すると、対象となる要素の中に最後の子要素として指定した要素が挿入されます。
<!-- beforeendの実行結果 -->
<div id="hoge">
<p>↓に要素が追加されます。</p>
<p>この要素が最後の子要素として挿入されます</p>
</div>
対象要素の直後に挿入
<div id="hoge">対象要素です</div>
// 挿入先の要素を取得
const element = document.getElementByID('hoge');
// 挿入する要素を生成
const p = document.createElement('p');
p.textContent = 'この要素が後に挿入されます';
// 要素を挿入する
element.insertAdjacentElement('afterend', p);
insertAdjacentElement()
の第一引数にafterend
を指定すると、対象となる要素の後に指定した要素が挿入されます。
<!-- afterendの実行結果 -->
<div id="hoge">対象要素です</div>
<p>この要素が後に前に挿入されます</p>
jQueryではなく素のJavaScriptを使えた方がいいの?
ここまで記事を読んできた方の中には、「jQueryを使えば出来ることを、わざわざ素のJavaScriptで書く必要があるの?」と思った方もいるかもしれません。
そもそもjQueryは下記の役割を持たせるために開発されました。
- JavaScriptで書くと煩雑になりがちなコードをカンタンに記述するため
- ブラウザ間でサポートされているコード差を埋めるため
ただ、jQuery本体のファイルの容量が大きいため、Webサイトの表示パフォーマンスの面ではあまり良くありません。また、コードの処理速度の面でもJavaScriptの方が処理速度が速いです。
ただ近年では、JavaScriptでもDOM操作に便利なメソッドやプロパティが導入されたり、ブラウザ間でのコード差も少なくなってきており、上記のjQueryを使用するメリットが薄くなってきています。
こういったWebを取り巻く技術の進化から、JavaScriptを学習する事で得られるメリットは大きいです。
JavaScriptを学習する事で、jQueryで書いていたコードの理解が深まりますし、関数やオブジェクトの理解を深めれば、より綺麗で保守性が高いコードが書けるようになります。
まとめ
JavaScriptのDOM操作について解説しました。
難しく感じたり、どうしても分からない所が出てきたら、コードを分解してメソッドやプロパティの意味を1つずつ確認すると理解に繋がりやすくなります。
また、記事の中でも紹介したブラウザの検証ツールを使って、コンソールタブにconsole.log
で値を出力すると、今どんな値を扱っているのかが見えるのでこちらの方法もオススメです。
最初は難しく感じるかもしれませんが、慣れてくると理解も進んで楽しくなってくるので、ぜひ挑戦してみてください!