【JavaScript】HTMLのクラスを操作するには？〜classListの使い方〜

# `classList`
HTMLの要素（`Element`）には`classList`プロパティがあります。
`classList`の中身はオブジェクトになっていて、そこには`class`属性を変更するための便利なメソッドが揃っています。

```js
const element = document.getElementById('変更したい要素のid')
element.classList // オブジェクトが入っている
```

基本的にはここから変更するのがおすすめです。

## `DOMTokenList`
`classList`プロパティに入っているのは、[`DOMTokenList`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList)のインスタンスです。
`DOMTokenList`はスペース（` `）で区切られた文字列を示し、これを変更するためのメソッドがいくつかあります。

- `add`
- `remove`
- `toggle`
- etc...

`class`属性に入る文字列はスペース区切りなので、`DOMTokenList`が使えるといった感じです。

:::note warn
`DOMTokenList`のインスタンスを自分で作成することは、おそらく不可能です。
`new`しようとしてもエラーになってしまいます。

```js
const list = new DOMTokenList()
// Uncaught TypeError: Illegal constructor
```

おそらくと言ったのは、`DOMTokenList`のコンストラクタに関する情報が見つけられなかったからです。
[MDN](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList)に載ってなかったので多分無理なのでしょう。
:::

## `className`
クラスを示す文字列である[`className`](https://developer.mozilla.org/ja/docs/Web/API/Element/className)プロパティというものもあります。

`className`を変更することでもクラスを操作できますが、`classList`のほうがいろいろと便利なので、基本的には`classList`がおすすめです。

なお、`className`は`classList`の変更と連動しています。
そのため`classList`を変えると`className`も変わり、逆もまた然りです。

# メソッド

ここからは`DOMTokenList`のメソッド、つまりHTML要素のクラスを操作する具体的な方法を紹介します。

## [`add`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/add)
要素にクラスを追加します。

- 引数: 追加したいクラス（群）
- 戻り値: なし

```js
const elem = document.getElementById('id')
elem.className // 'class1'

elem.classList.add('class2') // class2というクラスを追加する
elem.className // 'class1 class2'

elem.classList.add('class3', 'class4') // class3とclass4を追加する
elem.className // 'class1 class2 class3 class4'
```

## [`remove`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/remove)
要素からクラスを削除します。

- 引数: 削除したいクラス（群）
- 戻り値: なし

```js
const elem = document.getElementById('id')
elem.className // 'class1 class2 class3'

elem.classList.remove('class1') // class1というクラスを削除する
elem.className // 'class2 class3'

elem.classList.remove('class2', 'class3') // class2とclass3を削除する
elem.className // ''
```

## [`toggle`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/toggle)
クラスがすでに存在するなら削除し、存在しなければ追加します。
名前の通りクラスのある / ないを切り替えるようなメソッドです。

- 引数: 
    1. トグルしたいクラス
    1. どちらかの操作を強制的に行うためのフラグ（オプション）
- 戻り値: クラスを追加したら`true`、クラスを削除したら`false`

```js
const elem = document.getElementById('id')
elem.className // 'class1'

elem.classList.toggle('class2') // class2を追加する、true
elem.className // 'class1, class2'

elem.classList.toggle('class2') // class2を削除する、false
elem.className // 'class1'
```

## [`contains`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/contains)

クラスが含まれるかどうかを判定するメソッドです。

- 引数: 含まれるかどうか調べたいクラス
- 戻り値: 含まれているかどうかを示す`boolean`

```js
const elem = document.getElementById('id')
elem.className // 'class1'

elem.contains('class1') // true
elem.contains('class2') // false

elem.classList.add('class2') // class2を追加する
elem.contains('class2') // true
```

なお、`contains`と`add`と`remove`を組み合わせることで、`toggle`のような処理ができます。

```js
if (elem.contains(className)) {
  elem.remove(className)
} else {
  elem.add(className)
}
```

## [`replace`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/replace)
既存のクラスを別のクラスで置き換えるメソッドです。

- 引数:
    1. `oldToken`: 置き換える対象となるクラス
    1. `newToken`: `oldToken`を置き換えた後のクラス
- 戻り値: 置き換えられたか（`oldToken`が見つかったか）を示す`boolean`

```js
const elem = document.getElementById('id')
elem.className // 'class1 class2'

elem.classList.replace('class1', 'class3') // class1をclass3にする
elem.className // 'class3 class2'
```

## [`forEach`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/forEach)
全てのクラス名でループするメソッドです。
これは配列の`forEach`に似た動きをします。

- 引数: 各ループで実行する関数（`callbackFn`）
- 戻り値: `undefined`

また、`callbackFn`は以下の引数で実行されます。

1. `currentValue`: 現在の要素
1. `currentIndex`: 現在の要素のインデックス
1. `listObj`: 実行されている`DOMTokenList`

```js
const elem = document.getElementById('id')
elem.className // 'class1 class2'

elem.classList.forEach(current => {
  console.log(`クラス: ${current}`)
})

// クラス: class1
// クラス: class2
```

## プロパティ
ここで一度プロパティの紹介に移ります。

### [`value`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/value)
クラス名を示す文字列（半角スペース` `区切り）です。
`className`と`classList.value`は基本的に同じ値になります。

```js
const elem = document.getElementById('id')
elem.className // 'class1 class2'
elem.classList.value // 'class1 class2'
```

### [`length`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/length)
クラスがいくつ含まれているかを示す数値です。

```js
const elem = document.getElementById('id')
elem.className // 'class1 class2'
elem.length // 2

elem.classList.remove('class1')
elem.length // 1
```

## その他のメソッド
`DOMTokenList`には、ここで紹介した以外にも以下のメソッドがあります。

- [`items`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/item): インデックスに対応するクラスを返す
- [`values`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/values): 全てのクラス名を処理できるイテレーターを返す
- [`keys`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/keys): キー（`0, 1, ...`）を処理できるイテレーターを返す
- [`entries`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/entries): キーと値の両方を処理できるイテレーターを返す
- [`supports`](https://developer.mozilla.org/ja/docs/Web/API/DOMTokenList/supports) <!-- これどういうメソッド...? -->

詳細は各リンクから飛べるMDNのページをご覧ください。