だれも聞いていないと思って歌え

dance as if no one’s watching, sing as if no one’s listening, and live everyday as if it were your last.

document.querySelector と document.querySelectorAll について

仕事でよく使っているけど、ちゃんと理解できていなかったので改めて調べてみました。

document.querySelector と document.querySelectorAll

document.querySelectordocument.querySelectorAll とは W3C によって定義された Selectors API の仕様です。 jQuery のようにセレクターを指定して、要素を取得できるメソッドです。

  • document.querySelector … 指定された CSS セレクタにマッチする文書中の最初の要素を返す。
  • document.querySelectorAll … 指定された CSS セレクタにマッチする文書中の要素の全てのリストを返す。

また、同様に文書中の要素を取得するメソッドとして下記があります。

  • document.getElementById … 指定されたIDを持つ要素を返す。
  • document.getElementsByClassName … 指定されたクラス名を持つ要素のリストを返す。

下記のHTML文書を例に、これらの違いについてまとめます。

<div class="news-box">
  <h2>NEWS</h2>
  <ul>
    <li class="news">news title 1</li>
    <li>topic title 2</li>
    <li class="news">news title 3</li>
  </ul>
</div>
<div class="articles-box">
  <h2>ARTICLES</h2>
  <ul>
    <li class="article">article list 1</li>
    <li>article list 2</li>
  </ul>
</div>

要素を一件だけ取得する

NEWSのnewsクラスではないリストの先頭の取得する場合、以下は同じ結果を取得することができます。 document.querySelector を使わない場合、一行で書く方法が分かりませんでした・・・

const elements = document.getElementsByClassName('news-box')[0].getElementsByTagName('li');
let elm = [];
for(var i = 0; i < elements.length; i++) {
  if(elements[i].className !== 'news') {
    elm.push(elements[i]);
  }
}
const element = elm[0];

> <li class="news">news title 1</li>
document.querySelector('.news-box li:not(.news)');

> <li class="news">news title 1</li>

ただし、単発のIDセレクタを指定する場合は document.getElementById の方が高速になります。

要素のリストを取得する

NEWSのnewsクラスのリストを取得する場合、以下は同じ結果を取得することができます。

document.getElementsByClassName('news-box')[0].getElementsByClassName('news');

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​]
document.querySelectorAll('.news-box .news');

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​]

こちらも、単発のクラス名を指定する場合は document.getElementsByClassName の方が高速になります。

引数に配列を指定する

ちなみに、引数には配列が指定可能で、 NEWSのnewsクラスのリスト と ARTICLESのarticleクラスのリスト のみを取得することができます。

document.querySelectorAll(['.news-box li.news', '.articles-box li:article']);

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​, <li class=​"article">​article list 1​</li>​]

CSS セレクタ

これを知っておくと便利だなと思ったものについてまとめました。

:not()

上記例で使っていますが、引数で指定したセレクターの要素を除外します。

document.querySelectorAll('.news-box li:not(.news)');

> [<li>​topic title 2​</li>​]

:first-child, :last-child

:first-child では最初の子要素を取得します。

document.querySelectorAll('.news-box li:first-child');

> [<li class=​"news">​news title 1​</li>​]

ただし、 document.querySelectorAll('.news-box li:not(.news):first-child')擬似クラスを複数組み合わせて使用することはできません(後述します。)

:last-child は最後の子要素を取得できます。

document.querySelectorAll('.news-box li:last-child');

> [<li class=​"news">​news title 3​</li>​]

:nth-child(), :nth-last-child()

引数には子要素のn番目、偶数(even)、奇数(odd)などが指定可能です。

document.querySelectorAll('.news-box li:nth-child(odd)');

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​]

:nth-last-child() も同様に、最後の子要素から逆向きに数えてn番目、偶数(even)、奇数(odd)と指定できます。

擬似クラスを複数組み合わせる

上にあげた例と同じになりますが、NEWSのnewsクラスを除外したリストの先頭を取得しようと以下のように記述します。

document.querySelectorAll('.news-box li:not(.news):first-child');

> []

しかし、取得対象の :first-child が除外対象の .news であるため空の配列が返ってきます。 :nth-child() を使うか document.querySelector で先頭の一件のみ取得する必要があります。

また、下記のように :not() を複数繋げて使用することも可能です。

document.querySelectorAll('li:not(.news):not(.article)');

