【JavaScript】DOMについて

##はじめに
JavaScriptの基礎を勉強したらとても良い学びになったのでメモ第3弾です
JavaScriptのDOMについてです

ちなみに2回目はこちら↓

https://qiita.com/komekami0131/items/2a0e4fcc0e013b1b7646


こちらの本を参考にさせていただきました

https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88JavaScript%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80-%EF%BD%9E%E3%83%A2%E3%83%80%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E7%8F%BE%E5%A0%B4%E3%81%A7%E3%81%AE%E5%BF%9C%E7%94%A8%E3%81%BE%E3%81%A7-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B-ebook/dp/B01LYO6C1N/ref=sr_1_5?dchild=1&keywords=javascript&qid=1623279484&sr=8-5

##概要
###DOMとは：
**Document Object Model**
マークアップ言語を操作する標準の仕組み

DOMはドキュメントを文書ツリーとして扱う
文書に含まれる要素や属性、テキストをそれぞれオブジェクト(=ノード)と見なし、「オブジェクトの集合が文書である」と考える

**DOMはこれらノードを抽出/追加/置換/削除するための汎用的な手段を提供するAPI**

```html:dom.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>【JavaScript】DOMについて</title>
</head>
<body>
  <p id="greet">これが<strong>文書ツリー</strong>です</p>
</body>
</html>
```

上記HTMLコードはこう解釈される↓

![DOM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1009493/084b35d6-8861-4d30-a8fd-169bc9c6c2df.png)

##クライアントサイドJavaScriptの前提知識
JavaScriptでクライアントサイド開発を進めるうえで欠かせない知識は以下の3つ

1. 要素ノードの取得
2. 文書ツリー間の行き来
3. イベントドリブンモデル

##1. 要素ノードを取得する
文書ツリーから操作対象となる要素ノードを取り出す必要がある

要素ノードを取得する主な方法は以下の3つ

* document.getElementById()
* document.querySelector()
* document.querySelectorAll()

###document.getElementById()
指定されたid値を持つ要素をElementオブジェクトとして返す
存在しない場合、nullが返る

```html:HTML
<span id="spanText">Hello</span>
```

```javascript:JavaScript
var spanText = document.getElementById('spanText');
console.log(spanText); //<span>
console.log(spanText.textContent); // "Hello"

// 要素を取得できていない例
var divText = document.getElementById('divText');
console.log(divText); // null
```

取得した要素（Elementオブジェクト）に対してテキストを埋め込むにはtextContentというプロパティを利用する

###document.querySelector()/document.querySelectorAll()
CSSセレクタでマッチした要素を取得する

>**CSSセレクタとは**
>CSSによるデザイン指定をどのHTML要素に適用させるかを指定するもの

getXxxxxメソッドが特定の名前/属性値をキーに要素を検索していたのに対して、より複雑な条件での検索が可能

```html:HTML
<ul id="list">
  <li><p class="en">Hello</p></li>
  <li><p class="en">GoodBye</p></li>
  <li><p class="ja">こんにちは</p></li>
  <li><p class="ja">さようなら</p></li>
</ul>
```

```javascript:JavaScript
const foo01 = document.querySelector('#list .en');
console.log(foo01.textContent);
// Hello

const foo02 = document.querySelectorAll('#list .en');
for(let i=0,len=foo02.length; i<len; i++){
  console.log(foo02.item(i).textContent);
  //Hello
  //GoodBye
}
```

querySelector()は一番最初にマッチした要素のみ取得する
戻り値はElementオブジェクト(単一)

querySelectorAll()はマッチした要素全てを取得する
戻り値はNodeListオブジェクト

>####取得したNodeListの使い方(一例)
配列に変換する

>```javascript:JavaScript
var elem =[].slice.call(document.querySelectorAll('#list'));
```

>**slice()**
>配列を新しい配列オブジェクトに作成して返すメソッド

>**call()**
>他のオブジェクトが持つメソッドを自分のメソッドのように呼び出すメソッド

**getXxxxxメソッドとqueryXxxxxメソッドの使い分け**

* getXxxxxメソッド（高速、低機能）：特定のid値、class属性などで要素を検索できる場合
* queryXxxxxメソッド（低速、高機能）：より複雑な条件で検索したい場合

##2. 文書ツリー間の行き来
あるノードを起点として相対的な位置関係からノードを取得する（＝ノードウォーキング）
>1.のgetXxxxx/queryXxxxxメソッドは特定の要素ノードを取得するためのメソッド

以下の例は、<select id="country">要素の配下に含まれる<option>要素を取り出し、そのvalue属性の値を列挙する

```html:HTML
<form>
  <label for="country">一番好きな国は？：</label>
  <select id="country">
    <option value="アメリカ">アメリカ</option>
    <option value="日本">日本</option>
    <option value="中国">中国</option>
  </select>
<input type="submit" value="送信" />
</form>
```
```javascript:JavaScript
const s = document.getElementById('country');

// <select>要素配下の子ノードを取得
const opts = s.childNodes;

// 子ノードを順に取得
for(let i = 0, len = opts.length; i < len; i++){
  let opt = opts.item(i);
　// 子ノードが要素ノードである場合にのみ、その値をログ表示
  if(opt.nodeType === 1) {
    console.log(opt.value);
    // "アメリカ" "日本" "中国"
  }
}
```

