SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

ブラウザで動くシンプルな万年カレンダーを作る/素のJavaScript(Vanilla JS)だけ

f:id:arakan_no_boku:20210228143618p:plain

目次

シンプルな万年カレンダー

出来上がりイメージはこんな感じです。

f:id:arakan_no_boku:20210228151044p:plain

右の△を押すと、1月先、左の△を押すと1月戻る・・ようにします。

HTML ソース

ベースとなるHTMLです。

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="utf8">
        <title>ごく簡単なカレンダー</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="bulma/css/bulma.css" />
    </head>
    <body>
        <section class="hero is-fullheight is-dark">
            <div class="hero-body">               
                <div class="container has-text-centered">
                    <div class="content">
                        <table>
                            <tr>
                                <td class="is-one-quarter">
                                    <input type="image" src="images/left-allow.jpg" onclick="dec_month()" />
                                </td>
                                <td class="is-half">
                                    <div id="title" class="content"></div>
                                </td>
                                <td class="is-one-quarter">
                                    <input type="image" src="images/right-allow.jpg" onclick="inc_month()" />
                                </td>
                            </tr>
                        </table>
                    </div>
                    <div id="main_body" class="content has-text-centered">
                    </div>
                </div>
            </div>    
            <div class="hero-foot">
                <div class="container has-text-centered is-vcentered">
                    <div class="content">
                    <p>
                        2021/02/25 基本の確認をかねてやってみる
                    </p>
                    </div>
                </div>
            </div>
        </section>
        <script src="js/cal_sample.js"></script>
    </body>
</html>

レイアウトを定義しています。

CSSは「Bulma」を使っています。

bulma.io

ダウンロード後解凍したbulmaフォルダごと、htmlを置いたフォルダにコピーしている想定です。 

カレンダー本体は、JavaScriptでHTMLを生成して、「<div id="main_body" class="content has-text-centered"> </div>」のブロック内に出力します。

 あと「X月のカレンダー」と表示する部分も、同様にJavaScriptでHTML生成して、「 <div id="title" class="content"></div>」内に出力します。 

JavaScriptのソース全体は最後に掲載します。

先に各ポイントごとに説明します。

javascript のポイント1:現在日付情報取得

まずは「現在日付情報の取得」です。

var d_now = new Date()
var tmp_n_year = d_now.getFullYear()
var tmp_n_month = d_now.getMonth() + 1

日付情報はJavaScriptのDateオブジェクトを使います。

developer.mozilla.org

ここで取得するtmp_n_monthは、実際の月を想定していますが、getMonth()が返してくる月は実際の月-1の数字なので、「d_now.getMonth() + 1」としているわけです。 

javascriptのポイント2:前月・次月ボタン

HTMLの画像ボタン「 <input type="image" src="images/left-allow.jpg" onclick="dec_month()" />」と「 <input type="image" src="images/left-allow.jpg" onclick="inc_month()" />」で右向きと左向きの△の画像ボタンを作ります。

f:id:arakan_no_boku:20210301213607j:plain と f:id:arakan_no_boku:20210301213630j:plain みたいな。

このボタンを押すと、月をプラス1かマイナス1して、月間のカレンダーを表示する「disp_cal()」を実行します。

function dec_month() {
    disp_cal(tmp_n_year, tmp_n_month - 1)
}

function inc_month() {
    disp_cal(tmp_n_year, tmp_n_month + 1)
}

tmp_n_monthが現在表示中の月を示します。

tmp_n_monthは、disp_cal()の中で更新して、現在表示中の月を保持しています。 

javascriptのポイント3:月間カレンダー表示

現在日付の年・月を初期値にカレンダー表示する部分です。

この部分は「disp_cal(year,month)」という名前の関数で定義します。

