ボタンをクリックすると別の要素にclassが付いたり外れたりするサンプルコードを、素のJavaScriptでまとめておきます。jQueryなどのライブラリは使いません。付け外しをまとめて済ませたいなら classList.toggle、必ず付ける・必ず外すを分けたいなら classList.add と classList.remove を使い分けるのが基本です。
まずは基本形:クリックでclassをトグルする
いちばんシンプルなのは、ボタンを押すたびにclassが付いたり外れたりする「トグル」です。ここでは黄色い背景になる highlight というclassを、別の要素に付け外しします。
HTML
<button class="myButton">クリック</button>
<div class="myElement">切り替わる要素</div>
CSS
.highlight {
background-color: yellow;
}
JavaScript
const button = document.querySelector(".myButton");
const element = document.querySelector(".myElement");
button.addEventListener("click", () => {
element.classList.toggle("highlight");
});
やっていることは3つだけです。querySelector で最初に一致した要素を取り出し、addEventListener で click イベントを登録し、クリックのたびに classList.toggle を呼びます。イベントの登録は addEventListener が推奨の書き方で、MDNでも register する際の推奨手段とされています(onclick 属性より扱いやすく、同じ要素に複数のハンドラーを付けられます)。
classList.toggle は、そのclassが無ければ追加し、あれば削除してくれます。戻り値は真偽値で、追加されたときは true、削除されたときは false が返ります。開閉ボタンのような用途なら、これ一行で往復できます。
追加と削除を分けたいとき
トグルは手軽ですが、「この操作では必ず付ける」「別の操作では必ず外す」と役割を分けたい場面もあります。そのときは classList.add と classList.remove を直接呼びます。
element.classList.add("highlight"); // 状態にかかわらず必ず付ける
element.classList.remove("highlight"); // 状態にかかわらず必ず外す
条件によって付けるか外すかを切り替えたいだけなら、toggle の第2引数(force)が使えます。第2引数に true を渡すと必ず追加、false なら必ず削除になります。
// isActive が true なら付ける、false なら外す
element.classList.toggle("highlight", isActive);
複数の要素をまとめて操作する
同じclassを持つ要素が複数あるなら、querySelectorAll で全部取得して forEach で回します。querySelector は最初の1個しか返さないので、複数を扱うときはこちらです。
const button = document.querySelector(".myButton");
const elements = document.querySelectorAll(".myElement");
button.addEventListener("click", () => {
elements.forEach((element) => {
element.classList.toggle("highlight");
});
});
クリック回数の偶数・奇数で切り替える
「偶数回で付けて奇数回で外す」といったカウント制御も、考え方は同じです。回数を数えて、その結果を toggle の第2引数に渡すと分岐がすっきりします。
const button = document.querySelector(".myButton");
const elements = document.querySelectorAll(".myElement");
let clickCount = 0;
button.addEventListener("click", () => {
clickCount++;
const isEven = clickCount % 2 === 0;
elements.forEach((element) => {
element.classList.toggle("highlight", isEven);
});
});
clickCount % 2 === 0 が偶数回の判定です。これを toggle の第2引数に渡すだけなので、if で追加・削除を書き分ける必要がありません。奇数回で付けたい場合は判定を === 1 にすれば逆になります。
data属性でターゲットを指定する
ボタンごとに操作する相手を変えたいときは、data-* 属性にターゲットのセレクタを持たせておくと便利です。対応関係をHTML側で管理できるので、ボタンが増えてもJavaScriptを書き換えずに済みます。
<button data-target=".box1">ボックス1を切り替え</button>
<button data-target=".box2">ボックス2を切り替え</button>
<div class="box1">対象1</div>
<div class="box2">対象2</div>
document.querySelectorAll("[data-target]").forEach((button) => {
button.addEventListener("click", () => {
const target = document.querySelector(button.dataset.target);
target.classList.toggle("highlight");
});
});
button.dataset.target で data-target の値(ここではセレクタ文字列)が取り出せます。あとはそのセレクタで対象を探して toggle するだけ。ボタンとターゲットの組み合わせを増やしても、JavaScript側は一切触らなくて済みます。
実装のポイント
最後に、私が使い分けるときの目安をまとめておきます。
- 付け外しを1つで済ませたいなら
classList.toggle、必ず付ける・外すを分けたいならaddとremove。 - 要素が複数あるときは
querySelectorAllとforEachの組み合わせ。 - 条件で切り替えるだけなら、
ifを書かずにtoggleの第2引数(force)に真偽値を渡す。 - 見た目の変化はCSSのclass側に寄せておくと、JavaScriptは「classを付け外しするだけ」に集中できて読みやすくなります。
素のJavaScriptでも、この程度のクラス操作ならライブラリなしで十分すっきり書けます。