DOMおれおれAdvent Calendar 2015 – 24日目

最終日です。

2015-12-24

jQueryでやってる事をjQueryなしでやるとしたらどうするのってやつです。

$(selector) → document.querySelectorAll(selector)

これが一番基本ですね。

// jQuery
var $el = $('.foo');
console.log($el.length);
console.log($el[0]);

// DOM
var els = document.querySelectorAll('.foo');
console.log(els.length);
console.log(els[0]);

// DOM(一件のみ)
var el = document.querySelector('.foo');
console.log(el);

find() → querySelectorAll()

// jQuery
var $el = $('.foo');
console.log($el.find('.bar'));

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].querySelectorAll('.bar'));

each() → Array.prototype.forEach()

document.querySelectorAll() の結果には each() のように「全てに適用」する仕組みがありません。自前で for 文を書くか、配列の forEach() を利用するのが便利です。

// jQuery
var $el = $('.foo');
$el.each(function(index, el) {
    console.log(index, el);
});

// DOM
var els = document.querySelectorAll('.foo');
Array.prototype.forEach.call(els, function(el, index) {
    console.log(index, el);
});

コールバック関数に与えられる引数の順序が異なる点に気を付けてください。

on() → addEventListener()

// jQuery
var $el = $('.foo');
$el.on('click', function(event) {
    console.log(event.type);
});

// DOM
var els = document.querySelectorAll('.foo');
els[0].addEventListener('click', function(event) {
    console.log(event.type);
});

document.querySelectorAll() の結果は複数件になりますが、 addEventListener() は一件ずつしか適用できません。複数件を対象にイベント監視する場合は別項で紹介した Array.prototype.forEach() を使います。

以降も同じです。

デリゲートは event.target.matches(selector)

デリゲートっていう表現してたよね? $area.on('click', '.inner', listener) みたいなやつ。

// jQuery
var $el = $('.foo');
$el.on('click', '.bar', function(event) {
    console.log(event.type);
});

// DOM
var els = document.querySelectorAll('.foo');
els[0].addEventListener('click', function(event) {
    if (event.target.matches('.bar')) {
        console.log(event.type);
    }
});

off() → removeEventListener()

var callback = function(event) {
    console.log(event.type);
};

// jQuery
var $el = $('.foo');
$el.off('click', callback);

// DOM
var els = document.querySelectorAll('.foo');
els[0].removeEventListener('click', callback);

解除するコールバック関数のインスタンスが必要なのがちょっと面倒なところ。WeakMapなんか使えると管理が楽そうなんだけどなー。

trigger() → dispatchEvent()

割と面倒くさい。

// jQuery
var $el = $('.foo');
$el.trigger('mogu');

// DOM
var els = document.querySelectorAll('.foo');
var myEvent = document.createEvent('CustomEvent');
myEvent.initCustomEvent('mogu', true, true, null);
els[0].dispatchEvent(myEvent);

クラス操作 → classList

addClass() → classList.add()

// jQuery
var $el = $('.foo');
$el.addClass('is-active');

// DOM
var els = document.querySelectorAll('.foo');
els[0].classList.add('is-active');

removeClass() → classList.remove()

// jQuery
var $el = $('.foo');
$el.removeClass('is-active');

// DOM
var els = document.querySelectorAll('.foo');
els[0].classList.remove('is-active');

toggleClass() → classList.toggle()

// jQuery
var $el = $('.foo');
$el.toggleClass('is-active');

// DOM
var els = document.querySelectorAll('.foo');
els[0].classList.toggle('is-active');

hasClass() → classList.has()

// jQuery
var $el = $('.foo');
$el.hasClass('is-active');

// DOM
var els = document.querySelectorAll('.foo');
els[0].classList.contains('is-active');

css() → style 、 getComputedStyle()

数値 200 は設定してもCSS的に不正なので、単位付き "200px" で指定する必要があります。取得時も単位付きで得られます。

