JavaScript学習：DOM

# DOMや要素をイメージしやすくする

![javascript.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667981/9336107f-059a-b0e5-ada9-85402a228663.png)


&nbsp;チーム開発でメンバーから思わぬ言葉が出たので、どうやって伝えよう？と試行錯誤してみた話。
<br>
【全体の話の流れ】
* [背景として](#背景として)
* [先ずはMDNでの解説を見てみる](#先ずはMDNでの解説を見てみる)
* [DOMとはどういうものか？](#DOMとはどういうものか？)
* [実際にDOMをいじってみる](#実際にDOMをいじってみる)
* [まとめ](#まとめ)

<br><br>
## 背景として
### 各々の前提知識から情報を提供しておくべきだった話
&nbsp;先ず筆者は、経営情報学部出身である。
同学部では、軽くではあるけれども、 HTMLとCSSの授業は必須であるため、ある程度表側を触った経験はある。
プロゲートのHTML＆CSSくらいであれば、ノーヒントでなんなくこなすことができた。
DOM要素に関しても、元から感覚的に身についてしまっていたところがある。
&nbsp;対してメンバーは、保守系の知識は豊富だが、表側は全く触ったことが無い。
バックエンドは最近勉強し始めたばかり。

&nbsp;普通はこういった場合、PMとしてはインフラや保守系の業務を担当してもらうべきなのだろうが、このチームでは結成時にあるコンセプトを掲げていた。（私が勝手に掲げたのですがw）

それは、**各々が自分一人でもアプリを立ち上げられるようになろう！**
だ。

保守系業務は日常で関わっている、かつバックエンドの学習もある程度進めている。
であるならば、フロントをプラスすればコンプリートじゃん♪
という短絡的な思考。

まあ、そういった感じで彼に無茶振りをしてしまったのだが、当然のことながら問題は発生する。

<font color="red">**「DOMの要素を付けたり外したりがいまいちイメージが掴めないんですけど…」**</font>

あ！（汗）

ワシのアホぽん！

0からJS学習して頑張ろうとしてくれているのに、DOMの説明を先にやっていないでどうやって進めるんだよ！
アホなんか、わし…

ええ…

そんなこんなで、反省ついでに自身の理解を深めるためにもDOMについて、さらっとまとめてみようと思います。

## 先ずはMDNでの解説を見てみる
MDNを見てみるとDOMについて次のように書かれています。
>[ドキュメントオブジェクトモデル (Document Object Model, DOM) は、— ウェブページを表す HTML のように — 文書の構造をメモリー内に表現することで、ウェブページとスクリプトやプログラミング言語を接続するものです。](https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model)

なんのこっちゃ？？？

わかりやすくDOMとはどういうものか、考えてみることにする。

## DOMとはどういうものか？
### DOMとはAPIの一種である
DOMとは、ドキュメントを制御するためのAPIです。
実際にはXMLパーサにアクセスして、XML形式のファイルからテキストデータを抜き出し、プログラムやアプリケーションが使いやすい形に変換してくれるのですが、そこまで説明すると余計にわからなくなりそうなので今回は割愛します。

### DOMツリーについて
Webページに書かれているHTML文書は、DOMを介してDOMツリーに変換されます。
例えば、次のようなHTML文書を作成したとします。
``` html:hoge.html
<html>
 <head>
  <title>hogehoge日記</title>
  <link rel=="stylesheet" href="hoge".css>
 </head>
 <body>
  <h1>hogehoge日記</h1>
  <p>こんにちは！私はhogehogeです。</p>
 </body>
</html>
```
この場合のDOMツリーは、こんな感じ！
![スクリーンショット 2022-05-17 16.54.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667981/c639d38e-670f-dfdb-8a32-b1eaed16888d.png)

ブラウザがHTMLを読み込むと、Documentを先頭としたDOMツリーがこのように構築されます。

この角丸枠で囲まれている部分をNodeと言い、基本的には3つの種類に分けられます。
* ドキュメントNode ・・・　参照する場合はdocumentを使う。この図では一番上の階層のDocument
* 要素Node ・・・　 参照する場合はelementを使う。この図ではタグで囲まれたもの。
* テキストNode ・・・　主にtextContentでgetできるかな？？この図では""で囲まれたもの。

空白Nodeは空のテキストノードとして構築されるようだ…
ただし、空白はいくつ重ねても１つ分の空白ノードでしかない。

なので、改行している場合は、後ろの空白は一つの空白ノードとして処理される。

各要素ノード間に空白ノードが生まれるのはこのため。

この点を踏まえた上で、実際にDOMをいじってみよう。

## 実際にDOMをいじってみる
### document.　〜

&nbsp;ノードの最上位、Documentを取得するために使われるのがこれ。
`document.getElementById("")`やら`document.createElement('')`やら
もはや、謎の呪文と言ってもいいくらいしょっちゅう使うやつ。

使い方は次の通り。

`document.[何をしたいのか]`

[何をしたいのか]には、
idがhogeのやつくれよ　-> `getElementById('hoge')`
やら
新しい要素ノードのdivタグ作ってくれよ -> `createElement('div')`

やらを指示できる。

注意するのは、要素ノードは作っただけでは画面に反映されない。

どこかに付け加える必要がある。

そこで、`appendChild([作った要素])`を使う。
例えば、先ほどのhtml文書のbodyタグ配下に新しくpタグの要素を付け加えたい場合。

```javascript:hoge.js
const body = document.getElementByTagName('body');
const div = document.createElement('div');
body.appendChild(div);
```
とすれば作ったdivタグをbody要素の一番後ろに加えることが可能だ。

その際のDOMツリーは次のように変更される。

![スクリーンショット 2022-05-17 18.11.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667981/07f1c907-e7d0-829e-9b49-0283c53a23a8.png)

もちろんこれはブラウザ上での処理なので、サーバー側に置いているHTMLは変更されることはない。
リロードすればまた元のHTMLが読み込まれる。

### 空白ノードを意識する。
&nbsp;parentNodeやchildNodeでノードを取得する場合は、そもそもノードを取得している意識が働くと思うので、さほど問題は起こらないのではないかと思う。
が、nextSiblingやpreviousSiblingを使う場合、うっかりこれを忘れてしまうことがある。

例えば、h1の次の要素を取得するつもりで、`console.log(document.getElementsByTagName('h1')[0].nextSibling)`と書いたとする。

期待しているのはpタグの情報だが、返ってくる値はおそらく#textになるだろう。

回避するにはnextSiblingをnextElementSiblingに変えてあげれば良い。

## まとめ

* DOMとはDOMツリーを作ってプログラムと連携しやすくするためのインターフェイスのAPIである
* JavaScriptを書く場合、DOMのツリー構造を意識しておく必要がある。
* 空白ノードを意識しよう