JavaScrpt/시간 날짜 달력

JavaScript Calendar - 캘린더 UI 구성, 연간 달력 만들기 (달력 생성 함수 사용)

carrotweb 2022. 4. 9. 17:37
728x90
반응형

달력 생성 함수(calendar.js)를 사용하여 캘린더(Calendar)를 만들겠습니다.

캘린더 UI 구성

기존 달력 UI에 연간과 월간 달력으로 변경할 수 있게 달력 뷰 버튼 그룹을 추가합니다.

<div class="calendar">
	<div class="calendar-header">
		<span class="calendar-yearmonth"></span>
		<div class="calendar-controls">
			<button type="button" class="calendar-prev">&lt;</button>
			<button type="button" class="calendar-next">&gt;</button>
			<button type="button" class="calendar-today">오늘</button>
		</div>
		<div class="calendar-views">
			<button type="button" class="calendar-view-year">년간</button>
			<button type="button" class="calendar-view-month">월간</button>
		</div>
	</div>
	<div id="calendar"></div>
</div>

 

기존 style에 달력 컨트롤 버튼 그룹(.calendar-controls)을 수정하고 달력 뷰 버튼 그룹(.calendar-views)를 추가합니다.

년과 월을 표시하는 <span> 태그와 달력 컨트롤 버튼 그룹(.calendar-controls)인 <div> 태그가 연속으로 나열되기 위해서 display를 inline-block으로 변경하고 달력 컨트롤 버튼 그룹(.calendar-controls)인 <div> 태그의 위치를 vertical-align과 margin으로 조정합니다.

달력 뷰 버튼 그룹(.calendar-views)은 기존 달력 컨트롤 버튼 그룹(.calendar-controls)처럼 오른쪽에 정렬되도록 설정합니다.

