본문 바로가기

JS

[Vanilla/JavaScript]캘린더 만들기

Calender 만들기

JS연습 겸 간단한 캘린더를 만들어볼까 합니다. 파일들은제 github홈페이지에 저장해 놓을테니 참고해주세요. 이 코드가 꼭 정답이 아닙니다. 더 좋은 코드가 있을 수 있습니다.

기능 구상

  • 달력을 출력합니다. 년도제한은 없습니다.
    • 달력은 6줄로 나오게 합니다.(총 7*6일이 나올 수 있게 합니다.)
    • 토, 일은 다른 색상을 주어서 표시합니다.
  • 현재날짜에는 테두리를 주어서 현재 날짜를 알 수 있게 합니다.
  • 기본적으로 오늘 날짜가 있는 달력이 나오게 하고 이전, 이후 달력을 볼 수 있는 기능을 만듭니다.
    • 이에따라 그 달력의 년도와 월을 표시해줍니다.

이 정도 기능을 염두해 두고 캘린더를 본격적으로 만들어보겠습니다. html과 css를 바탕으로 만든 캘린더 디자인은 다음과 같습니다.

캘린더 디자인

캘린더를 만들었을 당시가 12월 17일이라 2020년 12월 달력이 나오고 17일에 분홍빛 테두리가 들어간 것을 볼 수 있습니다. 먼저 캘린더 구조를 잡아봅시다.
index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link href="https://fonts.googleapis.com/css2?family=Raleway&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
  <title>Calender</title>
</head>
<body>
  <div class="calender">
    <div class="header">
      <button class="prevBtn" onclick="prevCal()">prev</button>
      <div class="title">
        <div class="yearTitle"></div>
        <div class="monthTitle"></div>
      </div>
      <button class="nextBtn" onclick="nextCal()">next</button>
    </div>
    <div class="main">
      <div class="daies">
        <div class="day">Sun</div>
        <div class="day">Mon</div>
        <div class="day">Tue</div>
        <div class="day">Wed</div>
        <div class="day">Thu</div>
        <div class="day">Fri</div>
        <div class="day">Sat</div>
      </div>
      <div class="dates"></div>
    </div>
  </div>
  <script type="text/javascript" src="calendar.js"></script>
</body>
</html>

<head>에 캘린더에서 사용할 폰트를 넣어주었습니다. 사용하실 분은 복사해서 본인 html파일의 <head>안에 넣으시면 됩니다.

  <link href="https://fonts.googleapis.com/css2?family=Raleway&display=swap" rel="stylesheet">

우선 html파일의 .calender의 구조를 보겠습니다. .calender안에는 prev(이전), next(이후)그리고 년, 월 정보가 들어갈 .header가 들어가 있습니다. .header안에 있는 .yearTitle.monthTitle은 아직 비어있지만 날에 맞는 년, 월을 스크립트를 통해서 넣어줄겁니다. .main에는 요일이 들어갈.daies와 날짜가 들어갈.dates가 있습니다. 스크립트를 실행해서 비어있는 .dates를 년, 월에 맞게 채워줄겁니다. 스크립트 태그는 </body>바로 위에 넣어줍시다.

이제 CSS를 작성해 봅시다.
style.css

:root {
    --bg-color: #F6F6F6;/*배경색*/
    --line-color: #aaaaaa;/*상단과 하단을 나눠줄 줄 색*/
    --sat-color: #FFE2E2;/*토요일 배경색*/
    --sun-color: #FFC7C7;/*일요일 배경색*/
    --today-color: #EFBBCF;/*오늘 날짜의 테투리색*/
    --font: 'Raleway';/*폰트 정의*/
}

body {
  /*padding과 margin을 없애고 body태그 전체에 배경색과 폰트를 넣어줍니다.*/
    padding: 0;
    margin: 0;
    background-color: var(--bg-color);
    font-family: var(--font);
}

button {
  /*버튼에는 따로 폰트를 적용시켜줘야됩니다.
      테두리선을 없애고 적당히 높이를 지정해줍시다.
  */
    font-family: var(--font);
    border:none;
    height: 32px;;
}

