複数のHTML要素をまとめて操作しよう
更新日:2026-08-02
同じ役割のボタンが複数ある場合は、要素ごとに処理を繰り返し書かず、まとめて取得して処理します。
今回は、記事一覧をカテゴリで絞り込むボタンを作ります。この記事を終えると、querySelectorAll()の戻り値、forEach()の役割、クリックされた要素の見分け方を説明できるようになります。
今回使用するファイル構成
javascript-practice/
├── index.html
└── js/
└── script.js
複数要素を扱う流れ
querySelectorAllで取得する
<button class="filter-button" type="button">HTML</button>
<button class="filter-button" type="button">CSS</button>
<button class="filter-button" type="button">JavaScript</button>
const buttons = document.querySelectorAll('.filter-button');
console.log(buttons.length);
querySelectorAll()は条件に一致する要素をNodeListとして返します。
forEachでイベントを登録する
buttons.forEach((button) => {
button.addEventListener('click', () => {
buttons.forEach((item) => item.classList.remove('is-active'));
button.classList.add('is-active');
});
});
クリックされたbuttonだけへ.is-activeを追加する前に、すべてのボタンから同じクラスを削除しています。
コールバックの要素を確認する
buttons.forEach((button, index) => {
console.log(index, button.textContent);
});
要素と番号をConsoleへ出すと、繰り返しの対象を確認できます。
要素が0件でもエラーにならない
querySelector()は見つからない場合にnullを返しますが、querySelectorAll()は要素数0のNodeListを返します。forEach()の処理は実行されません。
記事の絞り込み機能を完成させる
絞り込み対象をHTMLへ追加する
先ほどのボタンにdata-category属性を付け、記事側にも対応する値を持たせます。
<div aria-label="記事の絞り込み">
<button class="filter-button is-active" type="button" data-category="all">すべて</button>
<button class="filter-button" type="button" data-category="html">HTML</button>
<button class="filter-button" type="button" data-category="css">CSS</button>
<button class="filter-button" type="button" data-category="javascript">JavaScript</button>
</div>
<p id="filter-result" aria-live="polite"></p>
<ul>
<li class="article-item" data-category="html">HTMLの基本</li>
<li class="article-item" data-category="css">Flexbox入門</li>
<li class="article-item" data-category="javascript">DOM操作</li>
</ul>
data-categoryは、画面に表示しない補助データです。詳しい仕組みは第16回で扱います。
クリックしたカテゴリだけを表示する
js/script.jsを次の内容にします。
const buttons = document.querySelectorAll('.filter-button');
const articles = document.querySelectorAll('.article-item');
const result = document.querySelector('#filter-result');
buttons.forEach((button) => {
button.addEventListener('click', () => {
const selectedCategory = button.dataset.category;
let visibleCount = 0;
buttons.forEach((item) => {
item.classList.remove('is-active');
});
button.classList.add('is-active');
articles.forEach((article) => {
const shouldShow =
selectedCategory === 'all' ||
article.dataset.category === selectedCategory;
article.hidden = !shouldShow;
if (shouldShow) {
visibleCount += 1;
}
});
result.textContent = `${visibleCount}件の記事を表示しています。`;
});
});
hiddenへtrueを設定すると要素が非表示になります。!shouldShowは真偽値を反転するため、「表示する条件に当てはまらない要素を隠す」という意味です。
動作を順番に確認する
- HTMLボタンを押し、HTMLの記事だけが残ることを確認する
- CSSとJavaScriptでも同様に確認する
- 「すべて」で3件に戻ることを確認する
- 選択中のボタンだけに
is-activeが付くことをDevToolsで確認する
よくある間違い
最後の一件しか処理されない
querySelector()は最初の一件だけを返します。複数件を処理する場合はquerySelectorAll()を使います。
forEachの中で同じ変数名を使って混乱する
ボタン全体はbuttons、現在処理中の一件はbuttonのように、単数形と複数形を使い分けます。
NodeListは配列と同じなのか
NodeListは配列に似ていますが、配列のすべてのメソッドを持つわけではありません。forEach()は使えます。filter()やmap()が必要ならArray.from(buttons)で配列へ変換します。
まとめ
複数要素はquerySelectorAll()で取得し、forEach()で同じ処理を適用できます。次の記事では、JavaScriptから新しいHTML要素を作成・追加・削除します。