childNodesプロパティは要素直下の子ノード群を取得し、**NodeListオブジェクト**として返す。

しかし、リストに含まれるノードは要素だけではないため、今回のように<opption>要素だけを取り出したい場合は、**取り出したノードが要素ノードであるか**を確認する必要がある。
>タグの間にある改行や空白はテキストノードと見なされる

nodeTypeプロパティを用いてノードの種類を判定する
以下は、nodeTypeプロパティの対応表（抜粋）

| 戻り値 | 概要 |
|:-:|:-:|
|  1 |  要素ノード |
|  2 |  属性ノード |
|  3 |  テキストノード |
|  4 |  CDATAセクション |
|  5 |  実態参照ノード |
|  6 |  実態宣言ノード |
|  7 |  処理命令ノード |

今回の例では、nodeTypeプロパティが1（要素ノード）である場合にのみ、その値（valueプロパティ）を取得

##イベントドリブンモデル
**イベントドリブンモデル：**
ブラウザ上で発生するイベントに応じて、実行するコードを記述するプログラミングのモデル

イベントドリブンモデル＝イベント＋イベントハンドラー（/ イベントリスナー）
###イベント
ページ内で発生した様々な出来事

JavaScriptで利用できる主なイベント（抜粋）

| 分類 | イベント名 | 発生タイミング | 主な対象要素 |
|:-:|:-:|:-:|:-:|
| 読み込み  | load  | 画像の読み込みが完了したとき  | body,img  |
| マウス  | click  | クリック時  | -  |
| マウス  | mouseover | マウスポインターが要素に乗った時  | -  |
| キー  | keydown  | キーを押したとき  | -  |
| フォーム  | submit  | サブミットボタンを押した時  | form  |
| フォーカス  | focus  | 要素がフォーカスされた時  | -  |
| その他  | scroll  | スクロールした時  | body  |

###イベントハンドラー（/ イベントリスナー）
イベントに対応してその処理内容を定義するコードのかたまり（関数）

イベントハンドラー（/ イベントリスナー）を定義する

定義方法は以下の3種類

1. addEventListenerメソッドを使って宣言する（イベントリスナー）
2. タグ内の属性として宣言する（イベントハンドラー）
3. 要素オブジェクトのプロパティとして宣言する（イベントハンドラー）

基本的には、DOM Level2で定義され、標準化されている**（1.の）addEventListenerメソッド**を利用する

####1. addEventListenerメソッドを使って宣言する

2.と3.のイベントハンドラーと違うのは、同一要素/同一イベントに対して複数のイベントハンドラー（のようなもの）を紐づけられる点

以下はボタンクリックでウィンドウアラートが出る例

```html:HTML
<input id="btn" type="button" value="ダイアログ表示"> 
```

```javascript:JavaScript
// ページがロードされたタイミングでイベントを登録
document.addEventListener('DOMContentLoaded', function(){
	document.getElementById('btn').addEventListener('click', function() {
  window.alert('ボタンがクリックされました');
  },false);
},false);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1009493/fb54ffef-29d2-a0c1-b80f-426b6eb24635.png)

>**DOMContentLoadedイベントリスナー：**
コンテンツ本体がロードされたところで実行
**onloadイベントハンドラ：**
コンテンツ本体とすべての画像がロードされたところで実行

####2. タグ内の属性として宣言する
最もシンプルな記法

```html:HTML
<input type="button" value="ダイアログ表示" onclick="btn_click()" />
```

```javascript:JavaScript
function btn_click() {
  window.alert('ボタンがクリックされました');
}
```

HTMLに直接記述することもできる（可読性の観点から△）

```html:HTML
<input type="button" value="ダイアログ表示" onclick="window.alert('ボタンがクリックされました')" />
```

####3. 要素オブジェクトのプロパティとして宣言する
関連付けとイベントハンドラーそのものの宣言とをまとめてJavaScriptのコード内で記述する

```html:HTML
<input id="btn" type="button" value="ダイアログ表示" />
```

```javascript:JavaScript
// ページロード時に実行されるイベントハンドラーを登録
window.onload = function() {
  // ボタンクリック時に実行されるイベントハンドラーを登録
  document.getElementById('btn').onclick = function() {
    window.alert('ボタンがクリックされました');
  };
}
```

##さいごに
JavaScriptでの基本的なDOMについて勉強し、まとめてみました

仕事でちょうどDOMを扱ったのでよい復習になりました

このほかにも、参考にさせていただいた書籍では深堀りし解説しているので、気になった方はチェックしてみてください

##参考

https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88JavaScript%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80-%EF%BD%9E%E3%83%A2%E3%83%80%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E7%8F%BE%E5%A0%B4%E3%81%A7%E3%81%AE%E5%BF%9C%E7%94%A8%E3%81%BE%E3%81%A7-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B-ebook/dp/B01LYO6C1N/ref=sr_1_5?dchild=1&keywords=javascript&qid=1623279484&sr=8-5


https://qiita.com/amamamaou/items/25e8b4e1b41c8d3211f4

https://www.sejuku.net/blog/27019