●querySelector()で直下の子要素を取得
JavaScriptでDOM操作をする際に、特定の要素を取得する必要がありますよね。
今回は、その中でも特に「直下の子要素」に焦点を当てて、効率的に取得する方法をご紹介します。
「直下の子要素」とは、ある要素のすぐ下にある子要素のことを指します。
孫要素や、もっと下の階層の要素は含まれません。
この直下の子要素を取得するには、querySelector()メソッドが便利です。
querySelector()は、CSSセレクタを使って要素を取得するメソッドです。
これを使えば、特定のタグ名、クラス名、ID名などを指定して、簡単に目的の要素を取得できます。
では、実際にコードを見ながら、具体的な使い方を見ていきましょう。
○サンプルコード1:タグ名で取得
<div id="parent">
<p>子要素1</p>
<p>子要素2</p>
<div>
<p>孫要素</p>
</div>
</div>
const parent = document.getElementById('parent');
const firstChild = parent.querySelector('p');
console.log(firstChild.textContent); // "子要素1"
このコードでは、まずgetElementById()
で親要素を取得しています。
そして、その親要素に対してquerySelector('p')
を使うことで、直下の<p>
要素を取得しています。
取得した要素のtextContent
プロパティを出力すると、”子要素1″が表示されます。
これは、最初に見つかった<p>
要素の内容ですね。
○サンプルコード2:クラス名で取得
<div id="parent">
<p class="child">子要素1</p>
<p class="child">子要素2</p>
<div>
<p class="child">孫要素</p>
</div>
</div>
const parent = document.getElementById('parent');
const firstChild = parent.querySelector('.child');
console.log(firstChild.textContent); // "子要素1"
このように、クラス名を指定して要素を取得することもできます。
.child
というCSSセレクタを使うことで、class="child"
を持つ要素のうち、最初に見つかったものを取得しています。
○サンプルコード3:ID名で取得
<div id="parent">
<p id="child1">子要素1</p>
<p id="child2">子要素2</p>
<div>
<p id="grandchild">孫要素</p>
</div>
</div>
const parent = document.getElementById('parent');
const firstChild = parent.querySelector('#child1');
console.log(firstChild.textContent); // "子要素1"
ID名を指定する場合は、#child1
のように、#
に続けてID名を書きます。
これで、id="child1"
を持つ要素を取得できます。
●querySelectorAll()ですべての子要素を取得
前回は、querySelector()を使って直下の子要素を1つだけ取得する方法を見てきました。
でも、実際の開発では、条件に合致する子要素を全て取得したいことも多いですよね。
そんな時は、querySelectorAll()を使うのが便利です。
これは、querySelector()と同じくCSSセレクタを使って要素を取得するのですが、条件に合致する全ての要素を配列のようなNodeListオブジェクトとして返してくれます。
NodeListオブジェクトは、配列のように要素にアクセスできます。
例えば、インデックス番号を指定して特定の要素を取得したり、lengthプロパティで要素の数を取得したりできます。
それでは、具体的なコードを見ながら、querySelectorAll()の使い方を理解していきましょう。
○サンプルコード4:タグ名ですべて取得
<div id="parent">
<p>子要素1</p>
<p>子要素2</p>
<div>
<p>孫要素</p>
</div>
</div>
const parent = document.getElementById('parent');
const children = parent.querySelectorAll('p');
console.log(children.length); // 2
console.log(children[0].textContent); // "子要素1"
console.log(children[1].textContent); // "子要素2"
このコードでは、querySelectorAll('p')
を使って、直下の全ての<p>
要素を取得しています。
取得した要素は、変数children
に格納されます。
children.length
を出力すると、2
が表示されます。
これは、条件に合致した要素が2つあることを表しています。
そして、children[0]
やchildren[1]
のように、インデックス番号を指定することで、個々の要素にアクセスできます。
それぞれのtextContent
プロパティを出力すると、”子要素1″、”子要素2″が表示されますね。
○サンプルコード5:クラス名ですべて取得
<div id="parent">
<p class="child">子要素1</p>
<p class="child">子要素2</p>
<div>
<p class="child">孫要素</p>
</div>
</div>
const parent = document.getElementById('parent');
const children = parent.querySelectorAll('.child');
console.log(children.length); // 2
console.log(children[0].textContent); // "子要素1"
console.log(children[1].textContent); // "子要素2"
クラス名を指定して要素を取得することもできます。
.child
というCSSセレクタを使うことで、class="child"
を持つ要素を全て取得しています。
取得した要素は、先ほどと同じようにNodeListオブジェクトとして返されます。
インデックス番号を指定して個々の要素にアクセスできることも同じですね。
●childrenプロパティで子要素を取得
querySelector()やquerySelectorAll()を使えば、CSSセレクタを使って柔軟に子要素を取得できることがわかりました。
でも正直、セレクタを書くのって結構面倒ですよね。
もっと簡単に子要素を取得する方法はないのでしょうか。
実は、childrenプロパティを使えば、CSSセレクタを使わずに直下の子要素を取得できるんです。
childrenプロパティは、ある要素の直下にある全ての子要素を、HTMLCollectionオブジェクトとして返してくれます。
HTMLCollectionオブジェクトは、NodeListオブジェクトと同じように、配列のように扱うことができます。
インデックス番号を指定して特定の要素を取得したり、lengthプロパティで要素の数を取得したりできます。
それでは、実際のコードを見ながら、childrenプロパティの使い方を理解していきましょう。
○サンプルコード6:インデックス指定で特定の子要素を取得
<div id="parent">
<p>子要素1</p>
<p>子要素2</p>
<p>子要素3</p>
</div>
const parent = document.getElementById('parent');
const children = parent.children;
console.log(children.length); // 3
console.log(children[0].textContent); // "子要素1"
console.log(children[1].textContent); // "子要素2"
console.log(children[2].textContent); // "子要素3"
このコードでは、getElementById()
で親要素を取得した後、children
プロパティを使って直下の子要素を取得しています。
取得した子要素は、変数children
に格納されます。
children.length
を出力すると、3
が表示されます。
これは、親要素の直下に3つの子要素があることを示しています。
そして、children[0]
、children[1]
、children[2]
のように、インデックス番号を指定することで、個々の子要素にアクセスできます。
それぞれのtextContent
プロパティを出力すると、”子要素1″、”子要素2″、”子要素3″が表示されますね。
○サンプルコード7:ループですべての子要素を処理
<div id="parent">
<p>子要素1</p>
<p>子要素2</p>
<p>子要素3</p>
</div>
const parent = document.getElementById('parent');
const children = parent.children;
for (let i = 0; i < children.length; i++) {
console.log(children[i].textContent);
}
実行結果:
子要素1
子要素2
子要素3
childrenプロパティで取得した子要素は、for文などを使ってループ処理することもできます。
このコードでは、for文を使って、各子要素のtextContent
プロパティを順番に出力しています。
実行結果を見ると、”子要素1″、”子要素2″、”子要素3″が順番に表示されていますね。
このように、childrenプロパティとループを組み合わせることで、全ての子要素を一括で処理できます。
●その他の子要素の取得方法
これまで、querySelector()、querySelectorAll()、childrenプロパティを使って、直下の子要素を取得する方法を見てきました。
でも、状況によっては、これらの方法だけでは物足りないこともあるでしょう。
そんな時に使えるのが、getElementsByTagName()やgetElementsByClassName()、childNodesプロパティです。
これを使えば、もっと柔軟に子要素を取得できるようになりますよ。
○getElementsByTagName()
getElementsByTagName()は、指定したタグ名を持つ要素を全て取得するメソッドです。
これを使えば、特定のタグを持つ子要素だけを取得できます。
<div id="parent">
<p>子要素1</p>
<div>子要素2</div>
<p>子要素3</p>
</div>
const parent = document.getElementById('parent');
const children = parent.getElementsByTagName('p');
console.log(children.length); // 2
console.log(children[0].textContent); // "子要素1"
console.log(children[1].textContent); // "子要素3"
このコードでは、getElementsByTagName('p')
を使って、親要素の直下にある<p>
要素を全て取得しています。
取得した要素は、HTMLCollectionオブジェクトとして返されます。
children.length
を出力すると、2
が表示されます。
これは、親要素の直下に<p>
要素が2つあることを表しています。
そして、children[0]
とchildren[1]
のtextContent
プロパティを出力すると、”子要素1″と”子要素3″が表示されます。
これは、<p>
要素だけが取得されていることを表していますね。
○getElementsByClassName()
getElementsByClassName()は、指定したクラス名を持つ要素を全て取得するメソッドです。
これを使えば、特定のクラスを持つ子要素だけを取得できます。
<div id="parent">
<p class="child">子要素1</p>
<div class="child">子要素2</div>
<p>子要素3</p>
</div>
const parent = document.getElementById('parent');
const children = parent.getElementsByClassName('child');
console.log(children.length); // 2
console.log(children[0].textContent); // "子要素1"
console.log(children[1].textContent); // "子要素2"
このコードでは、getElementsByClassName('child')
を使って、親要素の直下にあるclass="child"
を持つ要素を全て取得しています。
取得した要素は、HTMLCollectionオブジェクトとして返されます。
children.length
を出力すると、2
が表示されます。
これは、親要素の直下にclass="child"
を持つ要素が2つあることを示しています。
そして、children[0]
とchildren[1]
のtextContent
プロパティを出力すると、”子要素1″と”子要素2″が表示されます。
これは、class="child"
を持つ要素だけが取得されていることを表していますね。
○childNodes
childNodesプロパティは、ある要素の直下にある全ての子ノードを取得するプロパティです。
子ノードには、要素ノード、テキストノード、コメントノードなどが含まれます。
<div id="parent">
<p>子要素1</p>
<!-- コメント -->
<p>子要素2</p>
</div>
const parent = document.getElementById('parent');
const childNodes = parent.childNodes;
console.log(childNodes.length); // 5
console.log(childNodes[0].nodeType); // 3 (テキストノード)
console.log(childNodes[1].nodeType); // 1 (要素ノード)
console.log(childNodes[2].nodeType); // 8 (コメントノード)
console.log(childNodes[3].nodeType); // 3 (テキストノード)
console.log(childNodes[4].nodeType); // 1 (要素ノード)
このコードでは、childNodes
プロパティを使って、親要素の直下にある全ての子ノードを取得しています。
取得した子ノードは、NodeListオブジェクトとして返されます。
childNodes.length
を出力すると、5
が表示されます。これは、親要素の直下に5つの子ノードがあることを表しています。
そして、各子ノードのnodeType
プロパティを出力すると、それぞれのノードの種類がわかります。
1
は要素ノード、3
はテキストノード、8
はコメントノードを表しています。
●よくあるエラーと対処法
JavaScriptを使ってDOM操作をしていると、思わぬエラーに遭遇することがありますよね。
特に、子要素の取得に関しては、初心者の方が陥りやすい落とし穴がいくつかあります。
そこで、ここではよくあるエラーとその対処法を見ていきましょう。
これらを理解しておけば、より円滑にJavaScriptを書けるようになるはずです。
○エラー1:子要素が1つもない場合
まず、ある要素の子要素を取得しようとした時に、実際には子要素が1つもない場合があります。
そんな時、どうなるのでしょうか。
<div id="parent"></div>
const parent = document.getElementById('parent');
const child = parent.querySelector('p');
console.log(child); // null
このコードでは、id="parent"
の要素の直下に<p>
要素を探そうとしています。
しかし、実際にはid="parent"
の要素は空で、子要素は1つもありません。
この場合、querySelector()
はnull
を返します。
null
はJavaScriptの特殊な値で、「値が存在しない」ことを表します。
したがって、子要素が見つからなかった場合は、null
が返ってくることを念頭に置いておく必要があります。
もし、null
に対して何らかの操作をしようとすると、エラーが発生します。
これを防ぐには、子要素が存在するかどうかを事前にチェックするのが良いでしょう。
if
文を使って、null
かどうかを判定するのが一般的です。
const parent = document.getElementById('parent');
const child = parent.querySelector('p');
if (child !== null) {
console.log(child.textContent);
} else {
console.log('子要素が見つかりませんでした。');
}
このように書けば、子要素が存在しない場合でもエラーが発生せず、適切なメッセージを出力できます。
○エラー2:存在しないセレクタを指定した場合
次に、querySelector()
やquerySelectorAll()
に存在しないセレクタを指定した場合を考えてみましょう。
<div id="parent">
<p>子要素1</p>
</div>
const parent = document.getElementById('parent');
const child = parent.querySelector('.child');
console.log(child); // null
このコードでは、id="parent"
の要素の直下にclass="child"
を持つ要素を探そうとしています。しかし、実際にはclass="child"
を持つ要素は存在しません。
この場合も、querySelector()
はnull
を返します。存在しないセレクタを指定した場合は、子要素が1つもない場合と同じ扱いになるのです。
したがって、対処法も同じです。
if
文を使ってnull
かどうかを判定し、適切な処理を行うようにしましょう。
○エラー3:パフォーマンス問題
最後に、パフォーマンスの問題について触れておきましょう。
JavaScriptでDOM操作を行う際は、常にパフォーマンスを意識する必要があります。
特に、querySelectorAll()
などを使って大量の要素を取得する場合、パフォーマンスが低下する可能性があります。
これは、querySelectorAll()
がDOMツリー全体を探索するため、要素数が多いほど時間がかかるためです。
<ul id="parent">
<li>子要素1</li>
<li>子要素2</li>
...
<li>子要素1000</li>
</ul>
const parent = document.getElementById('parent');
const children = parent.querySelectorAll('li');
console.log(children.length); // 1000
このように、1000個もの子要素を取得しようとすると、かなりの時間がかかってしまいます。
ユーザー体験を損なわないためにも、このような大量のDOM操作は避けるべきでしょう。
もし、どうしても大量の要素を取得する必要がある場合は、getElementsByTagName()
やgetElementsByClassName()
を使うのが良いでしょう。
これらのメソッドは、querySelectorAll()
よりも高速に動作します。
また、可能な限り、DOM操作の回数を減らすことも大切です。
例えば、ループ内でDOM操作を行うのは避けましょう。
代わりに、一時的な変数にデータを保持し、最後にまとめてDOMに反映するようにします。
const parent = document.getElementById('parent');
const children = parent.getElementsByTagName('li');
let html = '';
for (let i = 0; i < children.length; i++) {
html += '<p>' + children[i].textContent + '</p>';
}
parent.innerHTML = html;
このように、一時的な変数html
を使って<p>
タグを構築し、最後にinnerHTML
プロパティを使ってDOMに反映します。
こうすることで、DOM操作の回数を最小限に抑えられます。
●JavaScriptで直下の子要素を操作する応用例
これまで、JavaScriptを使って直下の子要素を取得する方法を様々に見てきました。
querySelector()、querySelectorAll()、childrenプロパティなど、状況に応じて適切な方法を選べるようになったのではないでしょうか。
でも、子要素を取得するだけでは物足りないですよね。せっかく取得した子要素を、実際に操作してみたいと思うのが人情です。
そこで、ここからは子要素を操作する応用例を見ていきましょう。子要素の削除や追加など、よく使われるテクニックを紹介します。
これを習得すれば、よりインタラクティブなWebサイトを作れるようになるはずです。
それでは、具体的なコードを見ながら、一緒に学んでいきましょう。
○サンプルコード8:特定の子要素を削除
まずは、特定の子要素を削除する方法から見ていきましょう。
ある要素の直下にある子要素を削除するには、removeChild()
メソッドを使います。
<div id="parent">
<p id="child1">子要素1</p>
<p id="child2">子要素2</p>
<p id="child3">子要素3</p>
</div>
const parent = document.getElementById('parent');
const child2 = document.getElementById('child2');
parent.removeChild(child2);
実行結果:
<div id="parent">
<p id="child1">子要素1</p>
<p id="child3">子要素3</p>
</div>
このコードでは、まずgetElementById()
を使って、親要素と削除したい子要素を取得しています。
そして、親要素のremoveChild()
メソッドに、削除したい子要素を渡しています。
実行結果を見ると、id="child2"
の要素が削除されていることがわかります。
このように、removeChild()
メソッドを使えば、特定の子要素を簡単に削除できます。
ただ、removeChild()
メソッドを使うためには、削除したい子要素への参照を取得する必要があります。
上の例ではgetElementById()
を使っていますが、他にもquerySelector()などを使うこともできます。
○サンプルコード9:すべての子要素を削除
次に、ある要素の直下にあるすべての子要素を削除する方法を見ていきましょう。
これは、innerHTML
プロパティを使うのが簡単です。
<div id="parent">
<p>子要素1</p>
<p>子要素2</p>
<p>子要素3</p>
</div>
const parent = document.getElementById('parent');
parent.innerHTML = '';
実行結果:
<div id="parent"></div>
このコードでは、getElementById()
を使って親要素を取得した後、そのinnerHTML
プロパティに空文字列を代入しています。
これにより、親要素の中身がすべて削除されます。
実行結果を見ると、<div id="parent">
の中が空になっていますね。
このように、innerHTML
プロパティを使えば、簡単にすべての子要素を削除できます。
ただ、innerHTML
プロパティを使うと、元々あった子要素のイベントリスナーなども削除されてしまうので注意が必要です。
イベントリスナーを維持したままにしたい場合は、ループを使ってremoveChild()
メソッドを呼び出す必要があります。
○サンプルコード10:子要素を動的に追加
最後に、子要素を動的に追加する方法を見ていきましょう。
これは、appendChild()
メソッドを使うのが一般的です。
<div id="parent"></div>
const parent = document.getElementById('parent');
for (let i = 1; i <= 3; i++) {
const child = document.createElement('p');
child.textContent = `子要素${i}`;
parent.appendChild(child);
}
実行結果:
<div id="parent">
<p>子要素1</p>
<p>子要素2</p>
<p>子要素3</p>
</div>
このコードでは、まずcreateElement()
メソッドを使って新しい<p>
要素を作成しています。
そして、そのtextContent
プロパティに子要素${i}
という文字列を代入することで、要素の中身を設定しています。
最後に、親要素のappendChild()
メソッドに、新しく作成した子要素を渡すことで、子要素を親要素の末尾に追加しています。
このプロセスをfor文で3回繰り返すことで、3つの子要素を動的に追加しています。
実行結果を見ると、<div id="parent">
の中に<p>
要素が3つ追加されていますね。
このように、appendChild()
メソッドを使えば、JavaScriptで動的に子要素を追加できます。
まとめ
こんな感じで、JavaScriptを使って直下の子要素を取得・操作する方法を見てきましたが、いかがだったでしょうか。
自分でコードを書いて、試行錯誤することが一番の学習になります。
エラーが出ても、めげずにデバッグしていきましょう。
その過程で、JavaScriptとDOM操作の理解が深まっていくはずです。
私からは以上になりますが、みなさんのJavaScriptとDOM操作のスキルが、今後ますます向上していくことを願っています。