> [<li>​topic title 2​</li>​, <li>​article list 2</li>​]

JavaScript勉強中です。 間違いありましたら指摘お願いします。

参考

Moment.jsで日付を扱う

とあるWebアプリを作ろうとしている中で、JavaScriptでもっと日付を楽に扱いたいと調べていて、 Moment.js というライブラリを知りました。

このMoment.jsについて紹介しているサイトは以前からあるので、最近できたものではないです。 比較的最近の Cybozuさんの記事 を読んだのをきっかけに使ってみることにしました。

現在の日付を扱う

Moment.js を参考にダウンロード、もしくはインストールをしてscriptタグで moment.min.js を読み込みます。

// momentオブジェクトの初期化
var today = moment();

// 日付の出力
console.log(today.format());    // -> 2016-06-05T19:37:38+09:00

// フォーマットを指定して出力
console.log(today.format('LLLL'));  // -> Sunday, June 5, 2016 7:54 PM

// 年月日をそれぞれ出力
console.log("year: ", today.year());    // -> year:  2016
console.log("month: ", today.month());  // -> month:  5
console.log("date: ", today.date());    // -> date:  5

moment().month() は、0から11の数字で帰ってくるため6月の場合は 5 と返ってきます。

日本語で出力する

上の手順と同様に、次は moment-with-locales.min.js をscriptタグで読み込みます。 Dateオブジェクトと比較して、この出力フォーマットの指定方法が一番楽だと感じました。

// locale指定
moment.locale('ja');

// momentオブジェクトの初期化
var today = moment();

// フォーマットを指定して出力
console.log(today.format('LLLL'));  // -> 2016年6月5日午後7時54分 日曜日

特定の日付を設定

日付の設定方法はいくつかあります。 moment() と括弧内で指定を行わなかった場合は現在日時で初期化が行われ、逆に括弧内で年月のみ指定された場合は1日で初期が行われます。そのため、上2つと下2つの結果が異なってきます。

// locale指定
moment.locale('ja');

console.log(moment(new Date(2016, 6 -1)).format('LL'));    // -> 2016年6月1日
console.log(moment({year:2016, month:6 -1}).format('LL')); // -> 2016年6月1日
console.log(moment().year(2016).month(6 -1).format('LL')); // -> 2016年6月5日
console.log(moment().set('year',2016).set('month',6 -1).format('LL')); // -> 2016年6月5日

最後に

すべての使い方を把握した訳ではないけれど、便利そうだなと思ったものをいくつか。 これら以外にも多くの関数が用意されている上に、タイムゾーンを扱うこともできるようです(タイムゾーンについては今回触れなかったので省略)。

// locale指定
moment.locale('ja');

// 指定した年月の日数を取得
console.log(moment(new Date(2016, 2 -1)).daysInMonth());  // -> 29

// 1月1日からの経過日数を取得
console.log(moment(new Date(2016, 6 -1, 5)).dayOfYear());  // -> 157

// 1月1日からの何週目か取得
console.log(moment(new Date(2016, 6 -1, 5)).weeksInYear());  // -> 53

X-UA-Compatibleについて調べてみた

今更ながらBootstrapの勉強を始めました。現在最新のBootstrap3です(4はαリリースのため)。 公式サイトを参考にしていて、Basic templateに書かれているmetaタグが見慣れないものだったので、調べてみました。

<meta http-equiv="X-UA-Compatible" content="IE=edge">

Getting started · Bootstrap

http-equiv

Mozillaの開発者向けの解説ページによると次のように記載されています。

プラグマディレクティブ、つまりどのように Web ページを提供するかについて、通常 Web サーバから与えられる情報です。 meta 要素 - HTML | MDN

では、 X-UA-Compatible は何かというと、Internet Explorerでどのバージョンのモードでレンダリングを行うか(ドキュメントモード)を指定することができるプラグマです。 IE=edge と指定することで、使用しているIEで利用可能なモードの中から、最高のモードを使用するように指示ができます。Internet Explorer 8 の場合はIE8モードに相当し、Internet Explorer 10 の場合はIE10モードに相当します。

ただし、 Internet Explorer 11 以降ではドキュメントモードの指定は推奨されず、Microsoft Edge では無視されるようになっているそうです。

新しい記事ではないですが、 X-UA-Compatible が何かを理解するためにこちらも参考にしました。