JavaScriptで要素を取得する際には主に2つの方法が用いられます。
ノード概要
ウェブページ内のすべてのコンテンツはノード(タグ、属性、テキスト、コメントなど)として扱われ、DOMではnodeで表されます。HTML DOMツリー内のすべてのノードはJavaScriptでアクセス可能であり、HTML要素(ノード)は変更、作成、削除可能です。
ノード属性
ノードは少なくともnodeType(ノードタイプ)、nodeName(ノード名)、nodeValue(ノード値)の3つの基本属性を持ちます。
要素ノード: nodeTypeは1
属性ノード: nodeTypeは2
テキストノード: nodeTypeは3(テキスト、空白、改行を含む)
実際の開発では主に要素ノードを操作します。
ノード階層
DOMツリーを利用してノードを異なる階層関係に分類できます。一般的なのは親子兄弟関係です。
1. 親ノード
node.parentNode
例:
<body>
<div class="demo">
<div class="box">
<span class="qr-code">×</span>
</div>
</div>
<script>
// 1. 親ノード parentNode
var qrCode = document.querySelector('.qr-code');
// var box = document.querySelector('.box');
// 返されるのは要素の直近の親ノード(親要素)で、親ノードがない場合はnullを返す
console.log(qrCode.parentNode);
</script>
</body>
parentNodeプロパティは指定ノードの親ノードを返します。注意点として、最近の親ノードを返す点と、親ノードがない場合はnullを返す点です。
2. 子ノード
parentNode.childNodes(標準)
parentNode.childNodesは指定ノードの子ノードのコレクションを返します。このコレクションは即時更新されます。 注意: 返される値にはすべての子ノード(要素ノード、テキストノードなど)が含まれます。要素ノードだけを取得したい場合は専用の処理が必要です。そのため、childNodesの使用は推奨されません。要素ノードだけを取得するためのループ処理例:
var list = document.querySelector('ul');
for(var i = 0; i < list.childNodes.length;i++) {
if (list.childNodes[i].nodeType == 1) { // list.childNodes[i] は要素ノード
console.log(list.childNodes[i]);}
}
非標準ですが、ブラウザサポートが広い方法として以下があります:
parentNode.children(非標準)
parentNode.childrenは読み取り専用のプロパティで、すべての子要素ノードを返します。他のノードは返しません(これは重点的に学ぶべき点です)。非標準ですが、ブラウザでのサポートが充実しているため安心して使用可能です。
<body>
<ul>
<li>私はliです</li>
<li>私はliです</li>
<li>私はliです</li>
<li>私はliです</li>
</ul>
<script>
// DOM APIによる取得
var list = document.querySelector('ul');
var items = list.querySelectorAll('li');
// 1. 子ノード childNodes すべての子ノードを含む
console.log(list.childNodes);
console.log(list.childNodes[0].nodeType); // ノードタイプ
console.log(list.childNodes[1].nodeType);
// 2. children すべての子要素ノードを取得(開発でよく使う)
console.log(list.children);
</script>
</body>
その他の子ノード取得方法:
//firstChild は最初の子ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
parentNode.firstChild
//lastChild は最後の子ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
parentNode.lastChild
//firstElementChild は最初の子要素ノードを返す。見つからない場合はnullを返す。
parentNode.firstElementChild
//lastElementChild は最後の子要素ノードを返す。見つからない場合はnullを返す。
parentNode.lastElementChild
実際の開発では、firstChildとlastChildはすべてのノードを含むため操作が不便です。firstElementChildとlastElementChildは互換性の問題があります。この場合、どのように最初の子要素ノードや最後の子要素ノードを取得すればよいでしょうか? 解決策: 最初の子要素ノードを取得するには
parentNode.children[0]
最後の子要素ノードを取得するには
parentNode.children[parentNode.children.length - 1]
例:
<body>
<ol>
<li>私はli1です</li>
<li>私はli2です</li>
<li>私はli3です</li>
<li>私はli4です</li>
<li>私はli5です</li>
</ol>
<script>
var list = document.querySelector('ol');
// 1. firstChild は最初の子ノードを返す(テキストノードや要素ノードを含む)
console.log(list.firstChild);
console.log(list.lastChild);
// 2. firstElementChild は最初の子要素ノードを返す(IE9からサポート)
console.log(list.firstElementChild);
console.log(list.lastElementChild);
// 3. 実際の開発で使われる方法(互換性問題なしで最初の子要素ノードを返す)
console.log(list.children[0]);
console.log(list.children[list.children.length - 1]);
</script>
</body>
3. 兄弟ノード
//nextSibling は現在の要素の次の兄弟ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
node.nextSibling
//previousSibling は現在の要素の前の兄弟ノードを返す。見つからない場合はnullを返す。すべてのノードを含む。
node.previousSibling
//nextElementSibling は現在の要素の次の兄弟要素ノードを返す。見つからない場合はnullを返す。
node.nextElementSibling
//previousElementSibling は現在の要素の前の兄弟ノードを返す。見つからない場合はnullを返す。
node.previousElementSibling
例:
<body>
<div>私はdivです</div>
<span>私はspanです</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 次の兄弟ノード(要素ノードやテキストノードを含む)
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 次の兄弟要素ノード
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
</body>
注意: nextElementSiblingとpreviousElementSiblingはIE9以上でのみサポートされています。 互換性のある関数をラッピングする:
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
4. ノードの作成
document.createElement('tagName')
document.createElement()メソッドは指定されたtagNameのHTML要素を作成します。これらの要素は元々存在しないため、動的に生成される要素ノードとも呼ばれます。
5. ノードの追加
node.appendChild()
node.appendChild()メソッドは指定された親ノードの子ノードリストの末尾にノードを追加します。CSSのafter擬似要素に似ています。
node.insertBefore(child, 指定要素)
node.insertBefore()メソッドは親ノードの指定された子ノードの前にノードを追加します。CSSのbefore擬似要素に似ています。
6. ノードの削除
node.removeChild(child)
node.removeChild()メソッドはDOMから子ノードを削除し、削除されたノードを返します。
作成、追加、削除の例:
<body>
<ul>
<li>123</li>
</ul>
<script>
// 1. 要素ノードの作成
var item = document.createElement('li');
// 2. ノードの追加 node.appendChild(child) nodeは親、childは子。末尾に追加。配列のpushに似た。
var list = document.querySelector('ul');
list.appendChild(item);
// 3. ノードの挿入 node.insertBefore(child, 指定要素);
var newItem = document.createElement('li');
list.insertBefore(newItem, list.children[0]);
// 4. ノードの削除
list.removeChild('li');
</script>
</body>
7. ノードの複製(クローン)
node.cloneNode() //浅コピー
node.cloneNode(true) //深コピー
node.cloneNode()メソッドは呼び出し元のノードのコピーを返します。クローンノード/コピーノードとも呼ばれます。 注意:
1. 引数が空またはfalseの場合、浅コピーとなり、ノード自体のみをコピーし、子ノードはコピーしません。
2. 引数がtrueの場合、深コピーとなり、ノード自体とすべての子ノードをコピーします。
簡易版コメント投稿機能
<style>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
}
textarea {
width: 200px;
height: 100px;
border: 1px solid pink;
outline: none;
resize: none;
}
ul {
margin-top: 50px;
}
li {
width: 300px;
padding: 5px;
background-color: rgb(245, 209, 243);
color: red;
font-size: 14px;
margin: 15px 0;
}
</style>
<body>
<textarea name="" id=""></textarea>
<button>投稿</button>
<ul>
</ul>
<script>
// 1. 要素の取得
var postButton = document.querySelector('button');
var inputArea = document.querySelector('textarea');
var commentList = document.querySelector('ul');
// 2. イベントの登録
postButton.onclick = function() {
if (inputArea.value == '') {
alert('内容が入力されていません');
return false;
} else {
// console.log(inputArea.value);
// (1) 要素の作成
var item = document.createElement('li');
// 作成したitemに値を設定
item.innerHTML = inputArea.value;
// (2) 要素の追加
// commentList.appendChild(item);
commentList.insertBefore(item, commentList.children[0]);
}
}
</script>
</body>