JavaScriptの基本⑤　DOM操作

本記事ではJavaScriptを使用してwebページを動作させる仕組みであるDOM操作についてまとめます。
用語の説明からやっていきます。

**DOM操作**
…HTMLやXMLの要素等をWebページ上で動作させる、仕掛けのようなものを作ります。
フォーム送信を利用せずにタブをクリックして表示を切り替えたり、入力欄に文字列を入力してすぐにエラーチェックを行う等あらゆる動作が可能です。

**DOM**
…Document Object Modelの略称です。JavaScriptで記述されたプログラムからHTMLにアクセスしてHTMLページを操作させるプログラミングインターフェースのこと。DOMはHTMLやXMLに記載された文書をツリー構造として表し、各要素をノードとして扱います。そのため、JavaScript等を使用してWebページの内容や構造を動的に操作することができます。

**プログラミングインターフェース**
…プログラムが特定の機能・サービスにアクセスし、操作するための手段や方法を提供する仕組みのこと。
　（例）API、ライブラリ、フレームワーク、DOM等

 **ノード**
 …データ構造や文書構造の基本単位のこと。DOMにおいてはHTMLやXMLの各要素のことを表します。

### DOMにおけるノードの種類
**・ドキュメントノード**
　…文書全体を表している最上位のノード。
**・要素ノード**
　…各HTMLタグのことを表しているノード。
**・テキストノード**
　…要素内のテキストを表しているノード。
**・属性ノード**
　…要素の属性を表しているノード。
**・コメントノード**
　…HTMLやXML文書内のコメントを表しているノード。

それでは実際にDOM操作を行ってみましょう。
 
## getElementByIdメソッド
…jaavaScript側でidを指定し、文書内でそのidを持つ要素を１つ取得します。
⇒指定したidを持つ要素が存在しなければ「null」を返します。

```javascript
document.getElementById(id);
```

＜＜具体的な使用例＞＞
ボタンを押してp要素のidを取得し、要素の内容と要素内のテキストをコンソールで出力します。
```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>テスト</title>
  </head>
  <body>
    <p id="test">テスト</p>
    <input type="button" id="push" value="push">
  </body>
  <script src="common.js"></script>
</html>
```

```javascript:common.js
'use strict'
const e = document.getElementById('push');
e.addEventListener('click',() => {
  const test = document.getElementById('test');
  console.log(test);
  console.log(test.innerText);
}, false);
```

Javascriptの行を１かたまりずつ確認していきます。

**'use strict'**
…JavaScriptの厳格モードを有効にする宣言。

**const e = document.getElementById('push');**
…「push」というidが付いた要素を取得し、定数eに格納します。

**e.addEventListener('click',() => { [省略)] }, false);**
…変数e（ここではinput要素のid=）の要素に対してクリックイベントリスナーを追加します。
　() => { [省略)] }の[省略]部分は、クリックしたときに実行される関数です。
 　falseはイベントのバブリングフェーズでリスナーを実行することを指定します。
  　（バブリングフェーズ：イベントが子要素から親要素へと伝播するプロセスのこと）

**const test = document.getElementById('test');**
…クリックイベントが発生したときに実行される関数の中で、id属性が「test」である要素を取得し、定数testに格納します。

**console.log(test);**
…定数testに格納された要素そのものをコンソールに出力します。

**console.log(test);**
…定数testに格納された要素の内部テキストをコンソールに出力します。


上記を記述することで、画面のボタンをクリックすると
p要素の内容とp要素内のテキストを出力することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/405f01cc-d9d0-d3ca-8aba-a221a1680538.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/b6406b21-c0bf-0bfe-2383-19e6f9077ec1.png)

--------------------------------------------------

## getElementsByIdメソッド
…javaScript側でタグを指定し、文書内でそのタグを持つ要素を取得します。
　**（複数要素が取得できる場合があるため、「Elements」（複数形）となっています）**
　戻り値はHTMLCollectionとして返ってきます。
⇒指定したタグを持つ要素が存在しない場合、空のHTMLCollection([])が返ってきます。

```javascript
document.getElementsByTagName(タグの名前);
```

ではままタグ名から要素の取得を行えるように記述します。

```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>テスト</title>
  </head>
  <body>
    <p>テスト１</p>
    <p>テスト２</p>
    <span>テスト３</span>
    <p>テスト４</p>
    <input type="button" id="push" value="push">
  </body>
  <script src="common.js"></script>
</html>
```

