1. 개요
만들면서 포스팅 하는 것을 잊고 있었다. 다른 블로그를 참고해서 달력 기능을 구현했다.
2. HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Anton&display=swap" rel="stylesheet">
<title>Calendar & To-do List</title>
<script src="https://kit.fontawesome.com/a7ac1b0a6e.js" crossorigin="anonymous"></script>
</head>
<body>
<!-- 좌측 To-to list -->
<div class="todo_conatiner">
<h3 class="todo_date">2021.05.08 토요일</h3>
<div class="todo_list_container">
<ul clas="todo_list">✅</ul>
</div>
</div>
<!-- 우측 Calendar -->
<div class="calendar_container">
<nav class="month_container">
<i class="fas fa-arrow-circle-left prev_month"></i>
<h3 class="this_month">2</h3>
<i class="fas fa-arrow-circle-right next_month"></i>
</nav>
<div class="day_container">
<div class="days">Sun</div>
<div class="days">Mon</div>
<div class="days">Tue</div>
<div class="days">Wed</div>
<div class="days">Thu</div>
<div class="days">Fri</div>
<div class="days">Sat</div>
</div>
<div class="date_container">
날짜
</div>
</div>
</body>
<script src="main.js"></script>
</html>
자바스크립트로 달력 기능만 완성된 상태이나, to-do list도 일단 마크업은 해 두었다.
3. CSS
/* 전체 레이아웃 */
body {
display: flex;
border: 2px solid #227093;
border-radius: 4px;
font-family: 'Anton', sans-serif;
}
.todo_conatiner, .calendar_container {
width: 50%
}
/* to-do list 레이아웃 */
.todo_date {
text-align: center;
color: #1e272e;
}
/* calendar 레이아웃 */
.month_container {
display: flex;
margin: 20px 0px;
justify-content: center;
align-items: center;
}
.month_container > .this_month {
margin: 0%;
flex: 0.9;
text-align: center;
color: #1e272e;
font-size: 24px;
}
.month_container > .prev_month {
/* flex: 1; */
/* padding-left: 30px; */
color: #1e272e;
cursor: pointer;
font-size: 24px;
}
.month_container > .next_month {
/* flex: 1; */
text-align: right;
/* padding-right: 30px; */
color: #1e272e;
cursor: pointer;
font-size: 24px;
}
.day_container {
display: flex;
margin: 20px 0px;
}
.day_container > .days {
flex: 1;
text-align: center;
color: #1e272e;
}
.day_container :nth-child(7n+1) {
color: #eb3b5a;
}
.day_container :nth-child(7n+7) {
color: #3867d6;
}
.date_container {
display: flex;
flex-wrap: wrap;
}
.date_container > .dates {
width: calc(100%/7);
text-align: center;
margin: 20px 0px;
}
.date_container > .transparent {
opacity: 0.3;
}
.date_container :nth-child(7n+1) {
color: #eb3b5a;
}
.date_container :nth-child(7n) {
color: #3867d6;
}
.holiday {
color: #eb3b5a;
}
nth-child를 활용해서 모든 7n+1번째 요소에는 빨간색, 7n번째 요소에는 파란색을 추가했다.
4. Javascript: 기준 월 만들기
const now = new Date();
let year = now.getFullYear();
let month = now.getMonth();
const prevLast = new Date(year, month, 0);
const prevLastDate = prevLast.getDate();
const prevLastDay = prevLast.getDay();
const thisLast = new Date(year, month + 1, 0);
const thisLastDate = thisLast.getDate();
const thisLastDay = thisLast.getDay();
이번 달을 기준으로 만들기 위해 필요한 데이터들을 변수에 할당했다. year과 month는 달력을 이동시킬 때 재할당이 필요하므로 let으로 할당했다. 달력의 날짜들을 표시하기 위해 필요한 것들은, 지난 달의 마지막 일에 대한 정보와 이번 달의 마지막 일에 대한 정보이므로, 이들을 각각의 변수에 할당했다.
const thisMonth = document.querySelector('.this_month');
function expressMonth() {
thisMonth.innerText = `${year}. ${month + 1}`;
}
expressMonth();
먼저 상단 중앙부에 이번 달에 대한 정보를 표시한다. 간단하게 innerText를 사용했다.
function getPrevDates() {
const prevLast = new Date(year, month, 0);
const prevLastDate = prevLast.getDate();
const prevLastDay = prevLast.getDay();
const prevDates = [];
if (prevLastDay != 6) {
for (i = 0; i < prevLastDay + 1; i++) {
prevDates.unshift(prevLastDate - i);
}
}
return prevDates;
}
이번 달의 달력에는, 지난 달의 마지막 주도 표시되므로, 그 데이터를 가져오기 위해 지난 달의 마지막 날에 대한 정보를 바탕으로 조건문을 작성했다. 지난 달의 요일(day)이 토요일(6)인 경우에는 지난 달의 마지막 주의 정보가 필요없으므로, prevLastDay가 6이 아닌 경우에만 for 반복문을 이용한다. 지난 달의 마지막 날의 요일보다 작을 때, 그 날짜를 unshift를 통해 prevDates 배열의 앞에서부터 채워 넣는다.
function getThisDates() {
const thisLast = new Date(year, month + 1, 0);
const thisLastDate = thisLast.getDate();
const thisDates = [...Array(thisLastDate + 1).keys()].slice(1);
return thisDates;
}
이번 달의 일자들도 구해서 thisDates 배열에 채워 넣는다. Array.prototype.keys()는 배열의 각 인덱스를 키 값으로 가지는 Array Iterator 객체를 반환한다. Array(n)에서 n이 정수라면, 길이가 n인 배열을 반환한다. 즉, thisDates는 이달의 마지막 날짜가 30일이라면, 길이가 31인 배열을 반환하고, 각 인덱스, 즉 0~30까지를 키 값으로 가지는 Array Iterator 객체를 반환하게 된다. 이를 [...]을 이용해 0~30의 숫자가 담긴 배열로 만들고, 슬라이스로 0을 제거한다.
function getNextDates() {
const thisLast = new Date(year, month + 1, 0);
const thisLastDay = thisLast.getDay();
const nextDates = [];
if (thisLastDay != 6) {
for (i = 0; i < 6 - thisLastDay; i++) {
nextDates.push(i + 1);
}
}
return nextDates;
}
다음 달의 일자들을 구할 때는, 이전 달의 일자를 구할 때와 마찬가지로 이번 달의 마지막 날이 토요일이 아닐 경우에 한하여 반복문을 이용한다.
function expressDates() {
const prevDates = getPrevDates();
const thisDates = getThisDates();
const nextDates = getNextDates();
const dateContainer = document.querySelector('.date_container');
const modifiedPrevDates = prevDates.map(prevdate => `<div class="dates transparent">${prevdate}</div>`).join('');
const modifiedThisDates = thisDates.map(thisdate => `<div class="dates">${thisdate}</div>`).join('');
const modifiedNextDates = nextDates.map(nextdate => `<div class="dates transparent">${nextdate}</div>`).join('');
dateContainer.innerHTML = modifiedPrevDates + modifiedThisDates + modifiedNextDates;
}
expressDates();
이렇게 이전 달의 마지막주 일자들, 이번 달의 모든 일자들, 다음 달의 첫주 일자들을 표시하고, 이전 달과 다음 달의 일자들에는 transsparent 클래스 속성을 추가로 부여함으로써 이번 달의 일자에 비해 약간 투명하게 만든다.
5. Javascript: 이전 월, 다음 월로 이동
const arrowsToPrevMonth = document.querySelector('.prev_month');
const arrowsToNextMonth = document.querySelector('.next_month');
function goToPrevMonth() {
}
function goToNextMonth() {
}
arrowsToPrevMonth.addEventListener('click', goToPrevMonth);
arrowsToNextMonth.addEventListener('click', goToNextMonth);
화살표를 누르면 각각 이전 달과 다음 달로 이동할 수 있도록 선택하여 변수에 할당한다.
function goToPrevMonth() {
if (month > 0) {
month = month - 1;
} else {
month = month + 11;
year = year - 1;
}
expressMonth();
getPrevDates();
getThisDates();
getNextDates();
expressDates();
experssHolidays();
}
이전 달로 이동하는 함수는, 클릭에 반응해 month에 1을 더해 준다. month가 0보다 크지 않다면 이전 년도로 이동하게 된 것이므로 year에서 1을 빼고 month에는 11을 더해 초기화한다. 이렇게 month와 year의 값을 재할당한 뒤, 4에서 만든 기능이 재실행되도록 한다.
function goToNextMonth() {
if (month < 11) {
month = month + 1;
} else {
month = month - 11;
year = year + 1;
}
expressMonth();
expressMonth();
getPrevDates();
getThisDates();
getNextDates();
expressDates();
experssHolidays();
}
다음 달로 이동하는 함수도 마찬가지 원리로 만들 수 있다.
6. 개선점
- 공휴일을 표시하는 함수를 만들고 있는데, 두 가지 문제가 발생하여 아직 완성하지 못했다.
- 토요일이 공휴일인 경우, 빨간색으로 덮어씌워지지 않는 점, 공휴일이 이틀 이상인 경우 표시되지 않는 점이다.
- 각 일자에 클릭 이벤트를 걸어, 왼쪽의 to-do list에 내용을 입력하고 로컬 저장소에 저장되도록 할 예정이다.
- 추가적으로, 화면을 줄이면 위쪽은 달력, 아래쪽은 to-do list가 나올 수 있도록 반응형으로 제작할 예정이다.
[Javascript] Calendar & To-do List ③Express Holidays (0) | 2021.05.13 |
---|---|
[Javascript] Calendar & To-do List ①planning (0) | 2021.05.06 |
댓글 영역