JavaScriptでDOM操作する方法[JavaScript本格入門]__WebデザイナーのJS学習備忘録

# DOM
DOMとは、Document Object Modelのことで、HTMLやXMLなどマークアップ言語で書かれたドキュメントの特徴のことである。
div要素やアンカータグなどのかたまりをオブジェクトとしてJavaScriptでHTMLを直接編集することができる。

DOMはHTMLなどで書かれたドキュメントを文書ツリー（ツリー構造）として扱う。

DOMでは、ドキュメントに含まれる要素や属性、テキストをそれぞれオブジェクトと見なし、「オブジェクトの集合（階層関係）がドキュメントである」と考える。

ドキュメントを構成する要素や属性、テキストといったオブジェクトのことを**ノード**と呼び、オブジェクトの種類に応じて**要素ノード、属性ノード、テキストノード**などと呼ぶ。

DOMは、これらノードを抽出、追加、置換、削除するための汎用的な手段を提供するAPI(Application Programming Interface)である。

それぞれのノードはツリー構造上での上下関係によって呼称がある。

### ルートノード
ツリーの最上位に位置するノードで、**最上位ノード**とも呼ぶ。

### 親ノード/子ノード
上下関係にあるノード。直接繋がっているノードで、ルートノードに近いノードを**親ノード**、遠いノードを**子ノード**と呼ぶ。
※上下関係にあるが、直接の親子でないものを**祖先ノードと子孫ノード**と呼ぶ場合もある。

### 兄弟ノード
同じ親ノードを持つノード同士のことである。先に書かれているものを**兄ノード**、後に書かれているものを**弟ノード**として区別することもある。


## DOMを操作する方法
DOM操作には要素ノードを取得する以外にも、**ノードウォーキング**や**イベントドリブンモデル**があるが、内容が多くなってしまうので、今回はDOM操作の最も基本となる**要素ノードの取得**に内容を絞っている。


### getElementByIdメソッド
Idをキーとして、そのIdを持つ要素(Element)を取得(get)するということである。

**▼ 構文 - getElementByIdメソッド**

`document.getElementById(id)`
`id:取得したい要素のid値`

**▼ サンプルコード**

```index.html
現在時刻: <span id="result"></span>
```

```script.js
var current = new Date();                          //デフォルトのDateオブジェクトを生成
var result = document.getElementById("result");
result.textContent = current.toLocaleString();
```

まずデフォルトのDateオブジェクトを生成して、変数currentを定義する。
Dateオブジェクトはデフォルトで生成された時点でのシステムの日付をセットする。
次にid値resultを要素の持つドキュメントを取得して変数resultを定義する。
ここでのドキュメントとは、`<span id="result"></span>`
toLocaleString()とは、Dateオブジェクトのローカル時を取得する。
取得した日時をtextContentプロパティでspan要素に現在時刻を埋め込み、ページに反映させる。

取得した要素(Elementオブジェクト)に対してテキストを埋め込むためには、textContentプロパティを利用する。


### getElementsByTagNameメソッド
タグ名をキーとして、そのタグ名を持つ要素(Elements)を取得(get)するということである。

タグとは、h1~h6やpなどの要素のことである。

id値は原則としてページ内で1つしか指定することができないのに対して、タグ名はページ内で何度も使用して良いため、取得する要素が複数になる可能性もある。
そのためgetElementByIdメソッドではElement（単数）であったのに対し、getElementsByTagNameメソッドではElements(複数形)となっていることに注意！

**▼ 構文 getElementByTagNameメソッド**

`document.getElementByTagName(name)`
`name: タグ名`

※ 引数nameに「*」と指定することですべての要素を取得することもできる。


例えば、ページのリスト要素をすべて取得したい場合

**▼ サンプルコード**

```index.html
<ul>
  <li><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript">JavaScript \| MDN</a></li>
  <li><a href="http://semooh.jp/jquery/">JQuery日本語リファレンス</a></li>
  <li><a href="https://jp.vuejs.org/">Vue.js</a></li>
  <li><a href="https://ja.reactjs.org/">React</a></li>
</ul>
```

```script.js
//ページ内のすべてのアンカータグを取得
var list = document.getElementByTagName("a");
//リスト(HTMLCollectionオブジェクト)から順にアンカータグを取り出し、
//そのhref属性をログに出力
for(var i = 0, len = list.length; i < len; i++) {
  console.log(list.item(i).href);
} 
```

**↓ ログ出力結果**

```
https://developer.mozilla.org/ja/docs/Web/JavaScript
http://semooh.jp/jquery/
https://jp.vuejs.org/
https://ja.reactjs.org/
```


getElemetnByTagNameメソッドの戻り値は、HTMLCollectionオブジェクトである。
HTMLCollectionオブジェクトから利用できるメンバーは以下

**length**
リストに含まれる要素数

**item(i)**
i番目の要素を取得

**namedItem(name)**
idまたはname属性が一致する要素を取得

### getElementsByNameメソッド
name属性をキーに要素(Elements)を取得(get)するということである。
一般的には「input」や「select」などフォーム要素へのアクセスで利用する。
用途はラジオボタンやチェックボックスなど、name属性が等しい要素群を取得するような場合に限られる。

**単一の要素を取得するなら、getElementByIdメソッドを利用する方がコードがシンプルになる。**


