jQuery の .removeClass() メソッドでは、「引数に関数を指定する」ことで柔軟なclass削除が実現できます。
「特定の文字列で始まるclass」を一括削除
「ユーザー操作に応じて画面表示を変更する」際など、要素の状態をあらわす "is-active"、"is-visible"、"is-fixed"、"is-closed" といった「特定の文字列で始まるclass」を複数利用する場合があると思います。
例えばこれらの "is-***" というclassのみを一括で削除したい場合、正規表現を利用した以下の方法で実現できます。
<div id="sample" class="block element is-active is-visible is-fixed">***</div>
<script>
// 'is-' で始まるclassをすべて削除
$('#sample').removeClass(function(index, className) {
return (className.match(/\bis-\S+/g) || []).join(' ');
});
// 結果: <div id="sample" class="block element">***</div>
</script>
もう少し詳しい説明
関数の戻り値が削除対象classとなる
.removeClass() メソッドの引数に関数が指定された場合、その関数の戻り値(returnされた値)と一致するclassが削除対象となります。
このことは、以下のコードの実行結果から確認できます。
<div id="sample" class="block element is-active is-visible is-fixed">***</div>
<script>
// 'is-active' を削除
$('#sample').removeClass(function() {
return 'is-active';
});
// 結果: <div id="sample" class="block element is-visible is-fixed">***</div>
</script>
つまり
「関数をうまく利用して、削除したいclassをきちんとreturnできれば、複雑な処理も実現できそう」
ということになりますね。
関数で利用できる2つの引数
この関数では2つの引数を利用することができ、
- 1つめの引数には「対象要素のインデックス番号」
- 2つめの引数には「対象要素の現在のclass属性値」
が入ります。
元のコードに戻り、
console.log() で確認してみましょう。
<div id="sample" class="block element is-active is-visible is-fixed">***</div>
<script>
// 'is-' で始まるclassをすべて削除
$('#sample').removeClass(function(index, className) {
console.log(index); // 0
console.log(className); // 'block element is-active is-visible is-fixed'
return (className.match(/\bis-\S+/g) || []).join(' ');
});
// 結果: <div id="sample" class="block element">***</div>
</script>
$('#sample') のインデックス番号「0」と、
現在のclass属性値「'block element is-active is-visible is-fixed'」が出力されることを確認できました。
正規表現を利用したマッチング
続いて、return されている値の部分に注目します。
(className.match(/\bis-\S+/g) || []).join(' ')
ここでの処理の流れとしては、
- 現在のclass属性値の文字列('block element is-active is-visible is-fixed')に対して.match() メソッドを実行し、正規表現(/\bis-\S+/)にマッチする値すべてを配列として取得
- 上記の配列に対して.join() メソッドを実行し、半角スペース区切りで結合して文字列に変換
となります。
正規表現の部分では「特殊文字」の使い方がポイントになります。
今回使用する特殊文字は以下です。
\b:単語の区切りにマッチ
\S:ホワイトスペース以外の1文字にマッチ
+:直前の文字の1回以上の繰り返しにマッチ
つまり /\bis-\S+/ は
「{単語の区切り}is-{ホワイトスペース以外の1文字以上}」
にマッチすることになります。
末尾のgは「グローバル検索フラグ」です。
これが無い場合は最初のマッチ('is-active')の時点で検索処理が終了してしまうため、
忘れずに付けるようにしましょう。
例外(エラー)処理も重要
.match() メソッドの直後に現れる
|| []
は何を意味するのでしょうか。
これは、「正規表現にマッチするclassが1つも存在しなかった場合」に
後続の.join() メソッドでエラーが発生してしまうのを防ぐための処理です。
以下の例のように、"is-" で始まるclassを1つも持たない要素を対象とした場合、3つめの console.log() でエラーが発生することが確認できます。
<div id="sample" class="block element">***</div>
<script>
// 'is-' で始まるclassをすべて削除
$('#sample').removeClass(function(index, className) {
console.log(className); // 'block element'
console.log(className.match(/\bis-\S+/g)); // null
console.log((className.match(/\bis-\S+/g)).join(' ')); // Uncaught TypeError: Cannot read property 'join' of null
});
</script>
null に対して.join() メソッドなんて使えないよ、ということですね。
|| []
を追記することで、マッチするclassが無かった場合には空の配列が生成され、
.join() メソッド呼び出し時のエラーを回避できます。
まとめ
ここまでの内容をふまえ、
コードを小さな単位に分解して console.log() してみましょう。
処理の流れがより理解できるかと思います。
<div id="sample" class="block element is-active is-visible is-fixed">***</div>
<script>
// 'is-' で始まるclassをすべて削除
$('#sample').removeClass(function(index, className) {
console.log(className); // 'block element is-active is-visible is-fixed'
console.log(className.match(/\bis-\S+/g)); // ['is-active', 'is-visible', 'is-fixed']
console.log((className.match(/\bis-\S+/g) || []).join(' ')); // 'is-active is-visible is-fixed'
return (className.match(/\bis-\S+/g) || []).join(' ');
// つまり
// return 'is-active is-visible is-fixed';
});
// 結果: <div id="sample" class="block element">***</div>
</script>
期待通りに 'is-active is-visible is-fixed' が return され、
**「"is-***" というclassのみを一括で削除」**が実現できました。
.addClass() は?
何となく想像はつくかと思いますが、
.addClass() メソッドでも同様に、引数に関数を指定することができます。
<ul id="sampleList">
<li>***</li>
<li>***</li>
</ul>
<script>
// 'li' に連番でclassを追加
$('#sampleList li').addClass(function(index, className) {
return 'item-' + index;
});
// 結果:
// <ul id="sampleList">
// <li class="item-0">***</li>
// <li class="item-1">***</li>
// </ul>
</script>
参考リンク
より詳しい内容については公式リファレンスを参照してください。
.removeClass() | jQuery API Documentation
.addClass() | jQuery API Documentation