// jQuery
var $el = $('.foo');
$el.css({ color:'red, width:200 });
console.log($el.css('color'));

// DOM
var els = document.querySelectorAll('.foo');
els[0].style.color = 'red';
els[0].style.width = '200px';
console.log(getComputedStyle(els[0]).color);

attr() → setAttribute() 、 getAttribute()

// jQuery
var $el = $('.foo');
$el.attr('href', '#top');
console.log($el.attr('href'));

// DOM
var els = document.querySelectorAll('.foo');
els[0].setAttribute('href', '#top');
console.log(els[0].getAttribute('href'));

prop() → プロパティ

// jQuery
var $el = $('.foo');
$el.prop('href', '#top');
console.log($el.prop('href'));

// DOM
var els = document.querySelectorAll('.foo');
els[0].href = '#top';
console.log(els[0].href);

val() → value

// jQuery
var $el = $('.foo');
$el.val('I like it!');
console.log($el.val());

// DOM
var els = document.querySelectorAll('.foo');
els[0].value = 'I like it!';
console.log(els[0].value);

text() → textContent

// jQuery
var $el = $('.foo');
$el.text('<b>BOLD</b>');
console.log($el.text());

// DOM
var els = document.querySelectorAll('.foo');
els[0].textContent = '<b>BOLD</b>';
console.log(els[0].textContent);

html() → innerHTML

// jQuery
var $el = $('.foo');
$el.html('<b>BOLD</b>');
console.log($el.html());

// DOM
var els = document.querySelectorAll('.foo');
els[0].innerHTML = '<b>BOLD</b>';
console.log(els[0].innerHTML);

$(html) → innerHTML を使って自作

// jQuery
var $el = $('<div>');
console.log($el);

// DOM
var wrapper = document.createElement('div');
wrapper.innerHTML = '<div></div>';
var el = wrapper.firstChild;
console.log(el);

is() → matches()

// jQuery
var $el = $('.foo');
console.log($el.is('.foo'));

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].matches('.foo'));

parent() → parentNode

// jQuery
var $el = $('.foo');
console.log($el.parent());

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].parentNode);

closest() → 自作

// jQuery
var $el = $('.foo');
console.log($el.closest('.wrapper'));

// DOM
var els = document.querySelectorAll('.foo');
for (var closest=els[0]; closest; closest=closest.parentElement) {
    if (closest.matches('.wrapper')) {
        break;
    }
}
console.log(closest);

children() → children

// jQuery
var $el = $('.foo');
var $children = $el.children();
for (var i=0, l=$children.length; i<l; i++) {
    console.log($children[i]);
}

// DOM
var els = document.querySelectorAll('.foo');
var children = els[0].children;
for (var i=0, l=children.length; i<l; i++) {
    console.log(children[i]);
}

その他 firstElementChild 、 lastElementChild というのもあります。

prev() → previousElementSibling

// jQuery
var $el = $('.foo');
console.log($el.prev());

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].previousElementSibling);

next() → nextElementSibling

// jQuery
var $el = $('.foo');
console.log($el.next());

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].nextElementSibling);

filter() → Array.prototype.filter()

// jQuery
var $el = $('.foo');
console.log($el.filter('.bar'));

// DOM
var els = document.querySelectorAll('.foo');
var filtered = Array.prototype.filter.call(els, function(el) {
    return el.matches('.bar');
});
console.log(filtered);

append(el) → appendChild(el)

// jQuery
var $el = $('.foo');
var $child = $('.child');
$el.append($child);

// DOM
var els = document.querySelectorAll('.foo');
var children = document.querySelectorAll('.child');
els[0].appendChild(children[0]);

append(html) → innerHTML と appendChild(el) で自作

別項で紹介したやつの組み合わせです。

// jQuery
var $el = $('.foo');
$el.append('<b>BOLD</b>');

// DOM
var els = document.querySelectorAll('.foo');
var wrapper = document.createElement('div');
wrapper.innerHTML = '<b>BOLD</b>';
var child = wrapper.firstChild;
els[0].appendChild(child);

remove() → removeChild()

// jQuery
var $el = $('.foo');
$el.remove();

// DOM
var els = document.querySelectorAll('.foo');
els[0].parentNode.removeChild(els[0]);

width() → clientWidth

// jQuery
var $el = $('.foo');
$el.width(200);
console.log($el.width());

// DOM
var els = document.querySelectorAll('.foo');
els[0].style.width = '200px';
console.log(els[0].clientWidth);

outerWidth() → getBoundingClientRect()

// jQuery
var $el = $('.foo');
console.log($el.outerWidth());

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].getBoundingClientRect().width);

position() → offsetLeft 、 offsetTop

// jQuery
var $el = $('.foo');
var position = $el.position();
console.log(position.left, position.top);

// DOM
var els = document.querySelectorAll('.foo');
console.log(els[0].offsetLeft, els[0].offsetTop);

offset() → getBoundingClientRect()

// jQuery
var $el = $('.foo');
var offset = $el.offset();
console.log(offset.top);

// DOM
var els = document.querySelectorAll('.foo');
var offset = els[0].getBoundingClientRect();
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var top = scrollTop + offset.top;
console.log(top);

その他

DOMじゃないけど。

$.ajax() → XMLHttpRequest で頑張る

簡単な例だけ。

// jQuery
$.ajax({
    url: '/api/sugoi',
    data: { foo:123 }
}).done(function(data) {
    console.log(data);
});

// DOMじゃない
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function(event) {
    var data = JSON.parse(this.response);
  console.log(data);
});
xhr.open('GET', '/api/sugoi');
xhr.send(JSON.stringify({ foo:123 }));

おしまい

こんな感じの実装を、昨日分の記事の「基本戦略」と組み合わせると「おれおれjQuery」ができあがります。

というわけで、よければgQuery使ってみてください。