자바 스크립트 달력 만들기 - jaba seukeulibteu dallyeog mandeulgi

달력은 Date 객체를 생성하여 Date에서 제공하는 메소드로 각각 연도, 달, 날짜, 요일(인덱스를) 추출합니다. 달력은 이중배열로 [[첫주], [둘째주],,,[마지막주]]와 같은 형태로, 첫주를 만드는 함수와 나머지 주차를 만드는 함수를 나누어 사용합니다.

Show

날짜는 전역변수로 지정했습니다. 먼저 현재 달의 1일을 Date객체에 지정하여 이번 달의 시작 요일(인덱스)을 얻습니다. 이 인덱스를 첫주를 만드는 함수에 넘겨 첫주를 캘린더 배열에 담고, 해당 달의 마지막 날에 이를때까지 배열을 추가하면서 달력을 생성합니다.

이렇게 생성된 이중배열을 매핑하여 document 객체에서 제공하는 셀렉터와 엘리먼트 생성 메소드를 이용하여 하루를 나타내는 div를 생성하고, 컨테이너에 자식으로 추가하여 달력을 생성합니다.

버튼 컨트롤은 좌,우 버튼으로 현재 달과 배경 이미지를 나타내는 인덱스를 증감시키고, 12개월의 범위와 연도의 범위, 배경이미지 클래스의 범위에 유효성검사를 지정해 줍니다. 배경이미지 컨트롤은 버튼 클릭 함수에 기존 배경 이미지 인덱스 id를 셀렉트하여 기존 opaque클래스를 삭제하고 인덱스에 1을 증가한 이미지에 opaque클래스를 추가하는 방식으로 구성했습니다.

css를 살펴보겠습니다.

css는 #back .imgview에 투명도 0과 -webkit-transition을 지정합니다.

그리고 #back .imgview:nth-child()클래스에 각각의 배경이미지를 설정해주고, #back .imgview.opaque 클래스에 투명도 1과 filter 속성을 주어, 현재 선택된 배경만 보여지고 나머지는 투명도 0으로 숨겨지도록 구성했습니다.

얼마 전에 업무 상에서 달력🗓이 필요한 경우가 있었는데요. 기존의 라이브러리들은 원하는 대로 커스텀하기가 어려워서, 달력을 직접 만들어야 했습니다. 그래서 이번 포스팅에서는 제가 업무 상에서 만들었던 달력을 간단하게 정리해서 공유해 보려고 해요. jQuery를 사용하지 않고 순수한 HTML, CSS, JavaScript, DOM API를 이용해서 달력을 만들게 됩니다. 직접 달력을 커스텀하셔서 사용해야 하는 분들께 작은 도움이 되었으면 좋겠습니다.

자바스크립트로 달력을 만들 때 가장 중요한 것은 Date 객체에 대한 이해입니다. 저도 Date 객체의 사용법을 제대로 알지 못하다보니, 어떻게 구현해야할 지 당최 생각이 나지 않았는데요, 아마 이번 캘린더 만들기를 따라하시면 여러분 모두Date 객체에 조금 더 친숙해지게 될 겁니다!

코딩을 시작하기전에, 달력을 어떻게 만들어야하는지 생각해보죠!

먼저 달력은 항상 5주 혹은 6주로 나타나므로, 6개의 행이 필요합니다.(5주인줄 알았는데, 정용욱님의 지적으로 1일이 토요일부터 시작할 경우 6주가 되는 경우가 있다는 것을 알았습니다!) 또한 매월 시작 날짜와 종료 날짜가 달라지므로, 이번 달의 시작 날짜와 종료 날짜를 구해야 합니다. 시작 날짜와 종료 날짜를 구했다면, 이번 달이 아닌 달력 빈 칸에 채워넣을 지난 달 시작 날짜 이전의 요일들, 다음 달 종료 날짜 이후의 요일들을 구해야 합니다.

이번 포스팅에서는 편의를 위해 하나의 html파일에 스타일과 스크립트를 모두 같이 작성해보겠습니다. 먼저 html파일을 만들고 다음과 같이 뼈대를 작성해주세요.

이제 스크립트를 짜봐야겠죠? 주석과 함께 진행해보겠습니다.

오늘 날짜의 Date 객체를 생성하고, 올해와 이번 달을 구해서 이번 달 날짜 데이터를 만드는 함수에 인자로 넘겨주겠습니다. 스크립트는 아래와 같습니다.

