바닐라 JS로 캘린더 만들기

지현·2023년 1월 27일
11

Javascript / TypeScript

목록 보기
10/16
post-thumbnail

🌱 시작하며 & 디자인

부트캠프 수료 후 게으른 일상을 보내고 있는 어느날 이렇게 살면 안 된다는 생각이 들어 할 일을 적어내려가는 투두리스트를 작성하려고 했다. 그런데 문득 내가 쓰는 투두리스트 엡을 내 손으로 만들면 재밌을 것 같다는 생각이 들어 당장 만들기 시작했다.

리액트를 이용해서 만들어볼까? 하는 생각도 했지만 굳이 한 페이지 짜리 웹에서 리액트를 쓸 필요성을 느끼지 못했다. 그리고 플젝을 하면서 리액트 위주로 쓰다보니 또 바닐라JS가 어색해지는 무한의 굴레에서 벗어나기 위해 이번 캘린더-투두리스트는 바닐라JS로만 만들어보기로했다. (그리고 사실 내 노트북에서 리액트 파일 켜는데만 한 세월이라 조금 부담스럽다 ㅠ..)

얼추 이런 느낌의 단순히 캘린더와 투두리스트를 합친 할 일 관리 웹을 만들고 싶었다.

후에 구체적인 색상이나 레이아웃을 정하기 위해 피그마를 켜서 적당히 네모네모하게 만들었다. 딱히 다른 기능은 당장 생각이 안나서 우선 이 정도로만 정해놓고 vscode를 켰다.

🗓️ 캘린더 만들기 시작


위 피그마와 큰 차이 없어 보이지만 완성한 것이다.

아직 캘린더만 만들었는데 모든 기능을 다 만들고 블로그를 쓰려하니 까먹을 것 같아 캘린더 코드만 써보려고 한다.

해당 코드는 17분 안에 자바스크립트로 달력 만들기 << 이 영상을 참고하여 만들었다. 처음부터 혼자 만들어야 더욱 의미있겠으나 그러다가 막히면 영영 놔버릴 것 같아 완성에 의의를 두고 시작하기로 했다. 코드를 이해하면서 진행하고 싶었기 때문에 주석이 가득하다.

🏗️ index.html 中 캘린더 부분

<section class='cal'>
  <div class='header'>
    <button class="nav-btn go-prev" onclick='prevMonth()'>&lt;</button>
    <div class="year-month"></div>
    <button class="nav-btn go-next" onclick='nextMonth()'>&gt;</button>
    <button class="nav-btn go-today" onclick='goToday()'>Today</button>
   </div>
   <div class='main'>
     <div class="days">
       <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>
</section>

캘린더 부분의 마크업이다. 원래는 nav를 이용하여 월 이동과 오늘날짜로 이동하는 방식이었으나 nav를 없애버렸다.

📜 calIndex.js (캘린더 script파일)

✨ 날짜 가져오기

달력을 보여주는 renderCalendar 함수를 만들고 그 안에서 달력을 보여주는 코드를 짠다

  • new Date() 를 이용해 오늘 날짜를 가져온다
  • 현재 연월을 표시하는 viewYearviewMonth 를 만들고 연과 월만 각각 할당한다. (getMonth는 0부터 시작이므로 이번달을 구하려면 +1 해줘야한다)
  • 화면에 textContent를 이용하여 '2022년 1'월 과 같은 형태로 출력한다
  • 달력에는 이번달만 있는게 아니라 이전달과 다음달이 흐리게 표시될 예정이므로 지난달 마지막날과 이번달 마지막날을 구해준다.

✨ 지난달, 이번달, 다음달 달력 배열 만들고 합치기

각각의 배열을 만들어준 후 합쳐준다

  • const thisDates = [...Array(TLDate + 1).keys()].slice(1) 에서 인덱스는 0부터 시작하므로 TLDate에 +1 해주어 요소 하나가 추가된 배열을 만들고, slice(1) 을 이용해 1일부터 마지막날까지의 배열로 만든다.
  • 지난달 마지막 요일이 토요일이 아니면 (요일 시작이 일요일부터니까) 지난달 날짜들을 넣어준다
  • concat으로 지난달 이번달 다음달 배열을 합쳐준다.

✨ 화면에 날짜 뿌려주기

  • date의 인덱스가 이번달 1일 인덱스보다 크거나 같고 막날 인덱스보다 작으면 this, 아니면 other 클래스를 부여한다. 다른달은 opacity 흐리게 해주기 위함
  • forEach 이용하여 dates 배열의 item을 각각의 div 태그에 뿌려준다.
  • <div class='dates'></div> 안에 innerHTML 이용하여 dates 배열을 string으로 출력한다.

✨ 오늘 날짜 표시하기

  • 지금 보고있는 달력이 이번년 이번달 달력이면 this라는 클래스를 갖고있는 값을 돌려서, date의 text가 오늘 날짜와 같으면 (string에 + 붙여줘서 type을 number로 바꿔줌) today라는 클래스를 붙여준다
  • break 이용해서 조건 충족되면 반복문 빠져나오기
  • 그럼 오늘 날짜에만 today 클래스가 붙으므로 이렇게 스타일을 따로 지정해줄 수 있다.

✨ 캘린더출력 함수 실행하고 이전달 다음달로 이동하기

  • renderCalendar() 로 캘린더 출력 함수 실행하기
  • Date.prototype.setMonth() : setMonth () 메서드는 현재 설정된 연도에 따라 지정된 날짜의 월을 설정할 수 있다

🎉 마치며

코드를 보면 그렇게 이해가 안 될 만한 코드는 아닌데 스스로 생각하기에는 아직 너무 어려운 것 같다.. 예전에 라이브러리로 달력을 불러온 적이 있는데 이렇게 라이브러리 없이 바닐라js로만 만들어보니 생각해야할게 많아서 놀랐다.
나중에 원하는 연월일로 가는 기능(갤럭시 기본 캘린더앱처럼)이나 여러날에 걸친 일정 기능도 추가해보고싶다.

1개의 댓글

comment-user-thumbnail
2023년 2월 28일

멋있습니다!! 저도 구현해보고 싶네요!

답글 달기