ここまででなんとなく(感覚的なものが大半を占めるw)、ToDoアプリがそこそこ動くところまで進めてきてしまったが、いよいよDOMについてちゃんと理解しておいた方がよいことに気づくww(遅!)
もちろん、なんとなくと言いつつ、ちゃんと「こうしよう!」と思って作ったToDoアプリではあるが、DOMの操作はちょっとふわっとしているのだ。
今回は、ここにメスを入れようと思う。
DOMとは?
DOMは、Document Object Modelの略。
今回もWiki先生から引用。
DOMは、HTML文書やXML文書(あるいはより単純なマークアップされた文章など)をオブジェクトの木構造モデルで表現することで、ドキュメントをプログラムから操作・利用することを可能にする仕組み
今回の例でいくと、JavaScriptのDOMを操作するAPIを使って、HTMLを書き換えちゃいましょう!という感じかな。(適当w)
要素の取得
まずは要素の取得から行ってみよう!
CodeSandboxを使って、どういう風に書いたら、どんなことが起こるのか、まず手を動かしてみます。
その前に、前提となるHTMLを紹介。
HTML
<body>
<h1 id="list_title">List Title</h1>
<div id="contents">
<div class="table">
<ul id="list">
<li class="list_content">リスト1</li>
<li class="list_content">リスト2</li>
<li class="list_content">リスト3</li>
</ul>
</div>
<div class="content">
<p>リストの色々な説明など1</p>
</div>
<div class="content">
<p>リストの色々な説明など2</p>
</div>
</div>
<script src="src/index.js"></script>
</body>
CSSなどは設定していないので、いたってシンプルなHTML
このHTMLに対して、DOM操作として、要素を取得をやっていきます。
idで要素を取得する
HTML
<h1 id="list_title">List Title</h1>
JavaScript
const title = document.getElementById('list_title');
console.log(title);
結果
親ノードを取得
HTML
<div class="table">
<ul id="list">
<li class="list_content">リスト1</li>
<li class="list_content">リスト2</li>
<li class="list_content">リスト3</li>
</ul>
</div>
JavaScript
const list = document.getElementById('list');
console.log(list);
console.log(list.parentNode);
console.log(list.parentNode.className);
結果
属性の取得と追加
HTML
<ul id="list"> <li class="list_content">リスト1</li> <li class="list_content">リスト2</li> <li class="list_content">リスト3</li> </ul>
JavaScript
const list = document.getElementById('list');
// 属性の取得
const listAttr = list.children[0].getAttribute('class');
console.log(listAttr);
// name属性を追加(F12で確認)
list.children[0].setAttribute('name', 'test');
結果
クラス名で要素を取得する+要素の数を取得
HTML
<div class="content"> <p>リストの色々な説明など1</p> </div> <div class="content"> <p>リストの色々な説明など2</p> </div>
JavaScript
const content = document.getElementsByClassName('content');
console.log(content);
console.log(content.length);
結果
innerHTMLとtextContent
HTML
<div class="content"> <p>リストの色々な説明など1</p> </div> <div class="content"> <p>リストの色々な説明など2</p> </div>
JavaScript
const content1 = document.getElementsByClassName('content')[0];
console.log(content1);
// innerHTMLはタグも含めて取得
console.log(content1.innerHTML);
// textContentはテキストのみを取得
console.log(content1.textContent);
console.log(content1.firstElementChild.innerHTML);
console.log(content1.firstElementChild.textContent);
console.log(content1.children[0].innerHTML);
const content2 = document.getElementsByClassName('content')[1];
console.log(content2);
const content3 = document.getElementsByClassName('content')[2];
console.log(content3);
結果
Collectionと配列
HTML
<ul id="list"> <li class="list_content">リスト1</li> <li class="list_content">リスト2</li> <li class="list_content">リスト3</li> </ul>
JavaScript
// HTMLCollection
const listContent = document.getElementsByClassName('list_content');
console.log(listContent);
// Collectionを配列に変換①
console.log(Array.prototype.slice.call(listContent, 0));
// Collectionを配列に変換②
console.log([...listContent]);
// タグが入った要素から文字列だけを取り出す
const listArray = [...listContent];
for (let i = 0; i < listArray.length; i++) {
console.log(listArray[i].textContent);
}
結果
NodeListと配列
HTML
<ul id="list"> <li class="list_content">リスト1</li> <li class="list_content">リスト2</li> <li class="list_content">リスト3</li> </ul>
JavaScript
// NodeList
const listContentArray = document.querySelectorAll('li');
console.log(listContentArray);
// NodeListを配列に変換①
console.log(Array.prototype.slice.call(listContentArray, 0));
// NodeListを配列に変換②
console.log([...listContentArray]);
結果
兄弟要素の取得
HTML
<ul id="list"> <li class="list_content">リスト1</li> <li class="list_content">リスト2</li> <li class="list_content">リスト3</li> </ul>
JavaScript
const listContent1 = document.getElementsByClassName('list_content')[0];
console.log(listContent1);
// nextElementSiblingは、改行やホワイトスペースを除いて取得
// nextSiblingは、改行やホワイトスペースが含まれる
console.log(listContent1.nextElementSibling);
console.log(listContent1.textContent);
console.log(listContent1.nextElementSibling.textContent);
結果
要素の追加と削除
今度は要素を追加したり削除したりしてみる。
子要素の追加と削除
HTML
<ul id="list"> <li class="list_content">リスト1</li> <li class="list_content">リスト2</li> <li class="list_content">リスト3</li> </ul>
JavaScript
// 起点はlist
const list = document.getElementById('list');
// 直下の子要素を削除
list.removeChild(list.firstElementChild);
// 2番目の子要素を削除
list.removeChild(list.children[1]);
// li要素の作成
const addList0 = document.createElement('li');
const addList4 = document.createElement('li');
// 追加した要素のテキスト追加
addList0.textContent = 'リスト0';
addList4.textContent = 'リスト4';
// 追加した要素にclassを追加
addList0.setAttribute('class', 'list_content');
addList4.setAttribute('class', 'list_content');
// 追加した要素をlistの下に挿入
list.insertBefore(addList0, list.firstChild);
list.appendChild(addList4, list.firstChild);
// コンソールに出力
console.log(list);
console.log(addList0);
console.log(addList4);
結果
子要素をまるっと削除
HTML
<ul id="list"> <li class="list_content">リスト1</li> <li class="list_content">リスト2</li> <li class="list_content">リスト3</li> </ul>
JavaScript
// 起点はlist
const list = document.getElementById('list');
list.innerHTML = '';
// list.textContent = ''; <- こっちもイケる
// コンソールに出力
console.log(list);
結果
要素そのものを削除
HTML
<div class="table">
<ul id="list">
<li class="list_content">リスト1</li>
<li class="list_content">リスト2</li>
<li class="list_content">リスト3</li>
</ul>
</div>
JavaScript
const table = document.getElementsByClassName('table')[0];
const list = document.getElementById('list');
list.remove();
console.log(table);
console.log(list);
結果
最初は、list を remove() したはずなのに、なんでコンソールに出力されてるんだろうって思ったけど、list には取得したDOMが格納されていて、HTMLからその要素が削除されるだけなので、変数 list そのものには、さっき格納したDOMの情報が残っているということらしい。