그럼 이제 이번 달의 날짜를 만드는 함수를 살펴봐야겠죠? 이 함수는 어떻게 구현되어있는지 간략하게 설명해보겠습니다.

  1. 빈 문자열을 만든 후 이번 달의 첫째 날, 첫째 요일, 마지막 날을 구하고 지난 달의 마지막 날을 구합니다.
  2. 매달 전체 일수가 달라지므로 날짜 수를 세기 위한 변수를 만들고 초기화합니다.
  3. 1~5주차 / 일요일~토요일을 세기 위한 반복문을 만듭니다.
  4. 반복문 안에서 첫째 주 시작 요일 이전일 때, 첫째 주 시작 요일일 때, 첫째 주 시작 요일 이후 일 때, 마지막 주 마지막 요일 이전일 때, 마지막 주 마지막 요일 이후일 때의 5가지 조건으로 나누어 날짜를 계산합니다.
  5. 해당 조건 마다 날짜를 계산한 후 이 날짜를 고유한 ID로 가진 HTML tag 문자열을 만들고 기존에 만들었던 빈 문자열에 이어붙입니다.
  6. 달력이 렌더링 될 div 태그에 만들어진 문자열을 붙여줍니다.

자 여기까지 하면 어떻게 나오는 지 볼까요?

이번 달의 전체 날짜가 출력되는 걸 확인하셨나요? 하지만 날짜만으로는 달력이 될 수 없겠죠?

스타일링을 통해 예쁜 달력으로 뒤바꿔보겠습니다. 기존에 태그를 만들면서 지정해놨던 ID 외에 클래스들을 추가합니다. 그리고 각 조건이 어떤 부분을 생성하는 지 명확하게 알기 위해, background-color 속성을 각각 다르게 주었습니다.

자, 위의 코드를 실행하면 어떻게 되는지 볼까요?

어떤가요? 예쁜 달력이 만들어진 걸 확인하셨나요?

이제 이 달력에 원하는 요소들을 넣어서 커스텀하시면 됩니다. 날씨 아이콘을 넣어도 되고, 보여주길 원하는 정보들을 입력해도 되죠!

만약 이번 달뿐만 아니라 올해의 모든 달을 보여주고 싶다면, 이전 달과 다음 달로 이동하는 버튼을 만들고 버튼을 누를 때마다 새로운 달력을 생성해서 보여주면 되겠죠? 버튼과 클릭 이벤트만 추가하면 올해의 달력을 모두 볼 수 있겠네요 😍

반응형

Javasciprt와 JQeury를 이용한 달력 만들기입니다.

날짜를 클릭 시 input type="text"에 날짜가 입력되도록 구현하였습니다.

달력을 구현하는 script부분을 제외하곤 나머지 부분은 적절히 수정하여 사용하시기 바랍니다.

 

자바 스크립트 달력 만들기 - jaba seukeulibteu dallyeog mandeulgi

 

HTML

<div class="calendar">
	<div class="header">
		<button class="calendar_btn" onclick="prevCal();">&lt;</button>
		<div class="title"><span class="year"></span><span class="month"></span></div>
		<button class="calendar_btn" onclick="nextCal();">&gt;</button>
	</div>
	<div class="day">
		<div>S</div>
		<div>M</div>
		<div>T</div>
		<div>W</div>
		<div>T</div>
		<div>F</div>
		<div>S</div>
	</div>
	<div class="dates"></div>
</div>
<input type="text" id="period_1"> ~ <input type="text" id="period_2">

 

Javascript & JQuery

<script type="text/javascript">
var CDate = new Date(); 
var today = new Date();
var selectCk = 0;

