jQueryの$(ʼ#idʼ)や$(ʼ.classʼ)などのDOM取得を生JavaScriptで実装する脱jQuery
jQueryを使わない生のJavaScriptでDOM取得をしてみます。取得だけではなく、注意すべき点がいくつかあるので紹介します。
DOM取得関数
ID名での取得
<ul id="list"></ul>
var id = document.getElementById('list');
// => <ul id="list"></ul>
マッチした1つの要素Elementを返します。マッチしなければ null
を返します。
クラス名での取得
<ul>
<li class="list-item"></li>
<li class="list-item"></li>
<li class="list-item"></li>
</ul>
var classes = document.getElementsByClassName('list-item');
// => (3) [li.list-item, li.list-item, li.list-item]
マッチする全ての要素リストHTMLCollectionを返します。マッチしなければ空のHTMLCollectionを返します。
タグ名での取得
<ul>
<li></li>
<li></li>
<li></li>
</ul>
var tags = document.getElementsByTagName('li');
// => (3) [li, li, li]
マッチする全ての要素リストHTMLCollectionを返します。マッチしなければ空のHTMLCollectionを返します。
CSSセレクタでの取得
<ul>
<li class="list-item">1</li>
<li class="list-item">2</li>
<li class="list-item">3</li>
</ul>
var node = document.querySelector('.list-item');
// => <li class="list-item">1</li>
var node = document.querySelector('li');
// => <li class="list-item">1</li>
var nodes = document.querySelectorAll('.list-item');
// => (3) [li.list-item, li.list-item, li.list-item]
querySelector()
はマッチする最初の要素のみのElementを返し、マッチしなければ null
を返します。querySelectorAll()
はマッチする全ての要素リストNodeListを返し、マッチしなければ空のNodeListを返します。
getElementsBy*()
と querySelectorAll()
の違い
HTMLCollectionは動的で、NodeListは静的だというのが大きな違いです。
<ul class="list">
<li class="list-item">1</li>
<li class="list-item">2</li>
<li class="list-item">3</li>
</ul>
var dynamicNode = document.getElementsByClassName('list-item'),
staticNode = document.querySelectorAll('.list-item');
console.log(dynamicNode.length); // 3
console.log(staticNode.length); // 3
このようなHTMLがあったとき、両方とも 3
となります。
var node = document.createElement('li');
node.className = 'list-item';
node.textContent = '4';
document.getElementsByClassName('list')[0].appendChild(node);
console.log(dynamicNode.length); // 4
console.log(staticNode.length); // 3
そのあとに <li class="list-item">4</li>
を追加してみます。その後、もう一度 length
を確認すると、getElementsBy*()
は 4
、querySelectorAll()
は 3
と表示されます。動的な方は要素を追加すると更新されるのに対し、静的な方は更新されません。
配列の関数を使うとき
HTMLCollectionやNodeListはArray-Like Object(配列のようなオブジェクト)といって、配列ではありません。そのため、DOMを取得した後に forEach()
で走査したい場合に問題が起こります。
var arrayLikeObject = {0: 'a', 1: 'b', 2: 'c', length: 3};
Array-Like Objectとは length
プロパティを持ち、数字の添え字でアクセス可能なオブジェクトのことです。実際には、いくつかのメソッドを持っている場合があります。
Array.prototype.slice.call(document.querySelectorAll('.list-item')).forEach(function(node) {
console.log(node);
});
Array.prototype.slice.call()
でArray-Like Objectを配列に変換します。配列であれば forEach()
関数が使えます。
Array.prototype.forEach.call(document.querySelectorAll('.list-item'), function(node) {
console.log(node);
});
配列の関数はジェネリックなので直接Array-Like Objectに対して call()
することができます。なので、このように書くこともできます。
ES6の Array.from()
Array.from(document.querySelectorAll('.list-item'), function(node) {
console.log(node);
});
ES6の Array.from()
を使えばもっと簡単に書けます。
// Array.from非対応
if (!Array.from) {
Array.from = function(node, callback) {
Array.prototype.slice.call(node).forEach(callback);
};
}
Array.from(document.querySelectorAll('.list-item'), function(node) {
console.log(node);
});
しかし、IEには対応していないので、簡単なPolyfillを書いてみました。検索すればより強固なPolyfillが見つかります。
CSS本執筆しました!!!
CSS本出します!1/29発売予定
— たかもそ@CSS本1/29発売!! (@takamosoo) 2018年12月31日
自分がCSS学びたての頃にもっとはやく知りたかったテクニックを載せています。CSSの基礎知識について解説していないので、中級者〜向けとなります。CSS入門書を読んではみたものの、思い通りに作れない人にオススメです。
よろしくお願いします。https://t.co/fkz1dM03Pj pic.twitter.com/suYyaPqwIs