はじめに
ウェブ制作において、JavaScriptによるDOM(Document Object Model)の操作は、ウェブページの要素を動的に制御するための基本的なスキルです。
DOMはウェブページの構造を表現するためのツリー構造で、HTML要素を親子関係で結びつけます。JavaScriptを使用してDOMを操作することで、テキストの変更や、要素の追加・削除、スタイルの変更など、ウェブページの外観と動作を制御することができます。
この記事では、JavaScriptを使ったDOM操作を基本から学んでいきます。DOM操作の理解は、初学者がJavaScriptを扱う上で不可欠なスキルです。この記事を通じてDOM操作の基本を習得し、JavaScriptの強力な側面に触れてみましょう。
この記事の対象者
- HTML、CSSについて基本的な知識がある方
- JavaScript初学者の方
- JavaScriptでHTML要素を操作する必要がある方
この記事で学べること
- JavaScriptにおいての基本的なDOMの役割
- HTML要素をJavaScriptで扱う方法
- JavaScriptで要素のテキストや属性を変更する方法
- JavaScriptで要素のclass属性を制御する方法
- 要素に対してイベントリスナーを登録する方法
前提知識
プログラミングの基本知識がない初学者の方向けに、この記事で扱うプログラミングの基本要素について簡単に解説しておきます。
- データ型:プログラミングにおいて、文字列や数値といったデータは異なる目的で利用されます。どのようなデータ型を定義できるかはプログラミング言語の種類によって異なります。
- 変数:データを格納するための箱のようなものです。変数には様々な種類のデータ(文字列、数値、真偽値、配列、オブジェクトなど)を格納できます。
- 関数:一連のタスクを実行するためのコードのブロックです。functionキーワードで関数を定義し、その関数を呼び出すことで、同じ処理を様々な場面で再利用することができます。
これらの機能は、プログラミングの基本要素としてJavaScript以外のプログラミング言語でも実装されており、記述方法は言語によって違いがあります。この記事では、DOMの操作の基本からはじめ、段階的に説明していきます。必要に応じて復習しながら学習していただけると良いかと思います。
DOMの基本
DOM(Document Object Model)は、ウェブページの構造を表現するためのツリー構造です。DOMは、HTML文書をコンピューターが理解しやすい形式に変換し、JavaScriptなどで操作するための仕組みと考えることができます。DOMを利用することで、ウェブページの要素にアクセスしてインタラクティブにテキストの変更や要素の追加・削除、スタイルの変更を行うことができます。
DOMツリーについて
DOMツリーは、HTML文書の各要素を親子関係で結びつけた構造です。HTML文書は、一つのルート要素(通常はhtml要素)から始まり、その中にhead要素とbody要素などが含まれ、更にその中に他の要素がネストされています。この階層構造は、DOMツリーにおいて各要素が親と子の関係を持つことを意味します。
例として、以下は簡単なHTML文書のDOMツリーを示しています。
html
├── head
│ ├── meta
│ └── title
└── body
├── h1
├── p
└── a
このDOMツリーでは、html要素がルート要素であり、head要素とbody要素がその子要素として含まれています。さらに、head要素内にはmeta要素とtitle要素が、body要素にはh1要素、p要素、a要素が子要素として含まれています。HTMLは以下のような構造のものが上記のDOMツリーに該当します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body>
<h1>Hello World!</h1>
<p>JavaScriptを学びましょう!
JavaScriptを初めて学ぶ方は以下の記事がオススメです!</p>
<a href="https://ns-adwork.com/javascript/3227/">【入門】JavaScriptとは?本質を理解して効率よく学ぼう</a>
</body>
</html>
DOM要素について
DOMツリーの各要素は、JavaScriptを使用してアクセスできるオブジェクトとして表現されます。各要素は、要素の種類(div, p, aなど)、属性(id, class, srcなど)や、子要素や親要素、兄弟要素への参照といった情報をオブジェクトのプロパティとして持っています。これにより、JavaScriptを使用して要素の内容や属性を変更し、ウェブページの外観や動作を制御することができます。
変数を宣言して要素を取得する方法
DOMを操作するためには、JavaScriptで要素を取得する必要があります。これにより、その要素に対して操作や変更を行うことができるようになります。取得した要素は変数に格納することが一般的です。ここでは、変数の宣言方法について簡単に触れ、要素を取得する際の方法としてよく使用されるメソッドである、document.getElementById()とdocument.querySelector()について解説します。
変数の宣言
JavaScriptは動的型付け言語なのでデータ型の宣言は必要ありません。よって、変数を宣言するための記述はとてもシンプルです。
// let 変数名 = 格納するデータ
let myVariable = 'Hello World';
変数の宣言にはletやconstといったキーワードを使用します。その後、半角スペースで区切って変数名を記述し、「=」を挟んで変数に格納するデータを記述します。また、可読性のためにも「=」の両端には半角スペースを記述します。
上記のコードでは、myVariable変数に「Hello World」という文字列を格納しています。変数に値を格納することを「代入」といい、letキーワードで宣言された変数は再代入が可能です。再代入を行う際はletキーワードの記述は不要です。
myVariable = 'Welcome to the World';
宣言した変数を使用するときはそのまま変数名を記述します。
let myVariable = 'Hello World';
console.log(myVariable); // 出力: Hello World
myVariable = 'Welcome to the World';
console.log(myVariable); // 出力: Welcome to the World
変数を宣言する際のキーワードはlet以外にもvarとconstがあり、どれを選択するかにより扱い方が少し異なります。以下の記事で変数の宣言方法について詳しく解説しているので、気になる方は参考にしてください。
続いて、要素の取得方法について解説します。
要素の取得
JavaScriptで要素を取得するには、document.getElementById()メソッドやdocument.querySelector()メソッドを使用します。これらの使用方法について解説します。
document.getElementById()メソッド
document.getElementById()メソッドは、指定されたid属性を持つ要素を取得します。要素のid属性は一意でなければならず、同じid属性を持つ要素がページ内で複数存在してはいけません。以下はdocument.getElementById()メソッドの使用例です。
let myElement = document.getElementByEd('my-id');
document.getElementById()メソッドの引数には、取得したい要素のid属性の値を文字列で渡します。上記のコードでは、「my-id」というid属性を持つ要素がmyElement変数に格納されます。これにより、myElement変数を介してmy-idいうid属性を持つ要素を操作できるようになります。
document.querySelector()メソッド
document.querySelector()メソッドは、CSSセレクタを使用して取得する要素を選択することができます。クラスセレクタやタイプセレクタ、IDセレクタなど、CSSで指定できるセレクタを扱うことができるので、document.getElementById()メソッドに比べて柔軟な選択が可能です。以下はdocument.querySelector()メソッドの使用例です。
let myElement = doqument.querySelector('.js-class');
let myPrimaryButton = document.querySelector('button.primary-button');
document.querySelector()メソッドは、ページ内の要素から最初に一致するものを取得します。複数の要素が一致する場合でも最初に見つかった要素のみが返されます。複数の要素を取得する場合は別の方法を選択する必要があります。
document.getElementById()メソッドやdocument.querySelector()メソッドで取得した要素は、Element型やHTMLElement型を継承した、より詳細なオブジェクト(button要素であればHTMLButtonElementなど)として扱うことができます。JavaScriptではこのように、様々なオブジェクトを継承することであらゆる要素の特定の機能を表現しており、関数を含むほとんどの要素は根本的な継承元にObject型を持っています。
要素の取得については以上です。続いて、要素の変更方法について解説します。
要素の変更
DOMの強力な側面は、ウェブページの外観や動作をインタラクティブに変更できることです。ここでは、一般的なDOM操作である、要素のテキスト内容やスタイル、属性を変更する方法について解説します。
テキストの変更
要素のテキスト内容を変更は以下のように行います。
let myElement = document.getElementById('my-id');
myElement.textContent = '新しいテキスト';
JavaScriptにおいてのオブジェクトへのプロパティの値の変更や追加は、変数の宣言や更新と同じで「 = 」を使用します。
DOMから取得した要素はHTMLElement型やElement型、Node型といったオブジェクトを継承しており、Node型によってtextContentプロパティが定義されています。
プロパティがどこで定義されているかは初学者の方がJavaScriptを学ぶ上ではあまり重要ではありません。オブジェクト指向の概念として、JavaScriptでは取得した要素は様々な型を継承しており、それぞれの型は特定の役割を持ってプロパティやメソッドが定義されているところがポイントです。
textContentプロパティには要素のテキスト情報が格納されています。例えば、my-id属性の要素は以下のようなものだとします。
<p id="my-id">デフォルトのテキスト</p>
この要素をdocument.getElementById()メソッドで取得した場合、HTMLParagraphElementという型のオブジェクトになります。この要素のtextContentプロパティの値をコンソールに出力した場合、以下のようになります。
let myElement = document.getElementById('my-id');
console.log(myElement.textContent); // 出力: デフォルトのテキスト
myElement.textContent = '新しいテキスト';
console.log(myElement.textContent); // 出力: 新しいテキスト
textContentプロパティの他にもテキストの変更に使用できるプロパティとして、innerHTMLプロパティやouterHTMLプロパティなどがあり、目的に応じてこれらを使い分けます。この記事はDOM操作の基本をメインとしているのでこれらの解説はしませんが、気になる方は調べてみると良いでしょう。
スタイルの変更
取得した要素はCSSで定義された情報を持っており、これらは「style」というオブジェクトとして取得した要素のプロパティに格納されています。スタイルの変更は以下のように行います。
let myElement = document.getElementById('my-id');
myElement.style.color = 'red';
myElement.style.backgroundColor = 'yellow';
cssのプロパティ名とstyleオブジェクトのプロパティ名には若干の違いがあります。上記の例でいうと、cssプロパティでは背景色を設定する場合「background-color」と記述しますが、styleオブジェクトでは「backgroundColor」と記述します。このように、複数の単語の区切りを大文字で表現する記法を「キャメルケース」と言います。
cssプロパティのような、単語をハイフン( – )で区切る記法を「ケバブケース」と言います。JavaScriptでは、変数名やプロパティ名にハイフンを使用することはできません。また、JavaScriptで定義されている多くのオブジェクトのプロパティ名はキャメルケースで定義されており、自分で変数やオブジェクト、関数を定義する際もキャメルケースで名前を付けることが慣習となっています。
また、プロパティの値は文字列である必要があります。
let myElement = document.getElementById('my-id');
myElement.style.color = red; // 「redが定義されていない」と怒られます
let red = 'red';
myElement.style.color = red; // こちらは問題ありません
styleオブジェクトのプロパティには多くのスタイルを設定することができます。気になる方は以下を実行するとコンソールで確認できます。
console.dir(myElement.style);
属性の変更
JavaScriptで取得した要素は属性名とその値をプロパティとして参照しており、このプロパティにアクセスして値を変更することで、動作やリンク先などをカスタマイズすることができます。例として、a要素のhref属性を変更する場合は以下のように行います。
// a要素を取得
let myLink = document.getElementById('my-link');
myLink.href = 'https://example.com';
JavaScriptにおいて多くのプロパティの名前はキャメルケースで表現されていますが、HTMLの属性名は基本的に区切り文字がなく全て小文字なので、属性を変更する際に指定するプロパティの名前もこれに準ずることに注意が必要です。onclick属性を例にして説明します。
<button id = "myButton" onClick="console.log('クリックされました');">ボタン</button>
上記のようにキャメルケースでonclick属性名を記述しているコードを目にすることがあります。HTMLでは大文字と小文字は区別されず、要素名や属性名などは全て小文字として扱われるため、上記のコードは正常に動作します。
しかし、JavaScriptはHTMLと違って大文字と小文字を区別します。よって、JavaScript側でonclick属性を書き換える場合にプロパティ名を「onClick」と記述すると意図した動作になりません。
// 以下は書き換わります
myButton.onclick = function() { … };
// 以下は書き換わりません
myButton.onClick = function() { … };
具体的には、「myButton.onClick = function() { … };」と記述した場合は新たにonClick()というメソッドがmyButtonに追加されるだけなので、myButtonをクリックしてもonClick()メソッドは実行されません。
HTML要素のonclick属性に記述したJavaScriptコードは、「関数」として要素のクリックイベントに登録されます。よって、JavaScript側でonclickプロパティを変更する場合は関数として記述する必要があり、上記のコードではfunctionキーワードを使用して関数を定義しています。
基本的にはここでご紹介した方法で属性の変更ができますが、class属性に関しては少し方法が異なるのでこれについて解説します。
class属性の変更
取得した要素はclassというプロパティを持っておらず、かわりにclassListというプロパティを持っています。class属性を変更するには、classListプロパティにアクセスして制御する必要があります。classListプロパティには、クラスの追加や削除、指定したクラスを持っているかの確認など、クラスに関するさまざまなメソッドが定義されています。
例として、要素に対してクラスの追加や削除を行う場合は以下のように実装できます。
// クラスの追加
myElement.classList.add('new-class');
// クラスの削除
myElement.classList.remove('old-class');
また、指定したクラスを要素が持っていない場合は追加し、持っている場合は削除するといったこともできます。
myElement.classList.toggle('toggle-class');
ちなみに、classというプロパティをJavaScriptで新たに定義してもclass属性の変更は行われないので注意しましょう。
// 以下はclass属性の変更にはなりません
myElement.class = 'change-class';
class属性の変更は他の属性と方法が異なるので複雑に感じるかもしれませんが、classListでclass属性を管理することには多くのメリットがあり、add()メソッドやremove()メソッド、toggle()メソッドの他にも便利なメソッドが利用できます。興味のある方は調べてみると良いでしょう。
イベントリスナーの登録
イベントリスナーは、ウェブページでイベント(ユーザーのアクション、ブラウザの状態など)が発生した場合に処理を実行させるための仕組みです。イベントにはクリックやマウスオーバー、キー押下、フォームの送信、ウィンドウのリサイズ、ページの読み込み完了など様々な種類があり、要素に対してイベントリスナーを登録することで、インタラクティブにDOMを操作することができます。
イベントリスナーの登録はonclick属性などのHTML属性に設定することでも可能ですが、HTMLにJavaScriptコードを記述すると保守性を損なうなどの理由でaddEventListener()メソッドを使用することが推奨されています。
addEventListener()メソッドはEventTargetというオブジェクトで定義されており、HTMLElementやwindow、documentなどのオブジェクトはEventTargetオブジェクトを継承しています。つまり、基本的にはウェブページ上のあらゆる要素に対してイベントリスナーの登録を行うことができます。
addEventListener()の基本的な使い方
以下はaddEventListener()メソッドの使用例です。
myElement.addEventListener('click', function(event) {
console.log(event.target); // 出力:クリックされた要素
});
()と{}が入れ子構造になっているため、プログラミングを学び始めたばかりの方にとっては分かりにくいかもしれません。括弧の数や順番が正しくないとエラーが発生するので、適切なインデントや改行に気を配るなど、括弧への対応に注意しましょう。
addEventListener()メソッドの第一引数にイベントの種類を文字列で指定します。「’click’」と指定することで、myElementに対してクリックイベントを登録することができます。
第二引数にはfunctionキーワードを使用し、関数として{}内に処理を記述しています。これにより、myElementをクリックした場合に{}内の処理が呼び出されて実行(「発火する」とも言われます)されます。
また、関数の引数として「 event 」というオブジェクトを受け取っています。eventオブジェクトはイベントに関する情報をプロパティとして持っており、イベントの種類に応じた様々な情報にアクセスすることができます。発生したイベントの種類やクリックされた要素などを取得でき、複雑な処理を実装する場合に便利なので覚えておくと良いです。
関数を定義してaddEventListener()メソッドで呼び出す
addEventListener()メソッドの第二引数は、関数を別で定義して呼び出すこともできます。こちらの方が利点が多いので、通常は別で定義した関数を呼び出すかたちで実装します。
JavaScriptでは複数の方法で関数を定義できますが、ここでは他のプログラミング言語と差異が少ない方法で定義します。以下のように行います。
// function 関数名(引数){ 処理 }
function myFunction() {
// 処理を記述
}
functionキーワード先頭に記述し、半角スペースを挟んで関数名を記述します。関数名の後には「()」を記述し、必要に応じて引数を受け取ります。引数とは、この関数を実行するときに渡すことができるデータです。引数を受け取ることで、関数はこのデータを利用して処理をすることができるようになります。
function calc(num1, num2) {
return num1 + num2;
}
console.log(calc(1, 2)); // 出力:3
console.log(calc(2, 4)); // 出力:6
定義した関数をaddEventListener()メソッドで利用する場合、通常の関数の呼び出し方とは異なる点があります。以下が例です。
// 通常の関数の呼び出し
myFunction();
// addEventListenerでの呼び出し
myElement.addEventListener('click', myFunction);
addEventListener()メソッドの第二引数で関数を呼び出す場合、()は不要です。()があると通常の関数の呼び出しと同様に、JavaScriptの解析がその行に到達した時点で関数が実行されてしまいます。必ずエラーが発生するというわけではありませんが、意図した挙動にならない可能性があります。
// クリックされる前に一度myFunction()関数が実行される
myElement.addEventListener('click', myFunction());
// クリックされるまでmyFunction()関数は実行されない
myElement.addEventListener('click', myFunction);
基本的なイベントの種類
一般的によく使用されるイベントについてご紹介します。
- click:要素がクリックされたとき
- mouseover:マウスカーソルが要素の上に移動したとき
- mouseout:マウスカーソルが要素から外れたとき
- keydown:キーボードのキーが押されたとき
- keyup:キーボードのキーが離されたとき
- submit:フォームが送信されたとき
- load:ページが完全に読み込まれたとき
- DOMContentLoaded:ページのレンダリングが完了したとき
- resize:ウィンドウのサイズが変更されたとき
- scroll:要素内でスクロールされたとき
- focus:要素がフォーカスされたとき
- blur:フォーカスが外れたとき
- change:フォーム要素の値が変更されたとき
これらは一般的によく使用されるイベントの一部であり、実際にはさらに多くのイベントがあります。addEventListener()メソッドを使用することで、これらのイベントが発生したときにさまざまな変更を行うことができます。また、addEventListener()メソッドは一つの要素に対して複数のイベントリスナーを登録することもできるので、工夫次第で複雑な表現の実装が可能です。
DOM操作をしてみよう
これまでの解説をもとに、実際にコードを書いてDOM操作をしてみましょう。任意のディレクトリにHTMLファイルを作成して以下を記述します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>DOM操作をしてみよう</title>
<script src="script.js" defer></script>
</head>
<body>
<h1>DOM操作の実践例</h1>
<p id="message">初めてのDOM操作を体験しよう!</p>
<button id="changeButton">テキストを変更</button>
</body>
</html>
続いて、HTMLファイルと同じ階層に「 script.js 」を作成し、以下を記述します。
// ページの読み込みが完了したら実行
document.addEventListener('DOMContentLoaded', function() {
// ボタン要素を取得
let button = document.getElementById('changeButton');
// テキストを変更する関数
function changeText() {
let message = document.getElementById('message');
message.textContent = 'DOM操作が成功しました!';
}
// ボタンクリック時にテキストを変更
button.addEventListener('click', changeText);
});
上記のコードはDOMContentLoadedイベントが発生したときに実行される処理を定義しています。
処理について解説します。まず最初にchangeButtonというidを持つ要素をbutton変数に格納しています。
// ボタン要素を取得
let button = document.getElementById('changeButton');
次に、changeText()関数を定義し、この中で更にmessageというidを持つ要素をmessage変数に格納しています。message変数のtextContentプロパティの値を変更してmessage変数のテキストを変更する処理を記述しています。
// テキストを変更する関数
function changeText() {
let message = document.getElementById('message');
message.textContent = 'DOM操作が成功しました!';
}
最後にbutton変数に対してクリックイベントを登録し、これによってbutton要素がクリックされたタイミングでchangeText関数が実行されるようになります。
関数内で変数を宣言する理由は、変数をなるべく安全に扱いたいためです。変数に対してどこからでもアクセスできてしまうような実装は、変数名の衝突や開発者による解釈の違いによって不用意に値や型が書き換えられる可能性があります。関数内で変数を宣言することにより、その変数を扱える場所を関数内に制限できます。
上記のコードに変更を加えて、さまざまなDOM操作を行ってみてください。以下は比較的簡単な変更例です。
- messageのフォントサイズを変更する
- messageに枠線を追加する
- messageの幅を変更する
- messageの高さを幅と同じにする
- buttonにdisabled属性を追加してクリックイベントを無効にする
また、class属性の付け外しを実装できると表現の幅がとても広がるので、classListオブジェクトによるclass属性の制御は慣れておくと良いと思います。
最後に
この記事では、DOMの基本的な操作方法について学びました。DOM操作はウェブ制作において重要であり、ウェブページの要素をインタラクティブに制御するための基本的なスキルです。この記事の内容について簡潔にまとめます。
- DOMはウェブページの構造を表現し、要素間の親子関係をツリー構造で示します。
- 特定の要素を選択するにはgetElementById()メソッドやquerySelector()メソッドを使用し、これらで取得した要素はJavaScript上でHTMLElementなど複数の型を継承した詳細なオブジェクトとして扱われます。
- このオブジェクトは多くのプロパティやメソッドを持っており、これにアクセスすることでJavaScriptからテキスト内容やスタイル、属性などの変更を行うことができます。
- インタラクティブに変更を加えるにはイベントリスナーの登録が必要であり、イベントの種類を選択することで多彩な表現を実装することができます。
また、プログラミングの基本としてJavaScriptにおいての変数や関数の宣言方法について触れました。これらについてはこの記事の内容を理解するための最低限の内容しか説明していません。変数については以下の記事で詳しく解説しているので、参考にしていただけると幸いです。
関数についての詳しい記事は、今後執筆を予定しています。