.header {
    display: flex;
    font-size: 48px;
    justify-content: space-around;/*아이템들을 일정한 간격으로 벌려 배치합니다.*/
    align-items: center;
    padding-bottom: 12px;
    margin: 12px 24px 12px 24px;
    border-bottom: 2px solid var(--line-color);/*header쪽과 달력을 구분하기 위해 밑에만 선을 넣어줍시다.*/
}

.title {
      /*년, 월이 세로로 정렬되게 하기 위함입니다.*/
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.main {
      /*요일과 날짜는 가로가아니라 세로로 정렬되야 하므로 flex-diretion: column;을 해줍시다.*/
    display: flex;
    flex-direction: column;
    margin: 12px 24px 0px 24px;
}
.daies {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
}
.dates {
      /*wrap을 주어서 한줄에 날짜가 7개만 나오게 만들겁니다.*/
    display: flex;
    flex-wrap: wrap;
    width: 100%;
}
.date, .day{
      /*width가 100/7을 가지기 때문에 한 줄에 7개의 날짜와 요일이 정렬됩니다.*/
    text-align: center;
    width: calc(100%/7);
    padding: 16px 0 16px 0;
    box-sizing: border-box;
}
.date:nth-child(7n),
.day:nth-child(7n) {
      /*.date와 .day의 7n번째 요소만 적용시킵니다. 즉 토요일의 세로줄만 적용합니다.*/
    background-color: var(--sat-color);
    color: blue;/*글자색입니다.*/
}
.date:nth-child(7n+1),
.day:nth-child(7n+1) {
      /*.date와 .day의 7n+1번째 요소만 적용시킵니다. 즉 일요일의 세로줄만 적용합니다.*/
    background-color: var(--sun-color);
    color: red;
}
.today {
      /*오늘 날짜에 테두리를 줍니다. !important로 border의 우선순위를 1순위로 만들 수 있습니다.*/
    border: 2px solid var(--today-color) !important;
}

CSS는 만드는 사람 나름이라고 생각하기 때문에 따라 하셔도 되고 더 좋은 방법이나 자신이 원하는 디자인이 있다면 그렇게 하시면 됩니다. 이제 제일 중요한 javascript코드를 확인해 봅시다.
calenser.js

let CDate = new Date();
let today = new Date();

buildCalender();

function buildCalender(){
    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++){
            dates.unshift(prevLast.getDate()-i);
        }
    }
    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 = '';
    for(let i = 0; i < 42; i++){
        if(today.getDate()==dates[i] && today.getMonth()==CDate.getMonth() && today.getFullYear()==CDate.getFullYear()){
            htmlDates += `<div class="date today">${dates[i]}</div>`;
        }
        else{
            htmlDates += `<div class="date">${dates[i]}</div>`;
        }
    }
    document.querySelector(".dates").innerHTML = htmlDates;
}

function prevCal(){
    CDate.setMonth(CDate.getMonth()-1);
    buildCalender();
}

function nextCal(){
    CDate.setMonth(CDate.getMonth()+1);
    buildCalender();
}

우선, 현재 월의 날짜만 출력해보는 걸 목표로 스크립트를 작성해봅시다. 우선 함수 buildCalender()를 만들고 안에 내용을 작성해 나가겠습니다. 자바스크립트에서 날짜에 관한 정보를 얻어오고자 하면 Date()객체를 이용해야 합니다. let calender = new Date();이런식으로 Date객체를 가진 변수를 만들어 줄 수 있습니다. 이 Date객체는 여러가지 메소드를 제공하는데 그중 몇가지를 알아보겠습니다.

let exdate = new Date();
console.log(exdate);
let year = exdate.getFullYear();//현재 년도 정보를 가져옵니다.
console.log(year);
let month = exdate.getMonth();//현재 월 정보를 가져옵니다. 
                              //0~11의 값을 가지기 때문에 12월의 경우 11이 반환되고 1월의 경우 0이 반환됩니다.
console.log(month);
let day = exdate.getDay();//현재 요일을 가져옵니다. 0(일요일)~6(토요일)의 값을 반환합니다.
console.log(day);
let date = exdate.getDate();//현재 날짜를 가져옵니다.
console.log(date);

