README-ja.md
フロントエンドの開発環境はめまぐるしく進化していて、最近のブラウザでは十分な質、量のDOM/BOM APIが実装されています。もうDOM操作やイベント処理のためにjQueryを覚える必要はありません。また、ReactやAngularそしてVueなどのフロントエンドライブラリの流行により、DOMを直接操作することはアンチパターンとなりました。jQueryはそれほど重要ではなくなったのです。このプロジェクトは、jQueryでの書き方の代わりとなるネイティブでの書き方(IE10以上)をまとめます。
classセレクタ、idセレクタ、属性セレクタのような主要セレクタはdocument.querySelectorもしくはdocument.querySelectorAllで代替できます。
jQueryのセレクタと比べて以下の違いがあります。
document.querySelectorはセレクタにマッチする最初のエレメントを返すdocument.querySelectorAllはセレクタにマッチする全てのエレメントのNodeListを返す。Array.prototype.slice.call(document.querySelectorAll(selector) || []);で配列に変換できる。[]を返すが、DOM APIはnullを返す。したがってNull Pointer Exceptionに注意する必要がある。もしくはdocument.querySelectorAll(selector) || []のように||を使ってデフォルト値を指定しておく。注意:
document.querySelectorとdocument.querySelectorAllはかなり遅いです。もし、パフォーマンスが必要ならdocument.getElementByIdやdocument.getElementsByClassName、document.getElementsByTagNameを使ってください。
1.0 <a name='1.0'></a> セレクタによる選択
// jQuery
$('selector');
// Native
document.querySelectorAll('selector');
1.1 <a name='1.1'></a> クラス名による選択
// jQuery
$('.class');
// Native
document.querySelectorAll('.class');
// or
document.getElementsByClassName('class');
1.2 <a name='1.2'></a> idによる選択
// jQuery
$('#id');
// Native
document.querySelector('#id');
// or
document.getElementById('id');
1.3 <a name='1.3'></a> 属性による選択
// jQuery
$('a[target=_blank]');
// Native
document.querySelectorAll('a[target=_blank]');
1.4 <a name='1.4'></a> 子孫要素の選択
// jQuery
$el.find('li');
// Native
el.querySelectorAll('li');
1.5 <a name='1.5'></a> 兄弟要素の選択
兄弟要素
// jQuery
$el.siblings();
// Native
Array.prototype.filter.call(el.parentNode.children, function(child) {
return child !== el;
});
直前の兄弟要素
// jQuery
$el.prev();
// Native
el.previousElementSibling;
直後の兄弟要素
// jQuery
$el.next();
// Native
el.nextElementSibling;
1.6 <a name='1.6'></a> 祖先要素の選択
指定要素からdocument方向に遡って走査し、セレクタにマッチする最初の祖先要素を返します。
// jQuery
$el.closest(selector);
// Native - 最近のブラウザのみ。IEでは動かない。
el.closest(selector);
// Native - IE10+
function closest(el, selector) {
const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
while (el) {
if (matchesSelector.call(el, selector)) {
return el;
} else {
el = el.parentElement;
}
}
return null;
}
1.7 <a name='1.7'></a> Parents Until
指定要素からセレクタにマッチする祖先要素までdocument方向に遡って走査し、フィルタにマッチする祖先要素を全て取得します。ただし、セレクタで指定された要素は含みません。
// jQuery
$el.parentsUntil(selector, filter);
// Native
function parentsUntil(el, selector, filter) {
const result = [];
const matchesSelector = el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector;
// parentから走査を開始する
el = el.parentElement;
while (el && !matchesSelector.call(el, selector)) {
if (!filter) {
result.push(el);
} else {
if (matchesSelector.call(el, filter)) {
result.push(el);
}
}
el = el.parentElement;
}
return result;
}
1.8 <a name='1.8'></a> フォーム
input/textarea
// jQuery
$('#my-input').val();
// Native
document.querySelector('#my-input').value;
.radio内でのe.currentTargetのインデックスを返す
// jQuery
$(e.currentTarget).index('.radio');
// Native
Array.prototype.indexOf.call(document.querySelectorAll('.radio'), e.currentTarget);
1.9 <a name='1.9'></a> iframeのコンテンツ
$('iframe').contents()はiframeのcontentDocumentを返します。
Iframe contents
// jQuery
$iframe.contents();
// Native
iframe.contentDocument;
Iframe Query
// jQuery
$iframe.contents().find('.css');
// Native
iframe.contentDocument.querySelectorAll('.css');
1.10 <a name='1.10'></a> bodyを取得する
// jQuery
$('body');
// Native
document.body;
1.11 <a name='1.11'></a> 属性の設定、取得
属性値を取得する
// jQuery
$el.attr('foo');
// Native
el.getAttribute('foo');
属性値を設定する
// jQuery, DOMを変化させずメモリ上で動作することに注意
$el.attr('foo', 'bar');
// Native
el.setAttribute('foo', 'bar');
data-属性を取得する
// jQuery
$el.data('foo');
// Native (`getAttribute`を使う)
el.getAttribute('data-foo');
// Native (IE11以上のサポートなら`dataset`を使ってもよい)
el.dataset['foo'];
2.1 <a name='2.1'></a> CSS
スタイルを取得する
// jQuery
$el.css("color");
// Native
// NOTE: 既知のバグ デフォルト値が'auto'の場合、値が指定されていなくても'auto'が返る
const win = el.ownerDocument.defaultView;
// nullは疑似要素でないことを示している
win.getComputedStyle(el, null).color;
スタイルを設定する
// jQuery
$el.css({ color: "#ff0011" });
// Native
el.style.color = '#ff0011';
スタイルを一括取得、一括設定する
複数のスタイルを一括で設定したいなら、oui-dom-utilsのsetStyles関数を参考にすると良いでしょう。
クラスを追加する
// jQuery
$el.addClass(className);
// Native
el.classList.add(className);
クラスを削除する
// jQuery
$el.removeClass(className);
// Native
el.classList.remove(className);
クラスの有無をチェックする
// jQuery
$el.hasClass(className);
// Native
el.classList.contains(className);
クラスの有無を切り替える
// jQuery
$el.toggleClass(className);
// Native
el.classList.toggle(className);
2.2 <a name='2.2'></a> 横幅と高さ
横幅(width)と高さ(height)の書き方はほぼ同じなので、高さ(height)の例のみを示します。
ウィンドウの高さ
// window height
$(window).height();
// jQueryのようにスクロールバーを除いた高さ
window.document.documentElement.clientHeight;
// スクロールバーを含めるなら
window.innerHeight;
ドキュメントの高さ
// jQuery
$(document).height();
// Native
document.documentElement.scrollHeight;
エレメントの高さ
// jQuery
$el.height();
// Native
function getHeight(el) {
const styles = window.getComputedStyle(el);
const height = el.offsetHeight;
const borderTopWidth = parseFloat(styles.borderTopWidth);
const borderBottomWidth = parseFloat(styles.borderBottomWidth);
const paddingTop = parseFloat(styles.paddingTop);
const paddingBottom = parseFloat(styles.paddingBottom);
return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom;
}
// integerで取得(`border-box`の時は`height - border`が、`content-box`の時は`height + padding`が返る)
el.clientHeight;
// decimalで取得(`border-box`の時は`height`が、`content-box`の時は`height + padding + border`が返る)
el.getBoundingClientRect().height;
2.3 <a name='2.3'></a> PositionとOffset
Position
offset parentを起点として、エレメントの座標を取得する。
// jQuery
$el.position();
// Native
{ left: el.offsetLeft, top: el.offsetTop }
Offset
documentを起点として、エレメントの座標を取得する。
// jQuery
$el.offset();
// Native
function getOffset (el) {
const box = el.getBoundingClientRect();
return {
top: box.top + window.pageYOffset - document.documentElement.clientTop,
left: box.left + window.pageXOffset - document.documentElement.clientLeft
}
}
2.4 <a name='2.4'></a> スクロール位置
縦スクロールバーの位置を取得する。
// jQuery
$(window).scrollTop();
// Native
(document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
3.1 <a name='3.1'></a> Remove
DOMからエレメントを削除する。
// jQuery
$el.remove();
// Native
el.parentNode.removeChild(el);
3.2 <a name='3.2'></a> Text
テキストを取得する
子孫エレメントも含めた全テキスト内容を取得する。
// jQuery
$el.text();
// Native
el.textContent;
テキストを設定する
エレメントのコンテントを指定されたテキストに設定する。
// jQuery
$el.text(string);
// Native
el.textContent = string;
3.3 <a name='3.3'></a> HTML
HTMLを取得する
// jQuery
$el.html();
// Native
el.innerHTML;
HTMLを設定する
// jQuery
$el.html(htmlString);
// Native
el.innerHTML = htmlString;
3.4 <a name='3.4'></a> Append
最後の子要素としてエレメントを追加する。
// jQuery
$el.append("<div id='container'>hello</div>");
// Native
el.insertAdjacentHTML("beforeend","<div id='container'>hello</div>");
3.5 <a name='3.5'></a> Prepend
最初の子要素としてエレメントを追加する。
// jQuery
$el.prepend("<div id='container'>hello</div>");
// Native
el.insertAdjacentHTML("afterbegin","<div id='container'>hello</div>");
3.6 <a name='3.6'></a> insertBefore
指定要素の後ろに新しいノードを追加する。
// jQuery
$newEl.insertBefore(queryString);
// Native
const target = document.querySelector(queryString);
target.parentNode.insertBefore(newEl, target);
3.7 <a name='3.7'></a> insertAfter
指定要素の前に新しいノードを追加する。
// jQuery
$newEl.insertAfter(queryString);
// Native
const target = document.querySelector(queryString);
target.parentNode.insertBefore(newEl, target.nextSibling);
3.8 <a name='3.8'></a> is
セレクタにマッチするならtrueを返す。
// is関数は複数エレメントや関数にも対応するが、matches関数は単一エレメントのみに使える
$el.is(selector);
// Native
el.matches(selector);
3.9 <a name='3.9'></a> clone
エレメントのディープコピーを生成する。
// jQuery
$el.clone();
// Native
el.cloneNode();
// パラメータには`true`が渡され、深い複製を生成します。
// 浅い複製を生成するには、`false`を渡します。
3.10 <a name='3.10'></a> empty
全ての子ノードを削除する。
// jQuery
$el.empty();
// Native
el.innerHTML = '';
3.11 <a name='3.11'></a> wrap
エレメントを指定のHTMLで囲む。
// jQuery
$('.inner').wrap('<div class="wrapper"></div>');
// Native
Array.prototype.slice.call(document.querySelectorAll('.inner')).forEach(function(el){
var wrapper = document.createElement('div');
wrapper.className = 'wrapper';
el.parentNode.insertBefore(wrapper, el);
el.parentNode.removeChild(el);
wrapper.appendChild(el);
});
3.12 <a name='3.12'></a> unwrap
セレクタにマッチしたエレメントの親要素をDOMから削除する。マッチしたエレメント自体は残す。
// jQuery
$('.inner').unwrap();
// Native
Array.prototype.slice.call(document.querySelectorAll('.inner')).forEach(function(el){
Array.prototype.slice.call(el.childNodes).forEach(function(child){
el.parentNode.insertBefore(child, el);
});
el.parentNode.removeChild(el);
});
3.13 <a name='3.13'></a> replaceWith
セレクタにマッチしたエレメントの内容を与えられた内容に置き換える。
// jQuery
$('.inner').replaceWith('<div class="outer"></div>');
// Native
Array.prototype.slice.call(document.querySelectorAll('.inner')).forEach(function(el){
var outer = document.createElement('div');
outer.className = 'outer';
el.parentNode.insertBefore(outer, el);
el.parentNode.removeChild(el);
});
Fetch APIはXMLHttpRequestを置き換える新たな規格です。ChromeとFirefoxで動きます。レガシーなブラウザでもpolyfillを使えます。
IE9以上ならgithub/fetch、IE8以上ならfetch-ie8、jsonpを利用したいならfetch-jsonpを試してみてください。
4.1 <a name='4.1'></a> マッチしたエレメントをサーバから取得したHTMLに置き換える。
// jQuery
$(selector).load(url, completeCallback)
// Native
fetch(url).then(data => data.text()).then(data => {
document.querySelector(selector).innerHTML = data
}).then(completeCallback)
名前空間(namespace)と委譲(delegation)を利用した完全な代替手段が必要なら、 https://github.com/oneuijs/oui-dom-events を参照してください。
5.0 <a name='5.0'></a> ドキュメントが読み込まれたときの動作(DOMContentLoaded)
// jQuery
$(document).ready(eventHandler);
// Native
// DOMContentLoadedがすでに完了していないか確認する
if (document.readyState !== 'loading') {
eventHandler();
} else {
document.addEventListener('DOMContentLoaded', eventHandler);
}
5.1 <a name='5.1'></a> イベントをバインドする(on)
// jQuery
$el.on(eventName, eventHandler);
// Native
el.addEventListener(eventName, eventHandler);
5.2 <a name='5.2'></a> イベントをアンバインドする(off)
// jQuery
$el.off(eventName, eventHandler);
// Native
el.removeEventListener(eventName, eventHandler);
5.3 <a name='5.3'></a> イベントを発火させる(trigger)
// jQuery
$(el).trigger('custom-event', {key1: 'data'});
// Native
if (window.CustomEvent) {
const event = new CustomEvent('custom-event', {detail: {key1: 'data'}});
} else {
const event = document.createEvent('CustomEvent');
event.initCustomEvent('custom-event', true, true, {key1: 'data'});
}
el.dispatchEvent(event);
殆どのユーティリティ関数はネイティブのAPIで置き換えることができます。表記の一貫性やパフォーマンスを重視した他のライブラリを使う選択肢もあります。lodashがおすすめです。
6.1 <a name='6.1'></a> 基本的なユーティリティ関数
配列かどうか判定する。
// jQuery
$.isArray(array);
// Native
Array.isArray(array);
windowかどうか判定する。
// jQuery
$.isWindow(obj);
// Native
function isWindow(obj) {
return obj != null && obj === obj.window;
}
配列の中で、指定された値が最初に現れたインデックスを返す。(見つからなければ-1を返す)。
// jQuery
$.inArray(item, array);
// Native
Array.indexOf(item);
数値かどうか判定する。
typeofを使ってください。ライブラリを使う場合、typeofは正確でない場合があります。
// jQuery
$.isNumeric(item);
// Native
function isNumeric(item) {
return typeof item === 'number';
}
JavaScript関数オブジェクトかどうか判定する。
// jQuery
$.isFunction(item);
// Native
function isFunction(item) {
return typeof item === 'function';
}
空のオブジェクトである(列挙できる要素がない)か判定する。
// jQuery
$.isEmptyObject(obj);
// Native
function isEmptyObject(obj) {
for (let key in obj) {
return false;
}
return true;
}
{}もしくはnew Objectで生成されたオブジェクトであるか判定する。
// jQuery
$.isPlainObject(obj);
// Native
function isPlainObject(obj) {
if (typeof (obj) !== 'object' || obj.nodeType || obj != null && obj === obj.window) {
return false;
}
if (obj.constructor &&
!{}.hasOwnProperty.call(obj.constructor.prototype, 'isPrototypeOf')) {
return false;
}
return true;
}
二つ以上のオブジェクトをマージする。
object.assignはECMAScript6のAPIですが、polyfillも利用できます。
// jQuery
$.extend({}, defaultOpts, opts);
// Native
Object.assign({}, defaultOpts, opts);
前後の空白を除去する。
// jQuery
$.trim(string);
// Native
string.trim();
配列やオブジェクトを新しい配列に変換する。
// jQuery
$.map(array, function(value, index) {
});
// Native
array.map(function(value, index) {
});
配列やオブジェクトに対して繰り返し処理を行う。
// jQuery
$.each(array, function(value, index) {
});
// Native
array.forEach(function(value, index) {
});
フィルター関数に合致したエレメントだけを返す。
// jQuery
$.grep(array, function(value, index) {
});
// Native
array.filter(function(value, index) {
});
JavaScript「クラス」名を判定します。
// jQuery
$.type(obj);
// Native
Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
二つの配列をマージする。
// jQuery
$.merge(array1, array2);
// Native
// 重複した要素は削除されない
function merge() {
return Array.prototype.concat.apply([], arguments)
}
現在の時刻を返す。
// jQuery
$.now();
// Native
Date.now();
関数内で実行されるthisを任意のオブジェクトに変更する。
// jQuery
$.proxy(fn, context);
// Native
fn.bind(context);
配列形式のオブジェクトを配列に変換する。
// jQuery
$.makeArray(arrayLike);
// Native
Array.prototype.slice.call(arrayLike);
// ES6なら
Array.from(arrayLike);
6.2 <a name='6.2'></a> contains
ある要素が他の要素の子孫であるか判定する。
// jQuery
$.contains(el, child);
// Native
el !== child && el.contains(child);
6.3 <a name='6.3'></a> globaleval
JavaScriptコードをグローバル空間で実行する。
// jQuery
$.globaleval(code);
// Native
function Globaleval(code) {
let script = document.createElement('script');
script.text = code;
document.head.appendChild(script).parentNode.removeChild(script);
}
// evalはcurrentコンテキストで実行される。$.globalevalのコンテキストはグローバルである。
eval(code);
6.4 <a name='6.4'></a> parse
文字列をDOM nodeの配列として返します。
// jQuery
$.parseHTML(htmlString);
// Native
function parseHTML(string) {
const tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = string;
return tmp.body.children;
}
JSON文字列をJavaScriptに変換します。
// jQuery
$.parseJSON(str);
// Native
JSON.parse(str);
promiseは非同期処理の最終的な処理結果を表します。jQueryにはpromiseを扱うための独自の方法があります。ネイティブのJavaScriptではPromises/A+規格に則り、薄く、最小限のAPIを実装しています。
7.1 <a name='7.1'></a> done, fail, always
doneはpromiseが成功(resolved)したとき、fallは失敗(rejected)したとき、alwaysはどちらの場合も呼び出されます。
// jQuery
$promise.done(doneCallback).fail(failCallback).always(alwaysCallback)
// Native
promise.then(doneCallback, failCallback).then(alwaysCallback, alwaysCallback)
7.2 <a name='7.2'></a> when
whenは複数のpromiseを扱うときに使います。すべてのpromiseの結果が返ったときに成功となります(失敗が含まれてても成功となります)。
// jQuery
$.when($promise1, $promise2).done((promise1Result, promise2Result) => {})
// Native
Promise.all([$promise1, $promise2]).then([promise1Result, promise2Result] => {});
7.3 <a name='7.3'></a> Deferred
Deferredはpromiseを作成する方法の一つです。
// jQuery
function asyncFunc() {
var d = new $.Deferred();
setTimeout(function() {
if(true) {
d.resolve('some_value_compute_asynchronously');
} else {
d.reject('failed');
}
}, 1000);
return d.promise();
}
// Native
function asyncFunc() {
return new Promise((resolve, reject) => {
setTimeout(function() {
if (true) {
resolve('some_value_compute_asynchronously');
} else {
reject('failed');
}
}, 1000);
});
}
// Deferred way
function defer() {
let resolve, reject;
let promise = new Promise(function() {
resolve = arguments[0];
reject = arguments[1];
});
return { resolve, reject, promise };
}
function asyncFunc() {
var d = defer();
setTimeout(function() {
if(true) {
d.resolve('some_value_compute_asynchronously');
} else {
d.reject('failed');
}
}, 1000);
return d.promise;
}
8.1 <a name='8.1'></a> show、hide
// jQuery
$el.show();
$el.hide();
// Native
// show関数の詳細を見たければ次のURLを参照してください
// https://github.com/oneuijs/oui-dom-utils/blob/master/src/index.js#L363
el.style.display = ''|'inline'|'inline-block'|'inline-table'|'block';
el.style.display = 'none';
8.2 <a name='8.2'></a> toggle
エレメントが表示されていないなら表示し、表示されているなら非表示にします。
// jQuery
$el.toggle();
// Native
if (el.ownerDocument.defaultView.getComputedStyle(el, null).display === 'none') {
el.style.display = ''|'inline'|'inline-block'|'inline-table'|'block';
}
else {
el.style.display = 'none';
}
8.3 <a name='8.3'></a> fadeIn、fadeOut
// jQuery
$el.fadeIn(3000);
$el.fadeOut(3000);
// Native
el.style.transition = 'opacity 3s';
// fadeIn
el.style.opacity = '1';
// fadeOut
el.style.opacity = '0';
8.4 <a name='8.4'></a> fadeTo
エレメントのopacityを調整してください。
// jQuery
$el.fadeTo('slow',0.15);
// Native
el.style.transition = 'opacity 3s'; // 'slow'は3秒だということにしている
el.style.opacity = '0.15';
8.5 <a name='8.5'></a> fadeToggle
フェードイン・フェードアウトを伴ってエレメントの表示・非表示を切り替えます。
// jQuery
$el.fadeToggle();
// Native
el.style.transition = 'opacity 3s';
let { opacity } = el.ownerDocument.defaultView.getComputedStyle(el, null);
if (opacity === '1') {
el.style.opacity = '0';
}
else {
el.style.opacity = '1';
}
8.6 <a name='8.6'></a> スライドアップ、スライドダウン
// jQuery
$el.slideUp();
$el.slideDown();
// Native
let originHeight = '100px';
el.style.transition = 'height 3s';
// slideUp
el.style.height = '0px';
// slideDown
el.style.height = originHeight;
8.7 <a name='8.7'></a> slideToggle
スライドを伴って、エレメントの表示・非表示を切り替えます。
// jQuery
$el.slideToggle();
// Native
let originHeight = '100px';
el.style.transition = 'height 3s';
let { height } = el.ownerDocument.defaultView.getComputedStyle(el, null);
if (parseInt(height, 10) === 0) {
el.style.height = originHeight;
}
else {
el.style.height = '0px';
}
8.8 <a name='8.8'></a> animate
CSSプロパティで定義されたアニメーションを表示します。
// jQuery
$el.animate({params}, speed);
// Native
el.style.transition = 'all' + speed;
Object.keys(params).forEach(function(key) {
el.style[key] = params[key];
})
| Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | 6.1+ ✔ |
MIT