/* calendar-controls */
.calendar > .calendar-header { position: relative; height: 50px; margin: 0px 20px; }
.calendar > .calendar-header > .calendar-yearmonth { display: inline-block; font-size: larger; font-weight: bolder; color: red; line-height: 50px; }
.calendar > .calendar-header > .calendar-controls { display: inline-block; vertical-align: top; margin: 11px 0 0 5px; }
.calendar > .calendar-header > .calendar-controls > button { float: left; width: 25px; height: 28px; padding: 1px 4px 0 4px; border: 1px solid #cbcbcb; background-color: #fff; font-size: 12px; cursor: pointer; }
.calendar > .calendar-header > .calendar-controls > button.calendar-today { width: 40px; }
/* calendar-views */
.calendar > .calendar-header > .calendar-views { position: absolute; top: 11px; right: 0px; }
.calendar > .calendar-header > .calendar-views > button { float: left; width: 40px; height: 28px; padding: 1px 4px 0 4px; border: 1px solid #cbcbcb; background-color: #f8f8f8; font-size: 12px; cursor: pointer; }
.calendar > .calendar-header > .calendar-views > button.active { border-color: #7f4ac8!important; background: #9155e5!important; color: #fff; }

 

calendarMonth() 함수에서 연간 달력 함수와 공동으로 사용될 임시 공휴일 해시맵을 분리합니다.

// 임시 공휴일 해시맵(HashMap)
var hashmapTemporaryHoliday = [];
hashmapTemporaryHoliday["2022-3-9"] = {"title" : "20대 대통령 선거일"};

임시 공휴일은 Database에서 쿼리로 연도 또는 월 단위로 가져와서 사용하시면 됩니다.

 

연간 달력 함수 생성

달력 생성 함수(calendar.js)를 사용하여 연간 달력 함수를 생성합니다.

연간 달력은 월이 4열 X 3행으로 나오도록 for() 문으로 처리합니다.

function calendarYear(date) {
	// 년
	$(".calendar-yearmonth").html(date.getFullYear() + "년");
		
	var options = {
		showDay : true,
		showToday : true,
		arHoliday : hashmapTemporaryHoliday
	};
	
	var html = "";
	html += "<table>";
	html += "<tbody>";
	for (var index1 = 0; index1 < 4; index1++) {
		html += "<tr>";
		for (var index2 = 0; index2 < 3; index2++) {
			html += "<td>";
			html += "<div class=\"calendar-month\">" + (index1 * 3 + index2 + 1) + "월</div>";
			html += calendarHTML(new Date(date.getFullYear(), (index1 * 3 + index2), 1), options);
			html += "</td>";
		}
		html += "</tr>";
	}
	html += "</tbody>";
	html += "</table>";
	
	$("#calendar").attr("data-date", date.getFullYear());
	$("#calendar").html(html);
}

 

 

달력 뷰 버튼 클릭 이벤트 처리

달력 뷰 버튼에 대한 click 이벤트를 <script>에 추가합니다.

클릭 이벤트가 발생한 버튼에 클래스를 찾아서 연간 버튼인지 월간 버튼인지 확인하여 함수를 호출하게 합니다.

// 달력 뷰 버튼
$(".calendar-views > button").on("click", function(event) {
	if ($(event.target).hasClass("calendar-view-year")) {
		calendarYear(new Date());
	} else if ($(event.target).hasClass("calendar-view-month")) {
		calendarMonth(new Date());
	}
});

 

연간 버튼을 클릭하면 현재 연도의 1월부터 12월까지 나옵니다.

 

달력의 style이 동일하게 적용되다 보니 연간 달력이 크게 나옵니다.

 

그래서 월간의 style을 수정하고 연간 style를 추가합니다.

<td> 태그와 <span> 태그의 padding를 기본과 월간, 연간으로 분리합니다. 그리고 연간 달력의 폰트 사이즈를 작게하고 월을 왼쪽으로 정렬하여 설정합니다.

.calendar { width: 500px; }
.calendar table { width: 100%; }
.calendar table > caption { font-size: larger; font-weight: bolder; color: red; text-align: left; padding: 10px 20px; }
.calendar table > thead > tr > th.saturday { color: gray; }
.calendar table > thead > tr > th.sunday { color: red; }
.calendar table > tbody > tr > td { text-align: center; vertical-align: top; }
.calendar table > tbody > tr > td > span { display: block; }
.calendar table > tbody > tr > td > span.today { border: 1px solid red; border-radius: 50%; color: white; background-color: red; }
.calendar table > tbody > tr > td > span.saturday { color: gray; }
.calendar table > tbody > tr > td > span.sunday { color: red; }
.calendar table > tbody > tr > td > span.holiday { color: red; }
/* calendar month */
.calendar.month table > tbody > tr > td { padding: 10px 10px; }
.calendar.month table > tbody > tr > td > span { padding: 10px 10px; }
.calendar.month table > tbody > tr > td > span.today { padding: 9px 9px; }
/* calendar year */
.calendar.year table { font-size: 12px; }
.calendar.year table > thead > tr > th { font-weight: normal; }
.calendar.year table > tbody > tr > td > span { padding: 2px 2px; }
.calendar.year .calendar-month { height: 30px; font-size: 14px; font-weight: bolder; text-align: left; line-height: 30px; margin-left: 4px; }

style를 공용으로 사용하기 위해 위의 달력 컨트롤 버튼 그룹과 달력 뷰 버튼 그룹의 style을 포하해서 calendar.css 파일로 분리합니다.

 


월간과 연간 달력에 style이 적용되도록  calendarMonth() 함수와 calendarYear() 함수를 수정합니다.
클래스가 .calendar인 <div> 태그의 class에 월간이면 "month"를 연간이면 "year"를 추가합니다.
그리고 calendarMonth() 함수에서 연월 표시를 변경합니다.

 
function calendarMonth(date) {
	$(".calendar").removeClass("year");
	$(".calendar").addClass("month");
	// 년월
	$(".calendar-yearmonth").html(date.getFullYear() + "년 " + (date.getMonth() + 1) + "월");
	
	var options = {
		showDay : true,
		showFullDayName : true,
		showToday : true,
		arHoliday : hashmapTemporaryHoliday
	};
	
	var html = calendarHTML(date, options);
	$("#calendar").attr("data-date", date.getFullYear() + "-" + (date.getMonth() + 1));
	$("#calendar").html(html);
}

function calendarYear(date) {
	$(".calendar").removeClass("month");
	$(".calendar").addClass("year");
	// 년
	$(".calendar-yearmonth").html(date.getFullYear() + "년");
	
	var options = {
		showDay : true,
		showToday : true,
		arHoliday : hashmapTemporaryHoliday
	};
	
	var html = "";
	html += "<table>";
	html += "<tbody>";
	for (var index1 = 0; index1 < 4; index1++) {
		html += "<tr>";
		for (var index2 = 0; index2 < 3; index2++) {
			html += "<td>";
			html += "<div class=\"calendar-month\">" + (index1 * 3 + index2 + 1) + "월</div>";
			html += calendarHTML(new Date(date.getFullYear(), (index1 * 3 + index2), 1), options);
			html += "</td>";
		}
		html += "</tr>";
	}
	html += "</tbody>";
	html += "</table>";
	
	$("#calendar").attr("data-date", date.getFullYear());
	$("#calendar").html(html);
}

 

달력 뷰 버튼 클릭 시 선택된 버튼의 class에 .active를 추가합니다. 선택된 다른 버튼에서는 class에 .active를 삭제합니다.

// 달력 뷰 버튼
$(".calendar-views > button").on("click", function(event) {
	$(".calendar-views > button").each(function() {
		$(this).removeClass("active");
	});
	if ($(event.target).hasClass("calendar-view-year")) {
		calendarYear(new Date());
	} else if ($(event.target).hasClass("calendar-view-month")) {
		calendarMonth(new Date());
	}
	$(event.target).addClass("active");
});

 

월간 버튼을 클릭하면 현재 월이 나옵니다.

 

연간 버튼을 클릭하면 현재 연도의 1월부터 12월까지 나옵니다.

 

이전 버튼과 다음 버튼, 오늘 버튼을 공통으로 사용하기 위해서 버튼 클릭 이벤트 처리 함수에서 클래스가 .calendar인 <div> 태그의 class에서 "month"가 있으면 calendarMonth() 함수로 "year"가 있으면 calendarYear() 함수로 호출되게 처리합니다.

// 이전 이동 버튼
$(".calendar-controls > .calendar-prev").on("click", function() {
	if ($(".calendar").hasClass("year")) {
		var year = $("#calendar").attr("data-date");
		calendarYear(new Date(parseInt(year) - 1, 1, 1));
	} else if ($(".calendar").hasClass("month")) {
		var yearmonth = $("#calendar").attr("data-date").split("-");
		calendarMonth(new Date(parseInt(yearmonth[0]), parseInt(yearmonth[1]) - 2, 1));
	}
});

// 다음 이동 버튼
$(".calendar-controls > .calendar-next").on("click", function() {
	if ($(".calendar").hasClass("year")) {
		var year = $("#calendar").attr("data-date");
		calendarYear(new Date(parseInt(year) + 1, 1, 1));
	} else if ($(".calendar").hasClass("month")) {
		var yearmonth = $("#calendar").attr("data-date").split("-");
		calendarMonth(new Date(parseInt(yearmonth[0]), parseInt(yearmonth[1]), 1));
	}
});

// 오늘 이동 버튼
$(".calendar-controls > .calendar-today").on("click", function() {
	if ($(".calendar").hasClass("year")) {
		calendarYear(new Date());
	} else if ($(".calendar").hasClass("month")) {
		calendarMonth(new Date());
	}
});

 

 

전체 소스입니다.

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>캘린더</title>
		<link rel="stylesheet" type="text/css" href="calendar.css" />
		<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
		<script src="calendar.js"></script>
	</head>
	<body>
		<div class="calendar">
			<div class="calendar-header">
				<span class="calendar-yearmonth"></span>
				<div class="calendar-controls">
					<button type="button" class="calendar-prev">&lt;</button>
					<button type="button" class="calendar-next">&gt;</button>
					<button type="button" class="calendar-today">오늘</button>
				</div>
				<div class="calendar-views">
					<button type="button" class="calendar-view-year">연간</button>
					<button type="button" class="calendar-view-month">월간</button>
				</div>
			</div>
			<div id="calendar"></div>
		</div>
		<script>
			// 달력 뷰 버튼
			$(".calendar-views > button").on("click", function(event) {
				$(".calendar-views > button").each(function() {
					$(this).removeClass("active");
				});
				if ($(event.target).hasClass("calendar-view-year")) {
					calendarYear(new Date());
				} else if ($(event.target).hasClass("calendar-view-month")) {
					calendarMonth(new Date());
				}
				$(event.target).addClass("active");
			});
			
			// 이전 이동 버튼
			$(".calendar-controls > .calendar-prev").on("click", function() {
				if ($(".calendar").hasClass("year")) {
					var year = $("#calendar").attr("data-date");
					calendarYear(new Date(parseInt(year) - 1, 1, 1));
				} else if ($(".calendar").hasClass("month")) {
					var yearmonth = $("#calendar").attr("data-date").split("-");
					calendarMonth(new Date(parseInt(yearmonth[0]), parseInt(yearmonth[1]) - 2, 1));
				}
			});
			
			// 다음 이동 버튼
			$(".calendar-controls > .calendar-next").on("click", function() {
				if ($(".calendar").hasClass("year")) {
					var year = $("#calendar").attr("data-date");
					calendarYear(new Date(parseInt(year) + 1, 1, 1));
				} else if ($(".calendar").hasClass("month")) {
					var yearmonth = $("#calendar").attr("data-date").split("-");
					calendarMonth(new Date(parseInt(yearmonth[0]), parseInt(yearmonth[1]), 1));
				}
			});
			
			// 오늘 이동 버튼
			$(".calendar-controls > .calendar-today").on("click", function() {
				if ($(".calendar").hasClass("year")) {
					calendarYear(new Date());
				} else if ($(".calendar").hasClass("month")) {
					calendarMonth(new Date());
				}
			});
			
			// 날짜 클릭
			$(document).on("click", ".calendar table > tbody > tr > td", function(event) {
				//event.preventDefault();
				event.stopPropagation();
				var eventTarget = event.target;
				while (eventTarget.tagName != "TD") {
					eventTarget = eventTarget.parentElement;
				}
				if ($(eventTarget).attr("data-date") != undefined) {
					alert($(eventTarget).attr("data-date"));
				}
			});
			
			// 임시 공휴일 해시맵(HashMap)
			var hashmapTemporaryHoliday= [];
			hashmapTemporaryHoliday["2022-3-9"] = {"title" : "20대 대통령 선거일"};
			
			function calendarMonth(date) {
				$(".calendar").removeClass("year");
				$(".calendar").addClass("month");
				// 년월
				$(".calendar-yearmonth").html(date.getFullYear() + "년 " + (date.getMonth() + 1) + "월");
				
				var options = {
					showDay : true,
					showFullDayName : true,
					showToday : true,
					arHoliday : hashmapTemporaryHoliday
				};
				
				var html = calendarHTML(date, options);
				$("#calendar").attr("data-date", date.getFullYear() + "-" + (date.getMonth() + 1));
				$("#calendar").html(html);
			}
			
			function calendarYear(date) {
				$(".calendar").removeClass("month");
				$(".calendar").addClass("year");
				// 년
				$(".calendar-yearmonth").html(date.getFullYear() + "년");
				
				var options = {
					showDay : true,
					showToday : true,
					arHoliday : hashmapTemporaryHoliday
				};
				
				var html = "";
				html += "<table>";
				html += "<tbody>";
				for (var index1 = 0; index1 < 4; index1++) {
					html += "<tr>";
					for (var index2 = 0; index2 < 3; index2++) {
						html += "<td>";
						html += "<div class=\"calendar-month\">" + (index1 * 3 + index2 + 1) + "월</div>";
						html += calendarHTML(new Date(date.getFullYear(), (index1 * 3 + index2), 1), options);
						html += "</td>";
					}
					html += "</tr>";
				}
				html += "</tbody>";
				html += "</table>";
				
				$("#calendar").attr("data-date", date.getFullYear());
				$("#calendar").html(html);
			}
			
			calendarMonth(new Date());
			$(".calendar-view-month").addClass("active");
		</script>
	</body>
</html>

 

월간과 연간에서 이전 이동 버튼과 다음 이동 버튼을 클릭하여 테스트해 보시기 바랍니다.

 

 

728x90
반응형