var buildcalendar = function(){
	var htmlDates = ''; 
	var prevLast = new Date(CDate.getFullYear(), CDate.getMonth(), 0); //지난 달의 마지막 날 
	var thisFirst = new Date(CDate.getFullYear(), CDate.getMonth(), 1); //이번 달의 첫쨰 날
	var thisLast = new Date(CDate.getFullYear(), CDate.getMonth() + 1, 0); //이번 달의 마지막 날
	document.querySelector(".year").innerHTML = CDate.getFullYear() + "년";  // year에 년도 출력
	document.querySelector(".month").innerHTML = (CDate.getMonth() + 1) + "월";  //month에 월 출력
	const dates = []; 
	if(thisFirst.getDay()!=0){ 
		for(var i = 0; i < thisFirst.getDay(); i++){
			dates.unshift(prevLast.getDate()-i); // 지난 달 날짜 채우기
		} 
	} 
	for(var i = 1; i <= thisLast.getDate(); i++){
			 dates.push(i); // 이번 달 날짜 채우기 
	} 
	for(var i = 1; i <= 13 - thisLast.getDay(); i++){ 
			 dates.push(i); // 다음 달 날짜 채우기 (나머지 다 채운 다음 출력할 때 42개만 출력함)
	} 
	
	for(var i = 0; i < 42; i++){
		if(i < thisFirst.getDay()){
			htmlDates += '<div class="date last">'+dates[i]+'</div>'; 
		}else if(today.getDate()==dates[i] && today.getMonth()==CDate.getMonth() && today.getFullYear()==CDate.getFullYear()){
			 htmlDates += '<div id="date_'+dates[i]+'" class="date today" onclick="fn_selectDate('+dates[i]+');">'+dates[i]+'</div>'; 
		}else if(i >= thisFirst.getDay() + thisLast.getDate()){
			 htmlDates += '<div class="date next">'+dates[i]+'</div>'; 
		}else{
			htmlDates += '<div id="date_'+dates[i]+'" class="date" onclick="fn_selectDate('+dates[i]+');">'+dates[i]+'</div>'; 
		}
	 } 
document.querySelector(".dates").innerHTML = htmlDates; 
} 

function prevCal(){
	 CDate.setMonth(CDate.getMonth()-1); 
	 buildcalendar(); 
} 
function nextCal(){
	 CDate.setMonth(CDate.getMonth()+1);
	 buildcalendar(); 
}

function fn_selectDate(date){
	
	var year = CDate.getFullYear();
	var month = CDate.getMonth() + 1;
	var date_txt = "";
	if(CDate.getMonth + 1 < 10){
		month = "0" + (CDate.getMonth() + 1);
	}
	if(date < 10){
		date_txt = "0" + date;
	}
	
	if(selectCk == 0){
		$(".date").css("background-color", "");
		$(".date").css("color", "");
		$("#date_"+date).css("background-color", "red");
		$("#date_"+date).css("color", "white");
		
		$("#period_1").val(year+"-"+month+"-"+date);
		$("#period_2").val("");
		selectCk = date;
	}else{
		$("#date_"+date).css("background-color", "red");
		$("#date_"+date).css("color", "white");		
		for(var i = selectCk + 1 ; i < date ; i++){
			$("#date_"+i).css("background-color", "#FFDDDD");
		}
		
		$("#period_2").val(year+"-"+month+"-"+date);
		selectCk = 0;
	}
	
}

buildcalendar();
</script>

 

CSS

.calendar {width: 400px; padding: 5px 20px 20px 20px; box-sizing: border-box; border: 1px solid;}
.calendar > .header {text-align: center;}
.calendar > .header > .title {width:50%; display: inline-block;}
.calendar > .header > .calendar_btn {
	width: 30px;
	height: 30px;
	border: none;
	padding: 0;
	background-color: #ffffff;
	vertical-align: middle;
	color: black;
}
.calendar > .day {width:100%; display: table; table-layout: fixed;}
.calendar > .day > div {display: table-cell; text-align: center; height: 50px; vertical-align: middle;}
.calendar > .day > div:first-child {color: red;}
.calendar > .day > div:last-of-type {color: blue;}
.calendar > .dates {display: flex; flex-wrap: wrap; width: 100%;}
.calendar > .dates > .date {text-align: center; width: calc(100%/7); height: 50px; box-sizing: border-box;line-height: 3; border-radius: 3px;} 
.calendar > .dates > .date:nth-child(7n){color: blue;}
.calendar > .dates > .date:nth-child(7n+1){color: red;}
.calendar > .dates > .last {color: #c8c8c8 !important;}
.calendar > .dates > .next {color: #c8c8c8 !important;}

 

 

반응형

공유하기

게시글 관리

구독하기HyuniPad

저작자표시

  • 카카오스토리
  • 트위터
  • 페이스북

'Programming > Web' 카테고리의 다른 글

[Network] 3-way handshake, 4-way handshake의 개념 및 동작 원리  (0)2022.03.13세션(Session), 쿠키(Cookie), JWT(JSON Web Token) 의 개념 및 차이점  (0)2022.03.12CSS 프로그레스 바(progress bar)  (0)2021.10.12<button> 버튼 태그가 작동 안될 때  (0)2021.10.10CSS 테두리만 있는 말풍선 그리기  (0)2021.10.10