function disp_cal(year, month) {

    tmp_n_year = year
    tmp_n_month = month
    var d_date = new Date(tmp_n_year, tmp_n_month - 1, 1) 
    var n_dayOfWeek = d_date.getDay()
    var n_month = d_date.getMonth()
    var n_year = d_date.getFullYear()
const n_base_month = d_date.getMonth() document.getElementById('title').innerHTML = '<h1 class="title">' + n_year + '年' + (n_base_month + 1) + '月のカレンダー</h1>' var str_body = '' for (let i = 0; i < 5; i++) { str_body = str_body + '<div class="columns">' for (let j = 0; j < 7; j++) { if (n_dayOfWeek == j && n_base_month == n_month) { if (n_dayOfWeek == 0) { str_body = str_body + '<div class="column" ' + 'style="height:80px;color:yellow;' + 'border-bottom:solid white;border-left:solid white;border-right:solid white;"><p>' + d_date.getDate() + '</p></div>' } else { if (n_dayOfWeek == 6) { str_body = str_body + '<div class="column" ' + 'style="height:80px;color:yellow;' + 'border-bottom:solid white;border-right:solid white;"><p>' + d_date.getDate() + '</p></div>' } else { str_body = str_body + '<div class="column" ' + 'style="height:80px;border-bottom:solid;border-right:solid;"><p>' + d_date.getDate() + '</p></div>' } } d_date.setDate(d_date.getDate() + 1) n_dayOfWeek = d_date.getDay() n_month = d_date.getMonth() } else { if (n_dayOfWeek == 0 || j == 0) { str_body = str_body + '<div class="column" ' + 'style="height:80px;border-bottom:solid;border-left:solid;border-right:solid;">' + '<p>-</p></div>' } else { if (n_dayOfWeek == 6) { str_body = str_body + '<div class="column" ' + 'style="height:80px;border-bottom:solid;border-right:solid;"><p>-</p></div>' } else { str_body = str_body + '<div class="column" ' + 'style="height:80px;border-bottom:solid;border-right:solid;"><p>-</p></div>' } } } } str_body = str_body + '</div>' } var ar_dayOfWeek = ['日', '月', '火', '水', '木', '金', '土'] var str_head = '<div class="columns">' for (let t = 0; t < 7; t++) { str_head = str_head + '<div class="column" style="height:60px;border-bottom:solid;"><p>' + ar_dayOfWeek[t] + '</p></div>' } str_head = str_head + '</div>' str_body = str_head + str_body document.getElementById('main_body').innerHTML = str_body }

とりあえずポイントです。

tmp_n_year = year
tmp_n_month = month

引数をカレントの年・月を保持する変数にセットしています。

「var」で定義した変数はfunctionの外で定義していても、参照更新できます。

(lブロックスコープの「let」は、forループのカウンタ等に使ってます。)

それを使って、指定の年・月の1日の日付を取得します。

tmp_n_monthには「2月なら2」「3月なら3」のように人が認識するのと同じ月をセットしていますが、Dateオブジェクトの引数にするときは「2月なら1」「3月なら2」のようにマイナス1しないといけないので、以下のようになってます。

var d_date = new Date(tmp_n_year, tmp_n_month - 1, 1)
var n_dayOfWeek = d_date.getDay()
var n_month = d_date.getMonth()
var n_year = d_date.getFullYear()

javascriptのポイント4:タイトルの表示

 タイトル部分の表示です。

const n_base_month = d_date.getMonth()

document.getElementById('title').innerHTML = '<h1 class="title">' + n_year + '年' + (n_base_month + 1) + '月のカレンダー</h1>'

HTMLのタグを文字列で生成して、innerHTMLで上書きしてます。

Dateオブジェクトの「getDay()」で曜日(0-6 0が日曜)を返すので、それにあわせて日曜始まりの枠を作ってます。

var ar_dayOfWeek = ['日', '月', '火', '水', '木', '金', '土']
var str_head = '<div class="columns">'
for (let t = 0; t < 7; t++) {
 str_head = str_head
  + '<div class="column" style="height:60px;border-bottom:solid;"><p>'
  + ar_dayOfWeek[t] + '</p></div>'
}
str_head = str_head + '</div>'

あとは、7日×5行の枠を作るループをまわすと。

for (let i = 0; i < 5; i++) {
 for (let j = 0; j < 7; j++) {

   ・・・・

   }

}

内側の変数「j」が曜日(0-6)に対応するので、日にちを1日ずつすすめながら、

d_date.setDate(d_date.getDate() + 1)

n_dayOfWeek = d_date.getDay()

