JavaScriptでライブラリなどを使わずにカレンダーを作る機会があったのでメモ。
サンプルコード
1月分のカレンダーを作ろうと思った場合、(1)その月の初日の曜日 と (2)その月の末日 の2点が取得できれば実装できます。
まずは指定した年月のカレンダー情報をconsoleに出すようにしてみます。
JavaScript
// 年月の指定
var year = 2018;
var month = 5;
window.onload = function() {
console.log(get_month_calendar(year, month));
}
/**
* 指定した年月のカレンダー情報を返す
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function get_month_calendar(year, month) {
var firstDate = new Date(year, (month - 1), 1); // 指定した年月の初日の情報
var lastDay = new Date(year, (firstDate.getMonth() + 1), 0).getDate(); // 指定した年月の末日
var weekday = firstDate.getDay(); // 指定した年月の初日の曜日
var calendarData = []; // カレンダーの情報を格納
var weekdayCount = weekday; // 曜日のカウント用
for (var i = 0; i < lastDay; i++) {
calendarData[i] = {
day: i + 1,
weekday: weekdayCount
}
// 曜日のカウントが6(土曜日)まできたら0(日曜日)に戻す
if(weekdayCount >= 6) {
weekdayCount = 0;
} else {
weekdayCount++;
}
}
return calendarData;
}
カレンダーの情報を取得するデモページ
get_month_calendar()がカレンダーに使用する1月分の情報を返す関数で、引数で年と月を指定するようにしています。
次に、実際に指定した年月のカレンダーを表示してみます。
HTML
<div id="calendar"></div>
JavaScript
// 年月の指定
var year = 2018;
var month = 5;
window.onload = function() {
var data = generate_month_calendar(year, month);
document.getElementById('calendar').appendChild(data);
}
/**
* 指定した年月のカレンダー要素を生成して返す
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function generate_month_calendar(year, month) {
var weekdayData = ['日', '月', '火', '水', '木', '金', '土'];
// カレンダーの情報を取得
var calendarData = get_month_calendar(year, month);
var i = calendarData[0]['weekday']; // 初日の曜日を取得
// カレンダー上の初日より前を埋める
while(i > 0) {
i--;
calendarData.unshift({
day: '',
weekday: i
});
}
var i = calendarData[calendarData.length - 1]['weekday']; // 末日の曜日を取得
// カレンダー上の末日より後を埋める
while(i < 6) {
i++;
calendarData.push({
day: '',
weekday: i
});
}
// カレンダーの要素を生成
var cTable = document.createElement('table');
cTable.className = 'calendar-table';
var insertData = '';
// 曜日部分の生成
insertData += '<thead>';
insertData += '<tr>';
for (var i = 0; i < weekdayData.length; i++) {
insertData += '<th>';
insertData += weekdayData[i];
insertData += '</th>';
}
insertData += '</tr>';
insertData += '</thead>';
// 日付部分の生成
insertData += '<tbody>';
for (var i = 0; i < calendarData.length; i++) {
if(calendarData[i]['weekday'] <= 0) {
insertData += '<tr>';
}
insertData += '<td>';
insertData += calendarData[i]['day'];
insertData += '</td>';
if(calendarData[i]['weekday'] >= 6) {
insertData += '</tr>';
}
}
insertData += '</tbody>';
cTable.innerHTML = insertData;
return cTable;
}
/**
* 指定した年月のカレンダー情報を返す
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function get_month_calendar(year, month) {
var firstDate = new Date(year, (month - 1), 1); // 指定した年月の初日の情報
var lastDay = new Date(year, (firstDate.getMonth() + 1), 0).getDate(); // 指定した年月の末日
var weekday = firstDate.getDay(); // 指定した年月の初日の曜日
var calendarData = []; // カレンダーの情報を格納
var weekdayCount = weekday; // 曜日のカウント用
for (var i = 0; i < lastDay; i++) {
calendarData[i] = {
day: i + 1,
weekday: weekdayCount
}
// 曜日のカウントが6(土曜日)まできたら0(日曜日)に戻す
if(weekdayCount >= 6) {
weekdayCount = 0;
} else {
weekdayCount++;
}
}
return calendarData;
}
これで指定した年月のカレンダーの表示ができるようになりました。
カレンダーのデモページ
先ほどのget_month_calendar()の中身はそのままで、取得した情報を使ってgenerate_month_calendar()で要素を生成しています。
カレンダーのベースは作成できたので、最後に少しアレンジをしてみます。
デフォルトで表示するカレンダーを現在の年月にして、年月の表示・前月と翌月への移動の機能を追加してみます。
HTMLは先ほどと同じです。
JavaScript
window.onload = function() {
// 現在の年月の取得
var current = new Date();
var year = current.getFullYear();
var month = current.getMonth() + 1;
// カレンダーの表示
var wrapper = document.getElementById('calendar');
add_calendar(wrapper, year, month);
}
/**
* 指定した年月のカレンダーを表示する
* @param {object} wrapper - カレンダーを追加する親要素
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function add_calendar(wrapper, year, month) {
// 現在カレンダーが追加されている場合は一旦削除する
wrapper.textContent = null;
// カレンダーに表示する内容を取得
var headData = generate_calendar_header(wrapper, year, month);
var bodyData = generate_month_calendar(year, month);
// カレンダーの要素を追加
wrapper.appendChild(headData);
wrapper.appendChild(bodyData);
}
/**
* 指定した年月のカレンダーのヘッダー要素を生成して返す
* @param {object} wrapper - カレンダーを追加する親要素
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function generate_calendar_header(wrapper, year, month) {
// 前月と翌月を取得
var nextMonth = new Date(year, (month - 1));
nextMonth.setMonth(nextMonth.getMonth() + 1);
var prevMonth = new Date(year, (month - 1));
prevMonth.setMonth(prevMonth.getMonth() - 1);
// ヘッダー要素
var cHeader = document.createElement('div');
cHeader.className = 'calendar-header';
// 見出しの追加
var cTitle = document.createElement('div');
cTitle.className = 'calendar-header__title';
var cTitleText = document.createTextNode(year + '年' + month + '月');
cTitle.appendChild(cTitleText);
cHeader.appendChild(cTitle);
// 前月ボタンの追加
var cPrev = document.createElement('button');
cPrev.className = 'calendar-header__prev';
var cPrevText = document.createTextNode('prev');
cPrev.appendChild(cPrevText);
// 前月ボタンをクリックした時のイベント設定
cPrev.addEventListener('click', function() {
add_calendar(wrapper, prevMonth.getFullYear(), (prevMonth.getMonth() + 1));
}, false);
cHeader.appendChild(cPrev);
// 翌月ボタンの追加
var cNext = document.createElement('button');
cNext.className = 'calendar-header__next';
var cNextText = document.createTextNode('next');
cNext.appendChild(cNextText);
// 翌月ボタンをクリックした時のイベント設定
cNext.addEventListener('click', function() {
add_calendar(wrapper, nextMonth.getFullYear(), (nextMonth.getMonth() + 1));
}, false);
cHeader.appendChild(cNext);
return cHeader;
}
/**
* 指定した年月のカレンダー要素を生成して返す
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function generate_month_calendar(year, month) {
var weekdayData = ['日', '月', '火', '水', '木', '金', '土'];
// カレンダーの情報を取得
var calendarData = get_month_calendar(year, month);
var i = calendarData[0]['weekday']; // 初日の曜日を取得
// カレンダー上の初日より前を埋める
while(i > 0) {
i--;
calendarData.unshift({
day: '',
weekday: i
});
}
var i = calendarData[calendarData.length - 1]['weekday']; // 末日の曜日を取得
// カレンダー上の末日より後を埋める
while(i < 6) {
i++;
calendarData.push({
day: '',
weekday: i
});
}
// カレンダーの要素を生成
var cTable = document.createElement('table');
cTable.className = 'calendar-table';
var insertData = '';
// 曜日部分の生成
insertData += '<thead>';
insertData += '<tr>';
for (var i = 0; i < weekdayData.length; i++) {
insertData += '<th>';
insertData += weekdayData[i];
insertData += '</th>';
}
insertData += '</tr>';
insertData += '</thead>';
// 日付部分の生成
insertData += '<tbody>';
for (var i = 0; i < calendarData.length; i++) {
if(calendarData[i]['weekday'] <= 0) {
insertData += '<tr>';
}
insertData += '<td>';
insertData += calendarData[i]['day'];
insertData += '</td>';
if(calendarData[i]['weekday'] >= 6) {
insertData += '</tr>';
}
}
insertData += '</tbody>';
cTable.innerHTML = insertData;
return cTable;
}
/**
* 指定した年月のカレンダー情報を返す
* @param {number} year - 年の指定
* @param {number} month - 月の指定
*/
function get_month_calendar(year, month) {
var firstDate = new Date(year, (month - 1), 1); // 指定した年月の初日の情報
var lastDay = new Date(year, (firstDate.getMonth() + 1), 0).getDate(); // 指定した年月の末日
var weekday = firstDate.getDay(); // 指定した年月の初日の曜日
var calendarData = []; // カレンダーの情報を格納
var weekdayCount = weekday; // 曜日のカウント用
for (var i = 0; i < lastDay; i++) {
calendarData[i] = {
day: i + 1,
weekday: weekdayCount
}
// 曜日のカウントが6(土曜日)まできたら0(日曜日)に戻す
if(weekdayCount >= 6) {
weekdayCount = 0;
} else {
weekdayCount++;
}
}
return calendarData;
}
カレンダーのデモページ2
add_calendar()とgenerate_calendar_header()という関数を追加しています。
今回は簡単にカレンダーのベースを作っただけですが、以前投稿したJavaScriptで祝日を取得するを組み合わせると祝日を表示させたりできるかもしれません。
初めまして。
専門学校にてプログラミングを勉強中の者です。
課題制作において、このページのコードを参考にさせていただきました。
今回は機能の追加について質問させていただきたく、コメントを書くに至りました。
「今日の付けを取得し、該当するカレンダーの日にちの色を変える」
という機能を追加したいのですが、中々うまくいきません。
この機能を追加するにはどうすればいいでしょうか?
お手数なのは承知の上ですが、
よろしければご教授していただけると大変助かります。
仲井優さん
コメントありがとうございます。
以下のような形で問題ないでしょうか。
https://cly7796.net/blog/sample/create-a-calendar-with-javascript/index5.html
jsの追加点は以下になります。
(1) 89~93行目で今日の年月日の取得
(2) 136~141行目で今日の日付の場合にclassを追加
初めまして、
最近jvascriptを勉強し始めて何か作品を作りたいと思いこのブログを参考にさせてもらっています。
今回はコードについて疑問に思ったことがありましたのでコメントさせてもらいます。
実際に指定した年月のカレンダーのjavascriptのコード6のvarの値にgenerate_month_calendar(year, month)が割り当てられていますがこれはどのような役割をするのでしょうか?
さらにこのgenerate_month_calendar(year, month)が15のfunctionの名前に使用されていますがなぜ変数名を使用しないのでしょうか?
Riyoさん
コメントありがとうございます。
質問いただいている6行目と15行目で行っている処理について簡単に説明すると、
まず、15行目~72行目で generate_month_calendar という名前の関数を作成して、指定した年月のカレンダーを作成する処理をまとめています。
このgenerate_month_calendarという関数を6行目で使用して、作成したカレンダーをdataという名前の関数に格納する、という処理の流れになっています。
こちらで回答になっていますでしょうか。
初めまして、
プログラミングを勉強し始めた高校生です。
この度は、お聞きしたいことについてコメントをさせて頂きました。
私も今、プログラミング学習の中でカレンダーを作成をしており、本記事を参考にさせて頂きました。
カレンダーのロジックが分からず、思うように実装できない中とても本記事に助けられました。
一つお聞きしたいことがあるのですが、例えばhtmlでinputを用意し、カレンダー内の日付をクリックしたときにinput内に習得した日付を入れたいのですが、その場合どのようにすればいいのでしょうか?
お忙しいところ恐縮ですが、もしお時間があればご教授していただけると幸いです。
高橋理紗さん
コメントありがとうございます。
記事内3番目のデモに追加してみましたが、こちらでどうでしょうか。
https://cly7796.net/blog/sample/create-a-calendar-with-javascript/index4.html
大まかなjsの追加点は以下になります。
(1) 134~138行目でtdにdata属性で日付を追加
(2) 178~194行目でtd要素にクリックイベントを設定する処理を追加
(3) 30~31行目でカレンダーを追加した後にクリックイベントを追加するように設定