```javascript:common.js
'use strict'
const e = document.getElementById('push');
e.addEventListener('click',() => {
  const elements = document.getElementsByTagName('p');
  for(let i = 0; i< elements.length; i++){
    console.log(elements[i].innerText);
  }
}, false);
```

クリック時に実行されるJavascriptの行を確認していきます。

**const elements = document.getElementsByTagName('p');**
…クリックイベントが発生したときに実行される関数の中で、タグが「p」である要素を取得し、定数elementsに格納します。

**for(let i = 0; i< elements.length; i++){{ [省略] }**
…定数elementsに格納されている複数の要素を、１つずつ繰り返し処理で取り出すための記述です。

**console.log(elements[i].innerText);**
…定数elementsから取り出した要素の内部テキストを出力します。


ボタンをクリックすると下記のようにp要素の内部テキストのみコンソールに出力されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/41863abd-03d3-022c-e9c7-33571a5f8f8d.png)


## getElementsByNameメソッド
…javaScript側でnameを指定し、文書内でそのname属性を持つ要素を取得します。
　**（複数要素が取得できる場合があるため、「Elements」（複数形）となっています）**
　戻り値はHTMLCollectionとして返ってきます。
⇒指定したタグを持つ要素が存在しない場合、空のHTMLCollection([])が返ってきます。

```javascript
document.getElementsByName(name);
```

それではname属性から要素を取得するソースコードを記述していきます。
```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>テスト</title>
  </head>
  <body>
    <input type="text" name="test">
    <input type="text" name="test">
    <input type="text">
    <input type="button" id="push" value="push">
  </body>
  <script src="common.js"></script>
</html>

```

```javascript
'use strict'
const e = document.getElementById('push');
e.addEventListener('click',() => {
  const elements = document.getElementsByName('test');
  for(let i = 0; i< elements.length; i++){
    console.log(elements[i].value);
  }
}, false);

```

クリック時に実行されるJavascriptの行を確認していきます。
（for文はgetElementsByIdメソッドの説明時と同じです）

**const elements = document.getElementsByName('test');**
…クリックイベントが発生したときに実行される関数の中で、name属性が「test」である要素を取得し、定数elementsに格納します。

**console.log(elements[i].value);**
…定数elementsから取り出した要素の値（ここではinputの入力値）を出力します。

ボタンをクリックすると下記のようにjavascriptで指定したnames属性と一致したinputタグの入力値のみコンソールに出力されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/1598a914-700b-c51b-e695-b61138cceddb.png)

## getElementsByClassNameメソッド
…javaScript側でclassを指定し、文書内でそのclass属性を持つ要素を取得します。
　**（複数要素が取得できる場合があるため、「Elements」（複数形）となっています）**
　戻り値はHTMLCollectionとして返ってきます。
⇒指定したタグを持つ要素が存在しない場合、空のHTMLCollection([])が返ってきます。

```javascript
document.getElementsByClassName(className);
```

それではname属性から要素を取得するソースコードを記述していきます。
```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>テスト</title>
  </head>
  <body>
    <p class="test">てすと１</p>
    <p class="test">てすと２</p>
    <p class="text">てすと３</p>
    <p>てすと４</p>
    <input type="button" id="push" value="push">
  </body>
  <script src="common.js"></script>
</html>

```

```javascript:common.js
'use strict'
const e = document.getElementById('push');
e.addEventListener('click',() => {
  const elements = document.getElementsByClassName('test');
  for(let i = 0; i< elements.length; i++){
    console.log(elements[i].innerText);
  }
}, false);
```

クリック時に実行されるJavascriptの行を確認していきます。
（for文とconsole.logの部分はgetElementsByIdメソッドの説明時と同じです）

**const elements = document.getElementsByClassName('test');**
…クリックイベントが発生したときに実行される関数の中で、class属性が「test」である要素を取得し、定数elementsに格納します。


ボタンをクリックすると下記のようにjavascriptで指定したclass属性と一致したpタグのみコンソールに出力されるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/5182ee9a-cb34-cbe2-c308-7d884042f7e3.png)


# ノードの追加・置換・削除

### 【追加】 createElementメソッド
…要素を作成するメソッドです。要素を作成するだけのため、追加処理の記述が必要です。
```javascript
const newElement = document.createElement('タグ名');
```

