JavaScriptでカレンダーを自作したら勉強になった

この記事は [JavaScript2 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/javascript_02) の14日目の記事です。

JSでカレンダーを表示したくてライブラリを探したのですが、要件に合うライブラリが見つからず、生のJSで書きました。
そしたら、意外とすんなりできたし、良い勉強になりました。

JS勉強中の人とか、とりあえず何か作ってみるときの練習におススメです。
カレンダーは日付処理を学んだり、機能追加がしやすいので課題としてはやりやすいと思いました。

せっかくなので、練習問題としてこんな機能をつけていくと勉強になるんじゃないかという要件を考えて実装してみたので紹介します。

冒頭で言っている要件とは違います。必要になったものはもうちょっと複雑な要件がありました。

# 考えた要件

- 空きが出るマスを埋める
- 数ヶ月分表示する
- ボタンで次の月や前の月の表示ができる
- 日付をクリックしたらイベントを発生させる

今回は実装しませんでしたが、こういう機能もあると良いと思います。

- 月曜日始まりに表示変更できる
- 表示する月の数を選べる
- 次の月や前の月で表示できる期間を制限する
- 祝日を反映する
- 当日の表示を変更する
- 特定の日付の表示を変更する（店舗の定休日のようなイメージ）

ライブラリを使っていると、こういうカスタマイズが難しかったりするのですが、自分で作っていればこういった機能の追加も比較的簡単にできるように思います。

# 実装

## まずは普通にカレンダーを作る

こんな感じのシンプルなカレンダーから始めます。

<p data-height="265" data-theme-id="0" data-slug-hash="LMZVJL" data-default-tab="js,result" data-user="kandai" data-pen-title="JavaScript Cakendar 1" class="codepen">See the Pen <a href="https://codepen.io/kandai/pen/LMZVJL/">JavaScript Cakendar 1</a> by daichi (<a href="https://codepen.io/kandai">@kandai</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

最初に作り始めた時、意外と簡単にできるもんだなと思いました。

## 空きが出るマスを埋める

先月の末日を取得して空きが出るマスを埋めてみます。

<p data-height="265" data-theme-id="0" data-slug-hash="dwXXgw" data-default-tab="js,result" data-user="kandai" data-pen-title="JavaScript Calendar 2" class="codepen">See the Pen <a href="https://codepen.io/kandai/pen/dwXXgw/">JavaScript Calendar 2</a> by daichi (<a href="https://codepen.io/kandai">@kandai</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 数ヶ月分表示する

設定値を持たせて表示できる月の数をコントロールしてみます。

<p data-height="265" data-theme-id="0" data-slug-hash="oJLzzr" data-default-tab="js,result" data-user="kandai" data-pen-title="JavaScript Calendar 3" class="codepen">See the Pen <a href="https://codepen.io/kandai/pen/oJLzzr/">JavaScript Calendar 3</a> by daichi (<a href="https://codepen.io/kandai">@kandai</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## ボタンで次の月や前の月の表示ができる

<p data-height="265" data-theme-id="0" data-slug-hash="roLMro" data-default-tab="js,result" data-user="kandai" data-pen-title="JavaScript Calendar 4" class="codepen">See the Pen <a href="https://codepen.io/kandai/pen/roLMro/">JavaScript Calendar 4</a> by daichi (<a href="https://codepen.io/kandai">@kandai</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 日付をクリックしたらイベントを発生させる

data属性で日付を持つようにして、イベントで取得できるようにしてみました。
DOMの生成をJSでやっているのでdocumentに対してイベントリスナーの登録が必要なのが少し注意が必要です。

```JavaScript
document.addEventListener("click", function(e) {
    if(e.target.classList.contains("calendar_td")) {
        alert('クリックした日付は' + e.target.dataset.date + 'です')
    }
})
```

`el.dataset` でdata属性の値が取れるの知らなかったです。簡単で良いですね！

見た目はちょっとアレですが、これでとりあえず完成です！

<p data-height="265" data-theme-id="0" data-slug-hash="xmOgyz" data-default-tab="js,result" data-user="kandai" data-pen-title="JavaScript Calendar 5" class="codepen">See the Pen <a href="https://codepen.io/kandai/pen/xmOgyz/">JavaScript Calendar 5</a> by daichi (<a href="https://codepen.io/kandai">@kandai</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 何を作ったら良いかわからない問題

自分の経験上、プログラミングスキルが上がった実感があったのは、自分で考えながら何かを作ってみることでした。
今もそんな偉そうなこと言えるスキルではないですが…

写経も良いですが、自分で考えるっていうのが重要なのかなと思います。

ただ、初心者の頃は何を作ったら良いかわからないという状況になりがちだと思うので、こういった練習問題みたいなものがあると良いと思います。

自分の場合は、電卓を作ったり要素をソートさせるとかが結構勉強になりました。
機会があれば、そういうのも記事にしてみます。