<!DOCTYPE html>style.css
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Calendar</title>
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<table>
<thead>
<tr>
<th id="prev">«</th>
<th id="title" colspan="5">2020/05</th>
<th id="next">»</th>
</tr>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td id="today" colspan="7">Today</td>
</tr>
</tfoot>
</table>
<script src="js/main.js"></script>
</body>
</html>
style.css
body {
font-family: 'Courier New', monospace;
font-size: 14px;
}
table {
border-collapse: collapse;
border: 2px solid #eee;
}
thead,
tfoot {
background: #eee;
}
th,
td {
padding: 8px;
text-align: center;
}
tbody td:first-child {
color: red;
}
tbody td:last-child {
color: blue;
}
tfoot {
font-weight: bold;
}
td.disabled {
opacity: 0.3;
}
td.today {
font-weight: bold;
}
#prev,
#next,
#today {
cursor: pointer;
user-select: none;
}
'use strict';
console.clear();
{
const today = new Date();
let year = today.getFullYear();
let month = today.getMonth();
function getCalendarHead() {
const dates = [];
const d = new Date(year, month, 0).getDate();
const n = new Date(year, month, 1).getDay();
for (let i = 0; i < n; i++) {
// 30
// 29, 30
// 28, 29, 30
dates.unshift({
date: d - i,
isToday: false,
isDisabled: true,
});
}
return dates;
}
function getCalendarBody() {
const dates = []; // date: 日付, day: 曜日
const lastDate = new Date(year, month + 1, 0).getDate();
for (let i = 1; i <= lastDate; i++) {
dates.push({
date: i,
isToday: false,
isDisabled: false,
});
}
if (year === today.getFullYear() && month === today.getMonth()) {
dates[today.getDate() - 1].isToday = true;
}
return dates;
}
function getCalendarTail() {
const dates = [];
const lastDay = new Date(year, month + 1, 0).getDay();
for (let i = 1; i < 7 - lastDay; i++) {
dates.push({
date: i,
isToday: false,
isDisabled: true,
});
}
return dates;
}
function clearCalendar() {
const tbody = document.querySelector('tbody');
while (tbody.firstChild) {
tbody.removeChild(tbody.firstChild);
}
}
function renderTitle() {
const title = `${year}/${String(month + 1).padStart(2, '0')}`;
document.getElementById('title').textContent = title;
}
function renderWeeks() {
const dates = [
...getCalendarHead(),
...getCalendarBody(),
...getCalendarTail(),
];
const weeks = [];
const weeksCount = dates.length / 7;
for (let i = 0; i < weeksCount; i++) {
weeks.push(dates.splice(0, 7));
}
weeks.forEach(week => {
const tr = document.createElement('tr');
week.forEach(date => {
const td = document.createElement('td');
td.textContent = date.date;
if (date.isToday) {
td.classList.add('today');
}
if (date.isDisabled) {
td.classList.add('disabled');
}
tr.appendChild(td);
});
document.querySelector('tbody').appendChild(tr);
});
}
function createCalendar() {
clearCalendar();
renderTitle();
renderWeeks();
}
document.getElementById('prev').addEventListener('click', () => {
month--;
if (month < 0) {
year--;
month = 11;
}
createCalendar();
});
document.getElementById('next').addEventListener('click', () => {
month++;
if (month > 11) {
year++;
month = 0;
}
createCalendar();
});
document.getElementById('today').addEventListener('click', () => {
year = today.getFullYear();
month = today.getMonth();
createCalendar();
});
createCalendar();
}