概要
JavaScriptの理解を深めるため、
で学習した内容を記載していく。
本記事では、DOMについて記載する。
DOM
DOMの役割
・ボタンを押したら、ボタンのデザインが変わる
・ページをスクロールすると、途中で広告バナーが表示される
・入力フォームで、内容を間違えると「正しく入力してください」とエラーが表示される
DOM
を使うことで、このように動的な表現力を手に入れることができる。
以下の内容でHTMLファイルを保存する。保存後、HTMLファイルをブラウザで開く。
<!DOCTYPE html>
<html>
<head>
<meta chaset="utf-8">
</head>
<body>
<div id="sample">オリジナルのテキストです</div>
</body>
</html>
次にブラウザのデベロッパーツールのコンソールを開き、以下のコードを実行する。
const tag = window.document.querySelector('#sample');
tag.textContent = ''テキストを書き換えます;
このように、DOMを一言で表すと「JavaScriptからHTMLを操作するための仕組み」ということになる。
DOMはWindowオブジェクト配下のDocumentオブジェクトなので、DOMに関するすべての機能は、window.document
オブジェクトから呼び出して使う。
DOMはツリー構造
HTMLは要素の中に、別の要素を入れ子のように組み立てることができる。DOMはHTMLの文書構造をそのまま表現しているので、同様に要素同士が親子関係のようなツリー構造になっている。
<!DOCTYPE html>
<html>
<head>
<meta chaset="utf-8">
<title>ページのタイトル</title>
</head>
<body>
<div>
<p>テキストです。<strong>強調します。</strong></p>
<p>他のテキストです。</p>
</div>
</body>
</html>
ノードの種類
ツリーを構成している1つひとつのHTML要素をノード
と呼ぶ。
先ほどの例だと<html>
はルートノードである。ルートノードはHTMLの中にただ1つだけ存在する。つまり<html>
がルートノードになる。
そして<div>
は<body>
の子ノード。逆に<body>
は<div>
タグから見ると親ノードである。<div>
の下にある<p>
は兄弟ノードになる。
### 要素を探す
特定要素を探す
HTMLの要素を操作するには、まず操作対象となる要素を探す必要がある。
document.querySelector(CSSセレクタ);
querySelector()
は引数にCSSセレクタを渡すと、それに一致する最初の要素を返す。
<!DOCTYPE html>
<html>
<head>
<meta chaset="utf-8">
</head>
<body>
<div id="sample">class 属性が sample 1個目</div>
<div id="sample">class 属性が sample 2個目</div>
<div id="sample">class 属性が sample 3個目</div>
</body>
</html>
const element = document.querySelector('.sample');
console.log(element);
すべての特定要素を探す
CSSセレクタにマッチするすべての要素を取得したい場合はquerySelectorAll()
を使う。
document.querySelectorAll(CSSセレクタ);
querySelectorAll()は複数のHTML要素を取得するため、戻り値はNodeList
と呼ばれる特殊な配列形式のデータになる。
NodeListは通常の配列と同じようにlength
プロパティで配列内の数を調べることができる。
const elements = document.querySelectorAll('.sample');
console.log(elements.length);
配列のそれぞれの要素にアクセスするためにはfor...of
を使ってループ処理をする。
const elements = document.querySelectorAll('.sample');
for (const element of elements) {
console.log(element); // <div>タグが順次出力される
}
あるいは、配列のインデックスで直接アクセスすることもできる。
const elements = document.querySelectorAll('.sample');
console.log(elements[0]);
要素を変更する
要素のテキストを変更する
テキストを変更するにはtextContent
プロパティを使う。
要素.textContent = '変更したいテキスト';
textContentを使ってテキストを変更してみる。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<p>テキストです</p>
</body>
</html>
作成したHTMLファイルをブラウザで開いてデベロッパーツールのコンソールから以下のコードを実行する。
const p = document.querySelector('p');
p.textContent = '変更します';
要素の属性を変更する
// 指定属性の値を参照する
要素.属性名
// 指定属性の値を変更する
要素.属性名 = '変更したい値';
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<img src="sample.jpg" width="200" height="200">
</body>
</html>
画像の高さと幅が200pxの正方形のものを使って表示している。それを以下のコードを実行し、横長にしてみる。
const img = document.querySelector('img');
img.width = 300;
カスタムデータ属性について
あらかじめ定義されている属性以外に、任意の属性を指定することができるカスタムデータ属性
というものがある。data-
から始まる属性名で表現され、どのようなタグにも使うことができる。
data-任意の名前="値"
例えば以下のようにユーザ名を表示する
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="profile" data-id="100" data-user-name="zaru">zaru</div>
</body>
</html>
次にデベロッパーツールで以下のコードを実行する。ユーザには見えていなかった属性を、dataset
というプロパティを使って参照することができる。
const profile = document.querySelector('.profile');
console.log(profile.dataset.id);
console.log(profile.dataset.userName);
また、通常の属性と同じように値の書き換えもできる。
const profile = document.querySelector('.profile');
profile.dataset.id = 999;
profile.dataset.userName = 'new zaru';
console.log(profile.dataset.id);
console.log(profile);
CSSを変更する
Styleオブジェクト
を使うことでCSSを直接変更することができる。style
の後にドット(.
)でCSSのプロパティ名をつなげて操作する。
要素.style.CSSプロパティ名 = '値';
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<p>テキストです</p>
</body>
</html>
p要素のstyleオブジェクトのfontSizeプロパティに36pxを指定する。
const p = document.querySelector('p');
p.style.fontSize = '36px';
class属性を変更する
フォントのサイズや色、背景色など複数のCSSを変更しようとすると、複数のコードを書くようになりコードが煩雑になる。
const p = document.querySelector('p');
// 装飾の変更するコードが増えて読みにくい状態
p.style.fontSize = '36px';
p.style.color = 'red';
p.style.backgroundColor = 'yellow';
そこで、あらかじめCSSでスタイルをclass名で定義しておき、HTML要素のclass属性を変更することで見た目を切り替える方法がよく使われる。
例として.normalクラスと.warningクラスという2つのクラスを作る。通常は.normalクラスにし、警告を表現したいときには.warningクラスに切り替えるようにしてみる。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
<style>
.normal {
font-size: 16px;
color: black;
background-color: white;
}
.warning {
font-size: 36px;
color: red;
background-color: yellow;
}
</head>
<body>
<p class="normal">テキストです</p>
</body>
</html>
要素のクラスを変更するにはClassListオブジェクト
を使う。.normalクラスから.warningクラスに変えたいので、まずは.normalクラスを削除する。削除するにはremove()
メソッドを使う。
要素.classList.remove('削除するクラス名');
const element = document.querySelector('p');
element.classList.remove('normal');
続いて.warningクラスを追加する。追加するにはadd()
メソッドを使う。
要素.classList.add('追加するクラス名');
const element = document.querySelector('p');
element.classList.add('warning');
add()とremove()を使ったコードはreplace()
で書き換えることもできる。
const element = document.querySelector('p');
element.classList.replace('normal', 'warning');
要素を作成する
DOM要素はあらかじめHTMLファイルに書かれた要素だけではなく、createElement()
メソッドを使って自由に作ることもできる。引数にタグの名前を渡すと要素オブジェクトが作成される。
document.createElement('タグの名前');
const element = document.createElement('p');
console.log(element);
しかし要素オブジェクトを作成しただけでは、まだブラウザに表示される要素にはなっていない。実際に表示させるためにはいくつかのメソッドを使って、HTMLに要素オブジェクトを反映させる必要がある。
要素を末尾に追加する
createElementで作った要素オブジェクトをブラウザに表示するにはappend()
というメソッドを使う。append()は指定要素の子要素として、末尾に要素を追加することができる。
親要素.append(追加する要素);
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<p>最初からある要素です</p>
</div>
</body>
</html>
デベロッパーツールのコンソールで以下のコードを実行すると
要素が追加される。
const newElement = document.createElement('p');
newElement.textContent = '新しく追加しました';
const content = document.querySelector('.content');
content.append(newElement);
まずcreateElement()メソッドで<p>
要素オブジェクトを作成し、textContentプロパティでテキストを設定する。
作成した<p>
要素オブジェクトをappend()を使い.contentクラスの<div>
要素の子要素として末尾に追加する。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<p>最初からある要素です</p>
<p>新しく追加しました</p> ←追加された要素
</div>
</body>
</html>
逆に子要素の先頭に追加するにはprepend()
を使う。
親要素.prepend(追加する要素);
const newElement = document.createElement('p');
newElement.textContent = '先頭に追加します';
const content = document.querySelector('.content');
content.prepend(newElement);
すると、一番先頭に新しい要素が追加されているのを確認できる。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<p>先頭に追加します</p> ←追加された要素
<p>最初からある要素です</p>
</div>
</body>
</html>
指定要素の前や後ろに追加する
指定要素の前後に追加するにはbefore()
とafter()
を使う。その名前の通り、before()
は指定要素の前に要素を追加し、after()
は後ろに追加する。
指定要素.before(追加する要素);
指定要素.after(追加する要素);
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<!-- ここに新しい要素を追加したい -->
<p class="first">最初からある要素です</p>
</div>
</body>
</html>
今回は親要素は使わない。前後の軸となる.first要素さえ取得できれば追加することができる。
const newElement = document.createElement('p');
newElement.textContent = '新しく追加しました';
const firstElement = document.querySelector('.first');
firstElement.before(newElement);
このコードを実行すると、以下のHTMLと同じ状態になる。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<p>新しく追加しました</p> ←追加された要素
<p class="first">最初からある要素です</p>
</div>
</body>
</html>
要素を削除する
削除したい要素.remove();
.firstクラスの<p>
要素を削除する。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<!-- ↓この要素を削除したい -->
<p class="first">最初からある要素です</p>
</div>
</body>
</html>
ブラウザのデベロッパーツールコンソールで以下のコードを実行する。
const firstElement = document.querySelector('.first');
firstElement.remove();
このコードを実行すると、以下のHTMLと同じ状態になる。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
</div>
</body>
</html>
要素を置換する
既存要素を新しい要素で置き換えるにはreplaceWith()
を使う。
置き換えたい要素.replaceWith(置き換える要素);
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<!-- ↓この要素を別の要素に置換したい -->
<p class="first">最初からある要素です</p>
</div>
</body>
</html>
デベロッパーツールのコンソールで以下のコードを実行する。
const newElement = document.createElement('p');
newElement.textContent = '置き換える要素です';
const firstElement = document.querySelector('.first');
firstElement.replaceWith(newElement);
このコードを実行すると、以下のHTMLと同じ状態になる。
<!DOCTYPE html>
<html>
<head>
<meta chaset="UTF-8">
</head>
<body>
<div class="content">
<p>置き換える要素です</p>
</div>
</body>
</html>