IEだとうまく動かないJavaScriptがあり、調べたところ Element.classList
が原因だった。
まだまだIE11は切れない環境なので、備忘としてメモ。
環境
Windows 10 Pro 64bit、Internet Explorer 11.476.18362.0で確認。
IEでは動かないメソッド
MDNを見れば対応表がある。
今回引っかかったのは以下2つ。
add, removeの引数に配列を渡せない
classList.add(String [, String [, ...]])
および classList.remove(String [, String [, ...]])
が、他ブラウザでは文字列の配列として複数のクラス名を渡せるのに対し、IEでは文字列として単一のクラス名しか渡せない。
対応としては、IE9以降なら Array.forEach
は使えるので、1つずつ渡してやればいい。
const targetElement = ...; const targetClassList = targetElement.classList; const targetClasses = ['foo', 'bar']; // IE以外 targetClassList.add(targetClasses); console.log(targetClassList); // foo,bar targetClassList.remove(targetClasses); console.log(targetClassList); // 空 // IE対応 targetClasses.forEach(function(targetClass) { targetClassList.add(targetClass); }); console.log(targetClassList); // foo,bar targetClasses.forEach(function(targetClass) { targetClassList.remove(targetClass); }); console.log(targetClassList); // 空
こちらはエラーになってくれるのでわかりやすい。
toggleの第2引数を渡せない
こちらのほうがハマってしまった。
classList.toggle(String [, force])
は、第1引数の文字列のクラス名は必須だが、第2引数の有無で挙動が変わる。
- 第2引数を渡さなければ、第1引数のクラスが指定されていれば削除、指定されていなければ追加
- 第2引数を渡すと、その値がtrueと評価されれば
classList.add
と同様にクラスを追加、falseと評価されればclassList.remove
と同様にクラスを削除
だが、IEの場合、第2引数が無視され、常に第2引数を渡さない場合の挙動となる。
対応としては、第2引数として渡していた値のtrue/falseで、それぞれadd/removeを呼ぶようにすればいい。
const targetElement = ...; const targetClassList = targetElement.classList; const toggleClass = 'foobar'; // IE以外 targetClassList.add(toggleClass); targetClassList.toggle(toggleClass, !targetClassList.contains(toggleClass)); console.log(targetClassList); // 空 targetClassList.toggle(toggleClass, !targetClassList.contains(toggleClass)); console.log(targetClassList); // foobar // IE対応 targetClassList.add(toggleClass); if (!targetClassList.contains(toggleClass)) { targetClassList.add(toggleClass); } else { targetClassList.remove(toggleClass); } console.log(targetClassList); // 空 // ワンライナーで targetClassList[!targetClassList.contains(toggleClass) ? 'add' : 'remove'](toggleClass); console.log(targetClassList); // foobar
こちらのほうが、エラーにならないので面倒。
replaceが未実装
これは引っかかったわけではないが、いちおう書いておく。
classList.replace(String, String)
で、第1引数のクラス名を第2引数のクラス名に置換できるが、IEではこのメソッド自体が未実装の模様。
対応としては、第1引数のクラス名を classList.contains
で設定されているか判定、設定されていればremoveおよび第2引数のクラス名をaddしてやればよさそう。
valueプロパティが存在しない
IEではclassList関連で使えない機能が色々ある。 - 青いやつの進捗日記。にて言及いただいていたので、2020/11/29追記。
ただ、MDN見てもcaniuse見てもclassList.valueがどうなのか、記述が無い…
については、classListはDOMTokenListインターフェースを実装しており、valueプロパティはDOMTokenList.valueとしてDOMTokenListで定義されている。そしてそれがIEでは未実装だった。
記事では String(element.classList)
文字列に変換しているが、classを文字列として取得したいのであれば、昔ながらのElement.classNameを使うのが手っ取り早そう。
確認したところ、 classList.value
は className
と同様、不要な半角スペースなど含んで返してくる。
昔は className
を半角スペースで分割して、空文字は除外してどうのこうのとかやってたなぁ...
振り返り
IE6~8対応とかやっていたころに比べると、IE11ならだいぶ楽に対応できるようになったが、まだまだ非互換は残っているんだなぁ...