フロントエンド/Vanilla JS
Vanilla JSはフレームワーク依存の多い現代に警鐘を鳴らすべく生まれた皮肉たっぷりのフレームワークだそうです。要するにスタンダードなバニラ味とは、フレームワークに依存しないでスクリプトを書くということのようです。特に「脱jQuery」という文言は一時期いろいろなところでみかけました。私はjQueryを結構好んで使ってますが、確かにプロジェクトによっては「$」が目障りだなと思うこともあるかもしれません。
昔はなかったdocument.querySelectorメソッドなんかがわかりやすいところで、DOMを操作するために必要な記述はjQueryを使わなくても簡単に書ける時代のようです。jQueryを使っていたプロジェクトから、jQueryを外したときに行ったことをメモしていきます。
セレクタ
$('#hoge')
idがついている要素は、昔からある通りdocument.getElementByIdで取得します。
document.getElementById('hoge');
$('.hoge.fuga')
document.querySelectorで先頭の要素を取得するか、該当する要素を全て取得するのにdocument.querySelectorAllを使う。
document.querySelector('.hoge.fuga');
document.querySelectorAll('.hoge.fuga');
$('.hoge')
クラス名で該当要素を取得する場合は、document.getElementsByClassNameが使えます。
document.getElementsByClassName('hoge');
こうしてみるとjQueryは統一された書き方で済むので扱うのは楽ですが、動作スピードがシビアな局面では条件分岐が入る分オーバーヘッドが大きそうですね。
$('input:checkbox:checked')
チェックのついたチェックボックスは、:checkedはCSSセレクタとして有効でも、:checkboxはjQuery独自の仕様っぽいです。
document.querySelectorAll('input[type="checkbox"]:checked');
$('#hoge').parent()
親はparentNodeでOK。
document.getElementById('hoge').parentNode;
イベント
$elm.on('click',function(){});
イベントリスナーを登録するのは、昔はブラウザ間で微妙に書き方が違いましたが、今はちゃんと統一されていますね。
elm.addEventListener('click',function(){});
$elm.offにはelm.removeEventListenerが対応しています。あんまり使ったことないですが。
$elm.trigger('click');
イベントを発生させるときには、document.dispatchEventを使います。
document.dispatchEvent(new Event('click'));
elm.dispatchEvent(new Event('click'));
Event('click')だとinput[type="file"]に渡してもファイル選択ダイアログを開いてくれなかったけど、そんなときにはMouseEventに変えてあげるといいみたい。
$(window).scrollTop()
ページの縦スクロール位置を知る方法も頻出ですね。まだブラウザ間でゴタゴタしている模様。時間の経過とともに統一されるとは思ってます。
document.documentElement.scrollTop || document.body.scrollTop;
AJAX
最近でもAJAXって呼び方であっているのか、ちょっと自信ないですが、外部のリソースを取ってくる処理のことのつもりです。XHR。fetchを使います。
$.get('hoge',{fuga:1},function(data){});
fetch('hoge?fuga=1).then(response => response.text()).then(data => {});
$.post('hoge',{fuga:1},function(data){});
const fd = new FormData();
fd.set('fuga',1);
fetch('hoge',{
method:'POST',
body:fd
}).then(response=>response.text()).then(data => {});
FormDataを$.ajaxで送信しているケースでは、processDataとcontentTypeにfalseを指定(↓)していましたが、それも不要になるということですね。
$.ajax({
url: hoge,
type: 'POST',
data. formdata, // FormData
processData: false,
contentType:false
});
認証情報をCookieに含めているときは要注意で、fetchの規定動作はCookieを送りません。(omit)
fetch('hoge',{credentials:'include'}); //Cookie渡しちゃう
fetch('hoge',{credentials:'same-origin'}); //origin縛りfetchのときCookie渡しちゃう
操作
$('.hoge').each(function(i){this;});
私はeachを多用します。JavaScriptだとforEachで代替できそうですが、getElementsByClassNameなんかはHTMLCollectionを返すので、そのままではforEachを使えませんでした。そこでArray.fromで配列化させます。
Array.from(document.getElementsByClassName('hoge')).forEach((el,i)=>{el;});
$('#hoge').val()
document.getElementById('hoge').value;
$('#hoge').attr('href')
document.getElementById('hoge').getAttribute('href');
.addClass,removeClass,toggleClass,hasClass
classの操作はclassListに同等のメソッドが揃っている模様。
const el = getElementById('hoge');
el.classList.add('fuga');
el.classList.remove('fuga');
el.classList.toggle('fuga');
el.classList.contains('fuga');
.append
element.appendChild(childElement);
.data('hoge')
var hoge = element.dataset.hoge;
element.dataset.hoge = 'fuga';
.remove
親要素からremoveChildで消すのが昔からある方法で、IEを無視できればremoveメソッドが叩けるとのこと。
element.delete();
.width(), .height()
document.defaultView.getComputedStyle(element,null).width;
document.defaultView.getComputedStyle(element,null).height;
アニメーション
アニメーションはjQueryが流行らせた要素の一つで、地味に面倒くさい実装を簡単に書けるようにしてくれていました。今だとCSS3のtransitionやanimationを使って静的なアニメーションで代替できるケースも増えています。それでも気の利いたことをやりたいときにJavaScriptで制御しなくてはならない部分がどうしても出てきそうです。slideDown、slideUp、slideToggleあたりを書き換えてみましたが、あんまり楽しい作業にならなかったので、jQueryにここは頼ったり、他のフレームワークで代用したり、アニメーションの内容を単純なものに差し替えたり、いろんな選択肢も一緒に検討できると幸せになれる気がしました。
ユーティリティ
$.extend(hoge,fuga)
Objectに別のObjectをマージする方法はObject.assignでできます。
Object.assign(hoge,fuga);
fugaの中のObjectなどを深くコピーしたい場合はこれでは不十分なので再帰的にコピーする必要があります。
$.Deferred()
Promiseで置き換える。
jQuery UI
jQuery UIのSortableを使ったプロダクトがあったので、これもjQueryを使わないバージョンに書き換えてみようと実装中なのですが、jQuery UIはよくできているので頑張って書き直す行為が単なる自己満足のような気がしてきました。それでも高機能なので不要な機能を外してシェイプアップできるというメリットはありそうです。jQueryを捨てた以上外部のモジュールに依存したくないというこだわりがなければ、目的に合致した代替ライブラリを探してきて使うのが楽な気がします。とりあえず自作頑張り中。