본문 바로가기

FRONT-END/JavaScript & JQuery

캘린더 구현(자바스크립트)

해당 링크의 소스와 설명을 바탕으로 작성했고, 정리를 위해 쓰는 글

 

더보기
let CDate = new Date();
let today = new Date(); 

buildCalendar();

function buildCalendar(){
    let prevLast = new Date(CDate.getFullYear(), CDate.getMonth(), 0); //지난달 마지막날짜
    let thisFirst = new Date(CDate.getFullYear(), CDate.getMonth(), 1); //이번달 첫날
    let thisLast = new Date(CDate.getFullYear(), CDate.getMonth() + 1, 0); //이번달 마지막날
    document.querySelector(".yearTitle").innerHTML = CDate.getFullYear() +'년';
    //상단에 년도 출력
    document.querySelector(".monthTitle").innerHTML = CDate.getMonth() + 1 +'월';
    //상단에 월 출력 
    let dates = [];
    //현재 월 달력에 쓰일 날짜를 모을 배열 
    if(thisFirst.getDay()!=0){//만약 이번 월의 첫째날이 일요일이 아니라면 
        for(let i = 0; i < thisFirst.getDay(); i++){//일요일부터 이번 월의 요일까지 날짜를 구하기 위한 for문 
            dates.unshift(prevLast.getDate()-i);//이전 월의 마지막 날짜부터 1씩 빼가며 unshift(배열 앞에 값을 넣습니다.) 
        } 
    } for(let i = 1; i <= thisLast.getDate(); i++){//이번 월 날짜 구하기 
        dates.push(i); 
    } 
    for(let i = 1; i <= 13 - thisLast.getDay(); i++){//다음 월 날짜 구하기 
        dates.push(i); 
    }
    let htmlDates = '';//날짜 정보를 html형식으로 저장할 변수 
    for(let i = 0; i < 42; i++){//42일을 출력할 for문 
        if(today.getDate()==dates[i] && today.getMonth()==CDate.getMonth() && today.getFullYear()==CDate.getFullYear()){ //만약 년도, 월, 일이 똑같은 dates[i]값이 나오면 class에 today를 추가하기 위함. 
            //이를 이용해서 today표시
            htmlDates += `<div class="date choice-date"><span class="today">${dates[i]}</span></div>`;
        } else{
            htmlDates += `<div class="date choice-date">${dates[i]}</div>`
        } 
    document.querySelector(".dates").innerHTML = htmlDates;//htmlDates를 index.html의 .dates안에 넣는 작업 
    } //<i class="fas fa-exclamation-circle"></i>
}

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

 

 

1. 날짜 저장 변수 선언

let CDate = new Date(); //현재 날짜(currentDate)를 저장
let today = new Date();  //오늘 날짜를 저장

 

2. buildCalendar()

  1) 전월 마지막 날짜, 당월 첫날짜, 이번달 마지막날짜 구하기

let prevLast = new Date(CDate.getFullYear(), CDate.getMonth(), 0); //지난달 말일
let thisFirst = new Date(CDate.getFullYear(), CDate.getMonth(), 1); //이번달 1일
let thisLast = new Date(CDate.getFullYear(), CDate.getMonth() + 1, 0); //이번달 말일

getFullYear() : 자바스크립트에서 연도를 구하기 위한 웹 표준. getYear()은 1900을 뺀 수를 반환함(deprecated)

getMonth() :0~11까지의 수를 반환한다.

 

new Date(2021, 6, 0) :  2021년 6월의 마지막 날짜를 반환

  • 두번째 파라미터 : 0에서 시작해 11로 끝난다. 7월의 날짜를 얻고 싶다면 6을 지정해야 한다.
  • 마지막 파라미터를 1로 주면 이번 달 1일을  반환한다.
  • 마지막 파라미터를 0으로 주면 이전 달의 말일(이번달 1일-1)를 반환한다.

 

 

  2) 연도, 월 출력

 

document.querySelector(".yearTitle").innerHTML = CDate.getFullYear() +'년'; //상단에 연도 출력 document.querySelector(".monthTitle").innerHTML = CDate.getMonth() + 1 +'월'; //상단에 월 출력

innerHTML : 선택한 요소 안에 HTML(이 경우엔 텍스트)를 삽입한다. 

 

 

3) 달력에 들어갈 날짜를 배열에 채우기

 

let dates = []; //현재 월 달력에 쓰일 날짜를 모을 배열
if(thisFirst.getDay()!=0){   //만약 이번 월 1일이 일요일이 아니라면
       for(let i = 0; i < thisFirst.getDay(); i++){     //일요일부터 이번 월의 요일까지 날짜를 구하기 위한 for문                   
            dates.unshift(prevLast.getDate()-i);   //이전 월의 마지막 날짜부터 1씩 빼가며 unshift(배열 앞에 값을 넣습니다.)
       }
}
for(let i = 1; i <= thisLast.getDate(); i++){//이번 월 날짜 구하기
        dates.push(i);
}
for(let i = 1; i <= 13 - thisLast.getDay(); i++){  //다음 월 날짜 구하기 
       dates.push(i); }

getDay() : 요일을 반환, 반환값 0 ~ 6 (일~토)

getDate() : 일(수)를 반환, 반환값 DD

unshift() : 변수의 맨 앞에 새로운 배열값을 추가

