自分用メモです。
参考ページ:https://www.geeksforgeeks.org/how-to-design-a-simple-calendar-using-javascript/ をもとに、若干スタイルを変更。
calender.html
<!DOCTYPE html>
<!-- 参考: https://www.geeksforgeeks.org/how-to-design-a-simple-calendar-using-javascript/ -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>Calendar</title>
<link rel="stylesheet" href="calender_style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="wrapper">
<header>
<p class="current-date"></p>
<div class="icons">
<span id="prev">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"/>
</svg>
</span>
<span id="next">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/>
</svg>
</span>
</div>
</header>
<div class="calendar">
<ul class="weeks">
<li>日</li>
<li>月</li>
<li>火</li>
<li>水</li>
<li>木</li>
<li>金</li>
<li>土</li>
</ul>
<ul class="days"></ul>
</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="calender_script.js" defer></script>
</html>
calender_style.css
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
body{
display: flex;
align-items: center;
padding: 0 10px;
justify-content: center;
min-height: 100vh;
background: #9B59B6;
}
.wrapper{
width: 450px;
background: #fff;
border-radius: 10px;
box-shadow: 0 15px 40px rgba(0,0,0,0.12);
}
.wrapper header{
display: flex;
align-items: center;
padding: 25px 30px 10px;
justify-content: space-between;
}
header .icons{
display: flex;
}
header .icons span{
height: 38px;
width: 38px;
margin: 0 1px;
cursor: pointer;
color: #878787;
text-align: center;
line-height: 38px;
font-size: 1.9rem;
user-select: none;
border-radius: 50%;
}
.icons span:last-child{
margin-right: -10px;
}
header .icons span:hover{
background: #f2f2f2;
}
header .current-date{
font-size: 1.45rem;
font-weight: 500;
}
.calendar{
padding: 20px;
}
.calendar ul{
display: flex;
flex-wrap: wrap;
list-style: none;
text-align: center;
padding-left: 0; /* ここで左側のスペースを調整 */
margin-left: -4px; /* カレンダーの左右のバランスを取るためにマージンを微調整 */
}
.calendar .days{
margin-bottom: 20px;
}
.calendar li{
color: #333;
width: calc(100% / 7);
font-size: 1.07rem;
}
.calendar .weeks li{
font-weight: 500;
cursor: default;
}
.calendar .days li{
z-index: 1;
cursor: pointer;
position: relative;
margin-top: 30px;
}
.days li.inactive{
color: #aaa;
}
.days li.active{
color: #fff;
}
.days li::before{
position: absolute;
content: "";
left: 50%;
top: 50%;
height: 40px;
width: 40px;
z-index: -1;
border-radius: 50%;
transform: translate(-50%, -50%);
}
.days li.active::before{
background: #9B59B6;
}
.days li:not(.active):hover::before{
background: #f2f2f2;
}
/* 非アクティブな日付(前月・次月の日付)にはポインターを無効に */
.days li.inactive {
color: #aaa;
cursor: default; /* カーソルをデフォルトに */
}
/* 非アクティブな日付にはホバー時の背景色変更を無効に */
.days li.inactive:hover::before {
background: none; /* ホバー時に背景色を無効に */
}
calender_script.js
document.addEventListener("DOMContentLoaded", () => {
const daysTag = document.querySelector(".days"),
currentDate = document.querySelector(".current-date"),
prevNextIcons = document.querySelectorAll(".icons span");
let date = new Date(),
currYear = date.getFullYear(),
currMonth = date.getMonth();
const renderCalendar = () => {
let firstDayofMonth = new Date(currYear, currMonth, 1).getDay(),
lastDateofMonth = new Date(currYear, currMonth + 1, 0).getDate(),
lastDayofMonth = new Date(currYear, currMonth, lastDateofMonth).getDay(),
lastDateofLastMonth = new Date(currYear, currMonth, 0).getDate();
let liTag = "";
// 前の月の最後の日を表示
for (let i = firstDayofMonth; i > 0; i--) {
liTag += `<li class="inactive">${lastDateofLastMonth - i + 1}</li>`;
}
// 現在の月の日付を表示
for (let i = 1; i <= lastDateofMonth; i++) {
liTag += `<li class="activeMonth" data-day="${i}">${i}</li>`;
}
// 次の月の最初の日を表示
for (let i = lastDayofMonth; i < 6; i++) {
liTag += `<li class="inactive">${i - lastDayofMonth + 1}</li>`;
}
currentDate.innerText = `${currYear}年 ${currMonth + 1}月`;
daysTag.innerHTML = liTag;
// カレンダーがレンダリングされた後にクリックイベントを再度追加
addClickEvents();
}
const addClickEvents = () => {
const allDays = document.querySelectorAll(".days li.activeMonth");
allDays.forEach(day => {
day.addEventListener("click", () => {
const dayValue = day.getAttribute("data-day");
// dayValue が取得できない場合の対策
if (!dayValue) {
console.error("Day value is not available.");
return;
}
const formattedDayValue = dayValue.toString().padStart(2, '0');
const selectedDate = `${currYear}-${(currMonth + 1).toString().padStart(2, '0')}-${formattedDayValue}`;
console.log("Selected date:", selectedDate);
});
});
}
renderCalendar();
prevNextIcons.forEach(icon => {
icon.addEventListener("click", () => {
currMonth = icon.id === "prev" ? currMonth - 1 : currMonth + 1;
if (currMonth < 0 || currMonth > 11) {
date = new Date(currYear, currMonth, new Date().getDate());
currYear = date.getFullYear();
currMonth = date.getMonth();
} else {
date = new Date();
}
renderCalendar();
});
});
});