getDay()で取得した曜日と変数[j」の値が一致するところに書き込むHTMLを生成して文字列として連結して、最後にinnerHTMLに上書きする・・というわけです。

で。

n_month = d_date.getMonth()

 上記で取得するn_monthの値(月)が、指定の月(base_month)と一致している間だけ繰り返すと、ちょうどひと月分のカレンダーになります。

HTMLを生成するときに、ちょっと面倒なのが「border」の引き方です。

普通に「border」ってするだけだと、隣り合う線が重複して太くなって不細工なので、基本bottomとrightのみ線を引いて、一番左端(j=0)の場合のみleftも引く・・みたいなことをやって、体裁を整えてます。

とりあえず。

こんなところでしょうか。 

javascriptソース全体 

最後に「cal_sample.js」全体をのせておきます。

function dec_month() {
    disp_cal(tmp_n_year, tmp_n_month - 1)
}

function inc_month() {
    disp_cal(tmp_n_year, tmp_n_month + 1)
}

function disp_cal(year, month) {

    tmp_n_year = year
    tmp_n_month = month

    var d_date = new Date(tmp_n_year, tmp_n_month - 1, 1) 
    var n_dayOfWeek = d_date.getDay()
    var n_month = d_date.getMonth()
    var n_year = d_date.getFullYear()
    const n_base_month = d_date.getMonth()

    document.getElementById('title').innerHTML = '<h1 class="title">'
        + n_year + '年' + (n_base_month + 1)
        + '月のカレンダー</h1>'

    var str_body = ''
    for (let i = 0; i < 5; i++) {
        str_body = str_body + '<div class="columns">'
        for (let j = 0; j < 7; j++) {
            if (n_dayOfWeek == j && n_base_month == n_month) {
                if (n_dayOfWeek == 0) {
                    str_body = str_body
                        + '<div class="column" '
                        + 'style="height:80px;color:yellow;'
                        + 'border-bottom:solid white;border-left:solid white;border-right:solid white;"><p>'
                        + d_date.getDate() + '</p></div>'
                } else {
                    if (n_dayOfWeek == 6) {
                        str_body = str_body
                            + '<div class="column" '
                            + 'style="height:80px;color:yellow;'
                            + 'border-bottom:solid white;border-right:solid white;"><p>'
                            + d_date.getDate() + '</p></div>'
                    } else {
                        str_body = str_body
                            + '<div class="column" '
                            + 'style="height:80px;border-bottom:solid;border-right:solid;"><p>'
                            + d_date.getDate() + '</p></div>'
                    }
                }
                d_date.setDate(d_date.getDate() + 1)
                n_dayOfWeek = d_date.getDay()
                n_month = d_date.getMonth()
            } else {
                if (n_dayOfWeek == 0 || j == 0) {
                    str_body = str_body
                        + '<div class="column" '
                        + 'style="height:80px;border-bottom:solid;border-left:solid;border-right:solid;">'
                        + '<p>-</p></div>'
                } else {
                    if (n_dayOfWeek == 6) {
                        str_body = str_body
                            + '<div class="column" '
                            + 'style="height:80px;border-bottom:solid;border-right:solid;"><p>-</p></div>'
                    } else {
                        str_body = str_body
                            + '<div class="column" '
                            + 'style="height:80px;border-bottom:solid;border-right:solid;"><p>-</p></div>'
                    }
                }
            }
        }
        str_body = str_body + '</div>'
    }
    var ar_dayOfWeek = ['日', '月', '火', '水', '木', '金', '土']
    var str_head = '<div class="columns">'
    for (let t = 0; t < 7; t++) {
        str_head = str_head
            + '<div class="column" style="height:60px;border-bottom:solid;"><p>'
            + ar_dayOfWeek[t] + '</p></div>'
    }
    str_head = str_head + '</div>'
    str_body = str_head + str_body

    document.getElementById('main_body').innerHTML = str_body

}

var d_now = new Date()
var tmp_n_year = d_now.getFullYear()
var tmp_n_month = d_now.getMonth() + 1
disp_cal(tmp_n_year, tmp_n_month)

素のJavaScript(Vanilla JS)でやってます。

vanilla-js.com

ではでは。

#JS