push() : 변수의 맨 뒤에 새로운 배열값을 추가

 

달력은 한 주가 일요일로 시작해 토요일로 끝나는 일종의 형태를 지닌다.

1일이 아니라, 일요일에 해당하는 날짜(전월 날짜)로 시작된다는 것이다.

따라서 이번 달 1일이 일요일인지 아닌지를 먼저 파악하고, 일요일부터 달력을 채워나가야 한다.

  • unshift를 통해 오늘날짜에서 1을 빼가면서 배열의 앞단을 채운다.
  • 지난달 말일까지의 날짜가 채워졌다면, push를 통해 1일부터 말일까지 이번달 날짜를 채운다.
  • push를 통해 토요일까지 남은 칸을 채워나간다.
  • 13의 의미 : 1일이 일요일이라 1일부터 달력을 채워나가게 될 경우, 2월이라고 가정한다면 최대 13일까지 다음달의 날짜가 표시된다.  또한 getDay()의 반환값 중 일요일은 0이다. 28일이 일요일이라면 여전히 13일이 표시되게 하기 위해 1~(13-0)까지 배열에 날짜를 모아야한다.

 

4) 달력에 들어갈 날짜를 배열에 채우기

let htmlDates = ' ';   //날짜 정보를 html형식으로 저장할 변수. 일단은 빈문자열 입력
for(let i = 0; i < 42; i++){       //42일을 출력할 for문
     if(today.getDate()==dates[i] &&
         today.getMonth()==CDate.getMonth() && today.getFullYear()==CDate.getFullYear()){

                                               //만약 연, 월, 일이 같은 dates[i]값이 나오면 class에 today를 추가하기 위함.
                                              //이를 이용해서 today표시
          htmlDates += `<div class="date choice-date"><span class="today">${dates[i]}</span></div>`;
     } else {
          htmlDates += `<div class="date choice-date">${dates[i]}</div>`
     }
    document.querySelector(".dates").innerHTML = htmlDates;   //누적한 htmlDates를  .dates안에 넣는 작업
}

 

  • 달력은 전월과 익월의 날짜를 포함해 6주 (42일)로 이루어져있음

 

function prevCal(){ CDate.setMonth(CDate.getMonth()-1); buildCalendar(); }
function nextCal(){ CDate.setMonth(CDate.getMonth()+1); buildCalendar(); }
  • CDate.setMonth( ... ) : 현재 속해있는 날짜(CDate)의 월을 변경
  • prevCal() : 지난달 달력 보기
  • nextCal() : 다음달 달력 보기

 

 <form class="vacation-request-form" style="margin: auto; width:1000px" method="post">
            <div class="vac-q q1">
                <label for="vac-category">휴가 종류</label>
                <select id="vac-category">
                	<option value="연차">연차</option>
                    <option value="반차">반차</option>
                    <option value="병가">병가</option>
                </select>
            </div>
        <div class="vac-q q2">
            <label>휴가 기간</label>
            <div class="calendar cal-request">
                <div class="header cal-request-header">
                    <button class="prevBtn req-btn" onclick="prevCal()">
                    <i class="fas fa-angle-double-left"></i></button> 
                    <div class="title"> 
                        <span class="yearTitle req-year"></span>
                        <span class="monthTitle req-month"></span>
                    </div>
                    <button class="nextBtn req-btn" onclick="nextCal()">
                    <i class="fas fa-angle-double-right"></i></button>
                </div>
                <div class="calendar-main">
                    <div class="days">
                        <div class="day">일</div>
                        <div class="day">월</div>
                        <div class="day">화</div>
                        <div class="day">수</div>
                        <div class="day">목</div>
                        <div class="day">금</div>
                        <div class="day">토</div>
                    </div>
                    <div class="dates"></div>
                </div>
            </div>
        </div>
        <div class="vac-q q3"><label for="vac-period">휴가 일수</label>
        	<input type="text" id="vac-period">
        </div>
        <div class="vac-q q4"><label for="vac-reason">휴가 사유</label>
        	<input type="text" id="vac-reason">
        </div>
        <div class="vac-q q5"><span class="fileName">결재.png</span>
        	<input type="file" id="vac-prove" class="hiddenBtn">
            <label class="fileBtn button-three" for="vac-prove">증빙파일첨부</label>
        </div>
        <div class="vac-send"><button class="button-three">전송</button></div>
    </form>

 

캘린더 클릭이벤트

  • 해당 날짜 css 변화
  • 휴가기간 input에 날짜 자동 입력
  • 클릭 시 선택해제
  • 휴가기간 input에서 해당 날짜 제거(replace)
    • replace() 사용 시 유의점
      replace한다고 값이 바로 바뀌는 게 아니라 바뀐 값을 넣어줘야함. (이걸 몰라서 몇시간 삽질)

 

function readDate(target){
    target.style.background='var(--imp-color)';
    target.style.color = 'white';
    let cdate = (CDate.getMonth()+1)+'/'+target.innerText+' ';
    let input = document.getElementById('vac-period');
    if(input.value.includes(cdate)){
        target.style.background = 'transparent';
        target.style.color = 'var(--base-color)';

        console.log(str);
        input.value=document.getElementById('vac-period').value.replace(cdate,'');
    }
    else{
        input.value += cdate;
    }