### 【追加】createTextNodeメソッド
…テキストノードを作成するメソッドです。ノード作成するだけのため、追加処理の記述が必要です。
```javascript
document.createTextNode(テキスト)
```


### 【追加】appendChildメソッド
…指定した要素を、現在の要素の最後の子要素として追加します。戻り値として追加した子ノードが返ってきます。
```javascript
element.appendChild(追加する子ノード)
```
----------------------------------------------------------
先ほどのメソッドを使用したソースコードと、その動作を確認します。
```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>addList</title>
  </head>
  <body>
    <ol id="addList">
    </ol>
    <input type="button" id="push" value="add">
  </body>
  <script src="common.js"></script>
</html>

```


```javascript:common.js
'use strict'
const e = document.getElementById('push');
e.addEventListener('click',() => {
  const li = document.createElement('li');
  const text = document.createTextNode('add');
  li.appendChild(text);
  const addElement = document.getElementById('addList');
  addElement.appendChild(li);
}, false);
```

ボタンクリック時に行われるJavaScriptの処理内容を１行ずつ確認していきます。

**const li = document.createElement('li');**
…追加するリスト項目（ここではli要素）を作成し、定数liに格納します。

**const text = document.createTextNode('add');**
…新しいテキストノード（ここではtextという文字列）を作成し、定数textに格納します。

**li.appendChild(text);**
…作成したテキストノード（text）をリスト項目（li）に追加します。

**const addElement = document.getElementById('addList');**
…子要素（li要素）を追加したい順序付きリスト（ol要素）をgetElementByIdメソッドで取得し、定数addElementに格納します。

**addElement.appendChild(li);**
…新しいリスト項目（li要素）を、順序付きリスト(ol要素)の子要素として追加します。

画面の動作はこのようになります。addボタンをクリックすると要素が増えていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/1abefb2a-4b5c-0504-255a-2424a1923150.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/fee0d640-ce66-a43a-cd08-8b896e64b5f5.png)

---------------------------------------------------


### 【置換】replaceElementメソッド

…指定の子ノードを置き換えるメソッドです。

```javascript
parentNode.replaceChild(newChildNode, oldChildNode);
```

----------------------------------------------------------
このメソッドを使用したソースコードと、その動作を確認します。

```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>replaceList</title>
  </head>
  <body>
    <ol id="replaceList">
      <li id="old">古い要素</li>
    </ol>
    <input type="button" id="push" value="replace">
  </body>
  <script src="common.js"></script>
</html>

```

```javascript
'use strict'
const e = document.getElementById('push');
e.addEventListener('click',() => {
  const newList = document.createElement('li');
  newList.setAttribute('id','new');
  const newText = document.createTextNode('新しい要素');
  newList.appendChild(newText);
  const oldList = document.getElementById('old');
  const parentNode = oldList.parentNode;
  parentNode.replaceChild(newList, oldList);
}, false);
```

ボタンクリック時に行われるJavaScriptの処理内容を１行ずつ確認していきます。

**const newList = document.createElement('li');**
…入れ替えるするリスト項目（ここではli要素）を作成し、定数liに格納します。

**newList.setAttribute('id','new');**
…作成したli要素にid属性「new」を設定します。

**const newText = document.createTextNode('新しい要素');**
…新しいテキストノード（ここでは「新しい要素」という文字列）を作成し、定数newTextに格納します。

**newList.appendChild(newText);**
…指定した要素を、現在の要素の子要素として追加します。戻り値として追加した子ノードが返ってきます。


**const oldList = document.getElementById('old');**
…入れ替えたい既存のli要素をgetElementByIdメソッドで取得し、定数oldListに格納します。

**const parentNode = oldList.parentNode;**
…既存のli要素の親要素を取得し、定数parentNodeに格納します。

**parentNode.replaceChild(newList, oldList);**
…既存のリスト項目を新しいリスト項目に置き換えます。parentNode.replaceChild(newList, oldList) は、parentNode の子要素 oldList を newList に置き換えます。




ボタンをクリックすると古い要素が新しい要素に入れ替えられます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/49df2b26-4ce3-00f2-f5b6-a49edce3e4cc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3906686/f3bbd329-275d-2d7f-3c07-908ed23dbb25.png)

### 【削除】deleteElementメソッド
…指定された子ノードを削除するメソッドです。削除した子ノードは再利用することができます。

```javascript
const oldChild = parentNode.removeChild(childNode);
```