**▼ 構文 getElementsByNameメソッド**

`document.getElementByName(name)`
`name: name属性の値`

例えば、テキストボックスに初期値として現在時刻をセットする場合

**▼ サンプルコード**

```index.html
<form>
  <label for="time">時刻: </label>
  <input id="time" name="time" type="text" size="10">
</form>
```

```script.js
var current = new Date();

//<input name="time">要素を取得
var nam = document.getElementByName("time");

//そのvalue属性を設定
nam[0].value = current.toLocaleTimeString();
```

↓
テキストボックスに現在時刻を設定


**nam[0]**としているのは、getElementByNameメソッドの戻り値がノードの集合(NodeListオブジェクト)であるから。
一致する要素が1つであることがわかっているため、決め打ちで0番目の要素を取り出している。
要素（テキストボックス)の値を設定するには、**valueプロパティ**を利用する。

単一の要素を取得する場合は、getElementByIdメソッドを利用する方がいい。
getElementByIdメソッドを利用した場合のjsファイルのコードは

```script.js
var nam = document.getElementById("time");
nam.value = current.toLocaleTimeString();
```

### getElementsByClassNameメソッド
class属性をキーとして、要素群(HTMLCollectionオブジェクト)を取得することができる。

**特定の役割を持った要素に対して、共通のクラス名を付与しておくと、getElementsByClassNameメソッドで目的の要素をまとめて取り出すことができる。**

**▼ 構文 getElementsByClassName**

`document.getElementsByClassName(clazz)`
`clazz: class属性の値`

例えば、class属性がframeworkである要素だけを取得し、そのリンク先を表示する場合

**▼ サンプルコード**

```index.html
<ul>
  <li><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript">JavaScript \| MDN</a></li>
  <li><a href="http://semooh.jp/jquery/">JQuery日本語リファレンス</a></li>
  <li><a href="https://jp.vuejs.org/" class="framework">Vue.js</a></li>
  <li><a href="https://ja.reactjs.org/" class="framework">React</a></li>
</ul>
```

```script.js
//ページ内のすべてのアンカータグを取得
var list = document.getElementsByClassName("framework");

//リストからアンカータグを取り出し、そのhref属性をログに出力
for(var i = 0, len = list.length; i < len; i++) {
  console.log(list.item(i).href);
}
```

**↓ ログ出力結果**

```
https://jp.vuejs.org/
https://ja.reactjs.org/
```

getElementsByClassNameメソッドの引数には、「clazz1 clazz2」のように空白区切で複数のクラス名を列記することもできる。
この場合、class属性としてclazz1 clazz2双方が指定された要素だけを検索する。


### querySelector/querySelectorAllメソッド
これらのメソッドを使用することで、セレクター式を文書で検索して、合致した要素を取得することができる。
getXxxxメソッドでは特定の名前/属性値をキーに要素を取得していたのに対して、querySelector/querySelectorAllメソッドではより複雑な条件での検索を可能とする。

**▼ 構文 querySelector/querySelectorAllメソッド**

`document.querySelector(selector)`
`document.querySelectorAll(selector)`
`selector: セレクタ一式`


例えば、id="list"である要素の配下から、class="framework"であるアンカータグを取り出す場合

**▼ サンプルコード**

```index.html
<ul id="list">
  <li><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript">JavaScript \| MDN</a></li>
  <li><a href="http://semooh.jp/jquery/">JQuery日本語リファレンス</a></li>
  <li><a href="https://jp.vuejs.org/" class="framework">Vue.js</a></li>
  <li><a href="https://ja.reactjs.org/" class="framework">React</a></li>
</ul>
```

```script.js
var list = document.querySelectorAll("#list .framework");

for(var i = 0, len = list.length; i < len; i++) {
  console.log(list.item(i).href);
}
```

**↓ ログ出力結果**

```
https://jp.vuejs.org/
https://ja.reactjs.org/
```

querySelectorAllメソッドの戻り値は、getElementsByNameメソッドと同じく、条件に合致した要素を全て含んだNodeListオブジェクトである。
最初から取得すべき要素が1つとわかっている場合、あるいは要素群の最初の一つだけ取り出したい場合には**querySelectorメソッド**を利用するとよい。
この場合の戻り値は、**Elementオブジェクト（単一の要素）**となる。


#### getXxxxメソッドとqueryXxxxメソッドの使い分け方
特定のid値、class属性などで要素を検索可能な場合 => **getXxxxメソッド**
より複雑な検索条件で検索したい場合             => **queryXxxxメソッド**

querySelector/querySelectorAllメソッドは柔軟で高機能なメソッドである一方、getXxxxメソッドよりも低速である点がデメリット。
getElementByIdメソッドは高速なので、id値を指定して利用できる場合はid値で検索することがおすすめ！

#最後に
今回はJavaScriptでのDOM操作で**「ノード要素を取得する方法」**についてまとめてきた。
今後、ノード要素の取得以外で、**ノードウォーキング、イベントドリブンモデル**についてもQiitaにまとめていこうと思う。

学習初学者ほどアウトプットを重視すべきだとQiitaに記事を投稿するためにまとめる度に感じている。

本記事において追記すべき内容な不備があればコメントいただけると嬉しいです。