みなさん、カレンダーつくっていますか?
今どきは Google Calendar 埋め込んだりして済ませることも多いんでしょうけど、稀に自分で作らなければいけなくなることがありますよね?
無い方はさようなら。
で、カレンダーの作り方をいろいろ探してみたんですが、ちょっとまどろっこしいというか、条件分岐めっちゃつかっててスマートじゃないなって感じたんですよ。
ということで、ifに頼ることなくカレンダーを作ろうという試みです。
まずはコードを御覧ください
最初に結論というか、コードを載せてしまいます。
const date = new Date();
// 今月の最終日を取得する
date.setMonth(date.getMonth() + 1);
date.setDate(0);
const lastDate = date.getDate();
// 一ヶ月の日付を配列にする
const dateList = [...Array(lastDate).keys()].map(item => item + 1);
// 今月1日の曜日を取得する
date.setDate(1);
const firstDay = date.getDay();
// 月初より前の部分を作るための配列
const spacer = [...Array(firstDay)];
// カレンダーの最初から最後まであるリストを作る
calendarItems = [...spacer, ...dateList];
// カレンダーに何週分必要か計算
const weekCount = Math.ceil(calendarItems.length / 7);
// 空のカレンダーを作る
const $month = $('<div>')
const $week = $('<tr>');
for (let i = 0; i < 7; i++) {
$week.append('<td>');
}
for (let i = 0; i < weekCount; i++) {
$month.append($week.prop('outerHTML'), '\n');
}
// カレンダーに日付を記入
calendarItems.forEach((item, index) => {
$month.find('td').eq(index).html(item);
})
// カレンダーTABLEに反映させる
$('#calendar-body').html($month.html());
HTMLは下記の通り。
<div id="calendar">
<table>
<thead>
<tr>
<td>日</td><td>月</td><td>火</td><td>水</td><td>木</td><td>金</td><td>土</td>
</tr>
</thead>
<tbody id="calendar-body">
</tbody>
</table>
</div>
考え方
ここからはこのカレンダーに関する考え方を説明していきます。
なるべくわかりやすくするため、説明がコードの順序と異なります。ご了承ください。
カレンダーの枠が決まってるんだから
カレンダーって、枠が決まっているじゃないですか。
必ず1行あたりに7日間あって、それが並んでいるという。
ということは、日付を記載するHTML要素をリスト化して、1から最終日まで日付を入力していけばいいだけなんですよね。
そうすれば条件分岐無しで全然行けてしまいます。
ただ、問題が起こります。
はい、必ず初日が日曜日になってしまいます。
そこでどうするか。
日付リストの初日のインデックスが適切であればいいよね
ということで、初日のインデックスを適切にオフセットしてあげれば単純なループで済ませることができるんです。
でもどうやってオフセットしましょう。
そう、初日の曜日番号をとって、その数の要素を日付配列の最初に追加してあげるといいですね。
それが
const firstDay = date.getDay();
const spacer = [...Array(firstDay)];
ということです。
ここまでできたらあとはループをブンブン振り回してあげればカレンダーの完成です。
月曜日スタートにしたかったらどうすりゃいいの?
日付リストを calendarItems.shift()
してあげればいいんじゃないでしょうか。
というわけで
無事、条件分岐を使わずにカレンダーを作ることができました。
これさえつくってしまえば、月の切り替えとかはさほど苦労なくできるでしょう。
もし時間があれば月の切り替えとか、曜日ごとの色付け、祝日の色付けあたりについても投稿してみようかな。
では、これで。