이를 이용해서 현재월의 날짜를 꽉 채울 것입니다. 달력을 보면 현재월 뿐만 아니라 이전, 이후 월이 표시되어있는 것을 볼 수 있습니다. 이전, 이후 월을 알아내기 위해서 이전월의 마지막 날짜가 몇일, 무슨 요일인지(30일인지 31일인지, 2월의 경우 28혹은 29), 현재월의 첫번째 날짜와 마지막 날짜가 몇일이고 무슨요일인지 알 필요가 있습니다. 그래서 함수 buildCalender()안에 다음과 같은 변수 3개를 선언해 주었습니다.

let CDate = new Date();
function buildCalender() {
    let prevLast;
    let thisFirst;
    let thisLast;
}

new Date()안에는 여러가지 인자 값을 넣어줄 수 있습니다. 그 형식은 다음과 같습니다.

    new Date(year, monthIndex[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
    //new Date(년, 월, 일, 시간, 분, 초, 밀리초);

그렇다면 이전 월의 정보를 담고 있는 let prevLast를 만들기 위해서는 현재 월의 첫째 날에서 딱 하루 전으로 돌아가면 됩니다. new Date()에서 "일"(day값) 정보를 입력할 때 0을 입력하게 되면 그 월의 전월 마지막 날의 정보를 가져오게 됩니다. 따라서 변수prevLast는 다음 구조를 같습니다.

    let prevLast = new Date(CDate.getFullYear(), CDate.getMonth(), 0);//현재 년도와 현재 월을 넣어주고 일의 값을 0으로 합니다.

현재월의 첫째날은 "일" 값을 1로 주고 현재월의 마지막 날은 다음 월에서 "일" 값을 0으로 해주면 됩니다. 그렇게 이전 월의 마지막 날, 현재 월의 첫째 날과 마지막 날의 정보를 갖는 객체를 선언해보겠습니다.

let CDate = new Date();

function buildCalender(){
    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);
}

이 객체들을 이용해서 달력을 출력해 보겠습니다. 방법은 이러합니다.

  • 달력에 표시되는 이전 월의 날짜 구하기
  • 구한 이전 월의 날짜들에 현재 월의 날짜 붙이기
  • 6줄이 만들어지도록 나머지 날짜는 다음 월의 날짜로 채워주기
  • 완성된 날짜 정보를 바탕으로 각 날짜마다 html형식으로 바꿔주기
    • 현재 날짜(today)의 경우 today라는 클래스를 추가해서 다른 날짜와 구분해주기
  • html형식으로 바꾼 날자 정보들을 index.html에 넣어주기
    이를 다음과 같이 구현했습니다.
let CDate = new Date();
let today = new Date();

function buildCalender(){  
    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 today">${dates[i]}</div>`;//html형식으로 날짜 정보 저장  
        }  
        else{  
            htmlDates += `<div class="date">${dates[i]}</div>`;//html형식으로 날짜 정보 저장  
        }    
        document.querySelector(".dates").innerHTML = htmlDates;//htmlDates를 index.html의 .dates안에 넣는 작업  
    }
}

그렇다면 다음 월과 이전 월로 넘어가는 기능은 어떻게 구현을 할까요? 방법은 생각보다 간단합니다. 함수에서 이용된 현재 날짜의 정보를 가진 CDate를 살짝 수정해주면 됩니다. 이전 월은 현재 날짜에서 월의 값을 1 빼준 상태에서 buildCalender()함수를 수행하고 다음 월의 경우 현재 날짜에서 월의 값을 1 더해준 상태에서 buildCalender()함수를 돌리면 됩니다. 이렇게 말이죠.


function prevCal(){  
CDate.setMonth(CDate.getMonth()-1);  
buildCalender();  
}

function nextCal(){  
CDate.setMonth(CDate.getMonth()+1);  
buildCalender();  
}

이 두개의 함수를 Calender.js에 추가해주고 최초 달력 생성을 위해 처음에 한번만 buildCalender()함수를 실행해주면 달력이  잘 나오는 걸 확인할 수 있습니다. 오타나 피드백 댓글 환영합니다.

'JS' 카테고리의 다른 글

[Json/JavaScript]JSON 파싱 및 출력하는 법  (0) 2020.12.16
[JavaScript]투두 리스트 만들기  (0) 2020.12.15