目的
Dot installで詳解されているDocument Object Motel (DOM)の内容をまとめる。
//ProgateだとDOMは扱われなかった。
対象
- DOM基礎を学びたい方
- Dot installを一周し、復習をしたい方
詳解JavaScript DOM編
HTMLの基礎 ~DOMとは~
- HTMLを読み込む
- DOMと呼ばれるデータ構造が作成される
- その内容に応じてページが描画される
- Javascriptで操作するのは、htmlではなく、DOM。
Nodeとは
- DOM内の1つ1つのデータをNodeと呼ぶ。
- Documentから始まり、ツリー状に枝分かれ=Node Tree (DOM Tree)
Nodeの種類
- HTMLの要素を表すNode:Element Node (要素Node)
- eg.
<head>
,<title>
- eg.
- Text、改行、空白:Text Node
- 改行、空白もNode。
- ただしhtml要素の先頭と末尾の改行、空白はNodeにならない。
- 改行、空白もNode。
Node間の関係
- 親子・兄弟といった単語を頻用する。
- eg.
head
に対するhtml
: Parent Node - eg.2
head
に対するtitle
: Chiled Node - eg.3
</head>
後の改行、空白と<body>
: Sibling Node
- eg.
DOMの操作
- DOMはdocumentオブジェクトで操作。
要素の取得
-
querySelector(狙う要素(Selector))
: 文書内から特定のSelectorを取得する。 -
要素を取得する際にcssクラスまたはid属性で指定する。
- id属性を指定する際には要素名の前に
#
をつける。 - 見つかった要素のうち、最初の1つしか取得しない。
- id属性を指定する際には要素名の前に
-
querySelectorAll(狙う要素(Selector))[i]
: 文書内の指定したSelectorすべてを対象とする。i
には要素のindex(何番目か?)を指定する。- オブジェクトなので、
.forEach()
が使用可。 - 他にも
-
getElementByTagName('h1')
: 文書内の指定したTagすべてを取得 -
getElementByClassName('box')
: 文書内の指定したclassすべてを取得
-
- オブジェクトなので、
-
getElementById
: id属性を取得する。- 要素名の前に
#
は不要。
- 要素名の前に
-
.chileNode
: 要素の child nodeをすべて取得する。-
.children
: child nodesのうちelement nodesのみ取得する。 -
.firstChild
: 最初のchild noteを取得 -
.lastChild
: 最後のchild noteを取得 -
.firstElementChild
: 最初のchild note (element node)を取得 -
.lastElementChild
: 最後のchild note (element node)を取得
-
-
.parentNode
: 要素の parent nodeを取得する。 -
.previousSibling
: 要素の前のsibling nodeを取得する。-
.previousElementSibling
: 要素の前のsibling node (element node) を取得する。
-
-
.nextSibling
: 要素の後のsibling nodeを取得する。-
.nextElementSibling
: 要素の後のsibling node (element node) を取得する。
-
コードサンプル
-
querySelector(狙う要素)
およびgetElementById
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Javascript DOM Practice</title>
</head>
<body>
<h1 id="target">hogehoge</h1>
<p>fugafuga</p>
<p>fugafuga</p>
<p>fugafuga</p>
<script src="js/main.js"></script>
</body>
</html>
{
function update() {
document.querySelector('#target').textContent = "Changed!";
}
setTimeout(update, 1000);
}
または
{
function update() {
document.getElementById('target').textContent = "Changed!";
}
setTimeout(update, 1000);
}
querySelectorAll(狙う要素)
{
function update() {
document.querySelectorAll('p').forEach((p, index) => {
p.textContent = `${index}番目のpです!`;
});
}
setTimeout(update, 1000);
}
イベント
-
.addEventListener(動作, 関数)
: 指定したnodeについて、ある動作
が起きた際に関数
で指定した処理をする。
// button要素をclickした際に、target idのテキストをChanged!に変更する。
document.querySelector("button").addEventListener("click", () => {
document.getElementById("target").textContent = "Changed!";
});
要素の操作
-
h1
タグのtitle
やcolor
,background-color
要素を操作する。
document.querySelector("button").addEventListener("click", () => {
const targetNode = document.getElementById("target");
targetNode.textContent = "Changed!";
targetNode.title = "This is my title!";
targetNode.style.color = "red";
targetNode.style.backgroundColor = "skyblue";
});
補足
CSSではbackground-color
と指定していたが、javascriptではbackgroundColor
のように、ーを消して2単語目を大文字にする。
※ただし、一般的に見た目の指定は上記のように直接行うのではなく、classを付与する形で行う。
クラスの操作
-
.className = ""
: classを""
内に書き換え
注意!
もともとclassが指定されている要素の場合、classNameで付与したクラスに完全に書き換わる。
-
.classList.add("")
: ""のclassを新規追加。 -
.classList.remove("")
:""のclassを消去。 -
.classList.contains("")
: ""のclassの有無を確認。結果はbooleanで返される。
document.querySelector("button").addEventListener("click", () => {
const targetNode = document.getElementById("target");
//"my-color"classが付与されていたら消去し、付与されていなかったら追加する。
if (targetNode.classList.contains('my-color') === true) {
targetNode.classList.remove("my-color");
} else {
targetNode.classList.add("my-color");
}
});
- 上記と同様の挙動は
.classList.toggle()
で記載可能。
document.querySelector("button").addEventListener("click", () => {
const targetNode = document.getElementById("target");
//"my-color"classが付与されていたら消去し、付与されていなかったら追加する。
targetNode.classList.toggle("my-color");
});
カスタムデータ属性の操作
-
.dataset.(カスタムデータ属性)
htmnl, jsにデータが分散していると後から編集しづらい。そこで、htmlにまとめてデータ属性を付与することで後からの編集をしやすくする。
<body>
<button>Run!</button>
<h1 id="target" data-translation="HOGEHOGE">hogehoge</h1>
<p>fugafuga</p>
<p>fugafuga</p>
<p>fugafuga</p>
<script src="js/main.js">
</script>
</body>
document.querySelector("button").addEventListener("click", () => {
const targetNode = document.getElementById("target");
//h1タグのtextをtranslationで指定した内容に変更する。
targetNode.textContent = targetNode.dataset.translation;
});
要素の追加
- createElement('追加したい要素'): 追加したい要素を生成。
あとは、追加したい要素をquerySelector等で指定すればok.
document.querySelector("button").addEventListener("click", () => {
const item2 = document.createElement('li'); //li要素を生成
item2.textContent = "fuga 2"; //li要素のtextを指定
const ol = document.querySelector('ol');
ol.appendChild(item2); //ol要素の下に追加
});
要素の複製と追加
-
.cloneNode(boolean)
: 指定したノードの複製。()内trueでcontentまで複製。 -
.insertBefore(挿入したいnode, 挿入する場所(このnodeの前に挿入される))
: 指定したnodeの前にnodeを追加する。
document.querySelector("button").addEventListener("click", () => {
const item0 = document.querySelectorAll("li")[0];
const copy = item0.cloneNode(true); //item0のnodeを複製してcopy nodeを生成。falseの場合はitem0のtextが複製されない
const ol = document.querySelector('ol');
const item2 = document.querySelectorAll('li')[2];
ol.insertBefore(copy, item2); //item2の前にcopy nodeを追加。
});
要素の削除
-
.remove('削除したいnode')
: 一部のブラウザで対応不可。 -
.removeChild('削除したいnodeの親node')
: 汎用的に使える方法
{
document.querySelector("button").addEventListener("click", () => {
const item1 = document.querySelectorAll('li')[0];
item1.remove(); //item1 nodeを削除。ただし一部のブラウザでは対応不可。よって書き方も覚えておく。
document.querySelector('ol').removeChild(item1);
});
}
input要素, option要素, ラジオボタンの操作
input要素
-
input
に入力された内容 =>node名.value
で取得可能。
→textContent
にnode名.value
で取得した値を代入する等すれば、input
で受け取った値を表示することが可能になる。
<!-- headは省略 -->
<body>
<input type="text">
<button>Add</button>
<ul>
</ul>
<script src="js/main.js">
</script>
</body>
{
document.querySelector("button").addEventListener("click", () => {
const li = document.createElement("li"); //li要素を追加。
const text = document.querySelector("input");
li.textContent = text.value; //inputフォームに記載された値(value)を取得してli nodeのtextとして代入。
document.querySelector('ul').appendChild(li);
text.value = "";
text.focus();
});
}
option要素
-
select
に対しても、value
で値を取得できる。
<body>
<select>
<option>赤</option>
<option>黄</option>
<option>青</option>
</select>
<button>Add</button>
<ul>
</ul>
<script src="js/main.js">
</script>
</body>
{
document.querySelector("button").addEventListener("click", () => {
const li = document.createElement("li");
const color = document.querySelector("select"); //select内にぶらさがっているchild nodeがすべて取得される。
li.textContent = `${color.value} - ${color.selectedIndex}`;
document.querySelector('ul').appendChild(li);
color.focus();
});
}
ラジオボタン
- ラジオボタンが複数ある場合、
input
要素をすべて取得する必要があるため、select
要素とは異なる点に注意。
<body>
<input type="radio" name="color" value="red"> 赤
<input type="radio" name="color" value="yellow"> 黄
<input type="radio" name="color" value="blue"> 青
<button>Add</button>
<ul>
</ul>
<script src="js/main.js">
</script>
</body>
{
document.querySelector("button").addEventListener("click", () => {
const colors = document.querySelectorAll("input"); //ここですべてのラジオボタンを取得。
let selectedColor; //選択したボタン(色)を入れる変数を準備
colors.forEach(color => {
if (color.checked === true) {
selectedColor = color.value; //ラジオボタン.checkedがtrueとなっている要素の値をselectedColor変数に代入
}
});
const li = document.createElement("li");
li.textContent = selectedColor;
document.querySelector('ul').appendChild(li);
});
}
チェックボックス
- チェックボックスは複数選択可で、チェックした要素を配列で扱うことに注意。
<body>
<input type="checkbox" value="red"> 赤
<input type="checkbox" value="yellow"> 黄
<input type="checkbox" value="blue"> 青
<button>Add</button>
<ul>
</ul>
<script src="js/main.js">
</script>
</body>
{
document.querySelector("button").addEventListener("click", () => {
const colors = document.querySelectorAll("input");
const selectedColors = []; //チェックボックスの場合、複数選択可。要素を配列で保持しておく。配列の内容は変わるが、再代入はされないため、constで宣言する。
colors.forEach(color => {
if (color.checked === true) {
selectedColors.push(color.value); //pushでtrueだったcolorのvalue追加
}
});
const li = document.createElement("li");
li.textContent = selectedColors.join(","); //, 区切りで値を代入
document.querySelector("ul").appendChild(li);
});
}
- 配列への要素の追加:
.push()
- 配列を文字列として代入:
.join('区切り文字')
様々なイベント
-
dblclick
: ダブルクリックしたとき -
mousemove
: マウスを動かしたとき -
keydown
: キーを押したとき- ここで引数を渡すと、マウスの座標・押されたキー等取得できる。
- ここで指定する引数をevent objectと呼び、慣習的に
e
で指定される。
'use strict';
{
document.querySelector("button").addEventListener("dblclick", () => {
console.log("Double click!");
});
document.addEventListener("mousemove", e => { //ここで引数を渡せば、ブラウザからイベントからの情報を渡してくれる
//ここでの引数は、event objectと呼ばれ、慣習的にeが用いられる。
console.log("Mouse moved!");
console.log(e.clientX, e.clientY);
});
document.addEventListener("keydown", e => {
console.log(e.key);
});
}
textarea関係
-
focus
: textareaにフォーカスされたとき -
blur
: textareaからフォーカスが外れたとき -
input
: textareaに文字が入力されたとき -
change
: textareaに入力された文字が確定されたとき
'use strict';
{
const text = document.querySelector("textarea");
text.addEventListener("focus", () => { //focusあたった際のイベント
console.log("focus.");
})
text.addEventListener("blur", () => { //focus外れた際のイベント
console.log("blur.");
})
text.addEventListener("input", () => { //文字が入力された際のイベント
console.log("input.");
console.log(text.value.length); //入力された文字カウント
})
text.addEventListener("change", () => { //入力された文字が確定した際のイベント
console.log("change.");
})
}
form
-
form
については、submit
がイベントとなる。-
form
をもちいることのメリット:エンターキーでform
内のテキストが送信される。 - 通常は
submit
するとページがリロードされる。e.preventDefault
によって、リロードする通常動作をキャンセルできる。 - フォームをエンターキーで送信するには、
form
タグの中にbutton
タグが必要だが、form
タグ中に<input type=”text”>
が1つだけだった場合はbutton
を省略してもエンターキーだけで送信できる。
-
'use strict';
{
document.querySelector("form").addEventListener("submit", e => {
e.preventDefault(); //リロードする通常動作をキャンセルする。
console.log("Submit!");
});
}
イベントの伝播
-
addEventListener
の引数でtarget
とすれば、child node
すべてがイベントの対象となる。
<body>
<ul> <!-- e.currentTarget -->
<li>To do</li>
<li>To do</li> <!-- e.target -->
<li>To do</li>
</ul>
<script src="js/main.js">
</script>
</body>
{
document.querySelector("ul").addEventListener("click", e => {
if (e.target.nodeName === "LI") { //nodeNameは大文字
e.target.classList.toggle("done");
}
});
}
以上。