完成イメージ
今回はホテル予約サイトなどでよく見る日付の範囲を選択するフォームをhtml、jquery、cssを用いて作成しました。
入力フォームをクリックするとカレンダーが表示されます
日付を2つ選択すると選択された期間に色が付き、決定ボタンを押すとフォームに日付けが表示されます。クリアボタンで選択した日付を解除します
追加した機能・修正
・2か月分のカレンダー表示
カレンダーを2か月分表示し、ナビゲーションボタンで前月・次月に移動できるようにしました。
・選択範囲のハイライト
選択された2つの日付間を青くハイライトして視覚的に範囲がわかるようにしました。
・コンソールでの確認
日付が決定された際に、選択された期間がコンソールに表示されるようにしました。
・カレンダーの表示を2か月分横並びで表示
カレンダーを2か月分表示し、横に並べて表示できるようにします。
・月をまたいで日付を選択した際に期間に色がつかない問題の修正
月をまたいで日付を選択した場合でも、正しく期間をハイライトするように修正しました。
・未来の日付が先に選択された場合の処理
未来の日付が先に選択された場合、その日付を選択解除し、過去の日付から選択できるようにします。
以下、css、jqueryもhtmlに含めて記述したコードになります
作成コード(HTMLファイル)
select_day.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>jQuery 日付範囲ピッカー</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>
.calendar-container {
display: none;
position: absolute;
background-color: white;
border: 1px solid #ccc;
padding: 10px;
z-index: 1000;
}
.calendar {
display: inline-block;
margin: 10px;
}
.date-input {
width: 150px;
padding: 5px;
margin: 5px;
}
.calendar td {
padding: 5px;
text-align: center;
cursor: pointer;
}
.calendar td.selected {
background-color: #007bff;
color: white;
}
.calendar td.range {
background-color: #a6c8ff;
}
.calendar td.disabled {
color: #ccc;
cursor: not-allowed;
}
.navigation-buttons {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.button-container {
display: flex;
justify-content: space-between;
}
</style>
</head>
<body>
<h1>jQuery 日付範囲ピッカー</h1>
<input type="text" id="daterange" class="date-input" placeholder="日付">
<div class="calendar-container" id="calendarContainer">
<div class="navigation-buttons">
<button id="prevMonth">< 前月</button>
<span id="currentMonth1"></span>
<span id="currentMonth2"></span>
<button id="nextMonth">次月 ></button>
</div>
<div class="calendar" id="calendar1"></div>
<div class="calendar" id="calendar2"></div>
<div class="button-container">
<button id="applyDates">決定</button>
<button id="clearDates">クリア</button>
</div>
</div>
<script>
$(document).ready(function () {
let selectedDates = [];
let currentDate = new Date();
function updateCalendar(monthOffset = 0) {
currentDate.setMonth(currentDate.getMonth() + monthOffset);
let nextMonthDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 1);
$('#currentMonth1').text(`${currentDate.getFullYear()}年 ${currentDate.getMonth() + 1}月`);
$('#currentMonth2').text(`${nextMonthDate.getFullYear()}年 ${nextMonthDate.getMonth() + 1}月`);
generateCalendar('#calendar1', currentDate);
generateCalendar('#calendar2', nextMonthDate);
highlightRange();
}
function generateCalendar(id, date) {
let calendar = $(id);
let month = date.getMonth();
let year = date.getFullYear();
let firstDay = new Date(year, month, 1).getDay();
let lastDate = new Date(year, month + 1, 0).getDate();
let table = $('<table></table>');
let tr = $('<tr></tr>');
let days = ['日', '月', '火', '水', '木', '金', '土'];
for (let i = 0; i < days.length; i++) {
tr.append('<td>' + days[i] + '</td>');
}
table.append(tr);
tr = $('<tr></tr>');
for (let i = 0; i < firstDay; i++) {
tr.append('<td></td>');
}
for (let i = 1; i <= lastDate; i++) {
if ((i + firstDay - 1) % 7 === 0) {
table.append(tr);
tr = $('<tr></tr>');
}
let td = $('<td class="date">' + i + '</td>');
tr.append(td);
}
table.append(tr);
calendar.html(table);
}
function handleDateSelection() {
$('.calendar').on('click', '.date', function () {
let day = parseInt($(this).text());
let month = $(this).closest('.calendar').is('#calendar1') ? currentDate.getMonth() : (currentDate.getMonth() + 1) % 12;
let year = $(this).closest('.calendar').is('#calendar1') ? currentDate.getFullYear() : (currentDate.getMonth() === 11 ? currentDate.getFullYear() + 1 : currentDate.getFullYear());
let fullDate = new Date(year, month, day);
if (selectedDates.length === 2) {
selectedDates = [];
$('.calendar').find('.date').removeClass('selected range');
}
if (selectedDates.length === 1 && fullDate < new Date(selectedDates[0])) {
selectedDates = [fullDate];
$('.calendar').find('.date').removeClass('selected range');
$(this).addClass('selected');
} else {
selectedDates.push(fullDate);
$(this).addClass('selected');
if (selectedDates.length === 2) {
highlightRange();
}
}
});
}
function highlightRange() {
if (selectedDates.length === 2) {
let [startDate, endDate] = selectedDates.sort((a, b) => a - b);
$('.calendar .date').each(function () {
let day = parseInt($(this).text());
let month = $(this).closest('.calendar').is('#calendar1') ? currentDate.getMonth() : (currentDate.getMonth() + 1) % 12;
let year = $(this).closest('.calendar').is('#calendar1') ? currentDate.getFullYear() : (currentDate.getMonth() === 11 ? currentDate.getFullYear() + 1 : currentDate.getFullYear());
let fullDate = new Date(year, month, day);
if (fullDate >= startDate && fullDate <= endDate) {
$(this).addClass('range');
}
});
}
}
function applyDates() {
if (selectedDates.length === 2) {
let [startDate, endDate] = selectedDates.sort((a, b) => a - b).map(date => formatDate(date));
$('#daterange').val(`${startDate} - ${endDate}`);
console.log(`選択された期間: ${startDate} - ${endDate}`);
} else {
alert('2つの日付を選択してください');
}
}
function clearDates() {
selectedDates = [];
$('#daterange').val('');
$('.calendar').find('.date').removeClass('selected range');
}
function formatDate(date) {
return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
}
$('#daterange').on('focus', function () {
$('#calendarContainer').toggle();
});
$('#applyDates').on('click', function () {
applyDates();
$('#calendarContainer').hide();
});
$('#clearDates').on('click', function () {
clearDates();
});
$('#prevMonth').on('click', function () {
updateCalendar(-1);
});
$('#nextMonth').on('click', function () {
updateCalendar(1);
});
$(document).click(function(event) {
if(!$(event.target).closest('#calendarContainer, #daterange').length) {
$('#calendarContainer').hide();
}
});
handleDateSelection();
updateCalendar();
});
</script>
</body>
</html>