라이브러리 없이 캘린더, 달력 만들기 입니다.
만들다 보니 라이브러리를 왜써야 하는지 알겠습니다.
대략 4일 정도 소요가 되었는데요 완벽하지는 않습니다.
라이브러리 없이 달력 만들기
전체적인 코드는 제 깃허브 주소에서 볼수 있습니다.
https://github.com/leemj0948/calendar.git
대략적인 페이지 UI는 이렇게 생겼습니다.
애플 캘린더와 비슷하게 구현하였습니다.
전체적 포인트는
https://bigtop.tistory.com/66
아래 블로그를 참고하였습니다.
자바스크립트로 달력을 만드는데 응용하여 리액트에 적용하였습니다.
cra를 통해서 리액트 초기 설정을 하였습니다. (초기설정은 생략합니다)
라이브러리 없이 만드는 캘린더 입니다.
styled-component를 사용했습니다.
메인 컴포넌트를 랜더링 하는데 메인 컴포넌트는
헤더와 바디 두 부분으로 나눴습니다.
헤더 구성은 년도와 월 그리고 좌우 클릭, 오늘 , 요일로 나뉘어 집니다.
각 원하는 디자인으로 구성하면 됩니다.
전체를 다룰수 없기 때문에 중요 부분만 코드로 작성해보도록 하겠습니다.
useState를 사용하여 Date함수를 사용해 전달해 주었습니다.
요일을 배열로 만들어서 map함수를 사용하여 만들었습니다.
각 요일 컴포넌트에
width: calc(100% / 7); 를 주면 너비100%를 7로 나눈 값으로
width가 생성되어 비율이 일정하게 조절됩니다.
li 태그를 사용하여 css를 주었습니다.
<BtnBox>
<Btn onClick={() => setMonth(month - 1)}><</Btn>
<Btn width="3vw" onClick={() => goToday()}>
오늘
</Btn>
<Btn onClick={() => setMonth(month + 1)}>></Btn>
</BtnBox>
헤더는 쉽게 구성할수 있습니다.
미흡하게도 아직 년도가 변경되도록 구현이 안됩니다.
리덕스를 활용하여 구현하였는데
리덕스를 사용하지 않으면 12월 이후에 13월로 가게 됩니다.
날짜가 들어가는 부분입니다.
이전 날짜와 다음달 날짜가 같이 보여야 하기 때문에
계산이 필요합니다.
상위 컴포넌트인 main에서 계산 함수를 작성하였고 state에 담아서 자식 컴포넌트에게 전달해주었습니다.
함수 전체는 아래와 같습니다.
const changeDate = (month) => {
//이전 날짜
let PVLastDate = new Date(YEAR, month - 1, 0).getDate();
let PVLastDay = new Date(YEAR, month - 1, 0).getDay();
//다음 날짜
const ThisLasyDay = new Date(YEAR, month, 0).getDay();
const ThisLasyDate = new Date(YEAR, month, 0).getDate();
//이전 날짜 만들기
let PVLD = [];
if (PVLastDay !== 6) {
for (let i = 0; i < PVLastDay + 1; i++) {
PVLD.unshift(PVLastDate - i);
}
}
//다음 날짜 만들기
let TLD = [];
for (let i = 1; i < 7 - ThisLasyDay; i++) {
if (i === 0) {
return TLD;
}
TLD.push(i);
}
//현재날짜
let TD = [];
TD = [...Array(ThisLasyDate + 1).keys()].slice(1);
return PVLD.concat(TD, TLD);
};
이전 날짜
let PVLastDate = new Date(YEAR, month - 1, 0).getDate();
let PVLastDay = new Date(YEAR, month - 1, 0).getDay();
변수를 생성해줍니다. new Date에 미리 저장한 YEAR값과 month 값을 넣어주고 변수를 생성해줍니다.
getDate() 함수는 날짜 , 일 을 반환해 줍니다.
getDay() 함수는 요일을 반환해 줍니다.
Sunday - Saturday : 0 - 6
일요일은 0을 반환합니다.
이전 날짜 만들기
let PVLD = [];
if (PVLastDay !== 6) {
for (let i = 0; i < PVLastDay + 1; i++) {
PVLD.unshift(PVLastDate - i);
}
}
일요일 부터 토요일까지 0~6까지 범위를 잡고
배열을 만들어둔 곳에 해당 월의 일수들을 unshift를 사용하여
하나씩 축적해 줍니다.
//다음 날짜
const ThisLasyDay = new Date(YEAR, month, 0).getDay();
const ThisLasyDate = new Date(YEAR, month, 0).getDate();
이전 날짜와 비슷하게 다음 날짜도 변수를 만들어 요일과 일을 받습니다.
//다음 날짜 만들기
let TLD = [];
for (let i = 1; i < 7 - ThisLasyDay; i++) {
if (i === 0) {
return TLD;
}
TLD.push(i);
}
반복 문으로 마지막날 이전날까지 반복시키고 그 값들을 배열에 담아둡니다.
그리고 현재값을 만들어서 담으면 되는데요
//현재날짜
let TD = [];
TD = [...Array(ThisLasyDate + 1).keys()].slice(1);
현재 날짜는 1일 부터 그날의 날짜들을 다 받아서 배열에 담아두었습니다.
return PVLD.concat(TD, TLD);
그리고 이전달의 날짜들에게 현재 날짜와 다음날짜를 더해서 새로운 배열로 리턴해줍니다.
함수로 담아준 이유는 달이 변경될때마다 새로운 값들을 그려야 하기 때문입니다.
데이터를 담아서 전달해 주어야 하는데 달마다 데이터를 다시 그려야 하니 useEffect를 실행해줍니다.
초기 설정
useEffect(() => {
setTotalDate(changeDate(7));
}, []);
초기로 뿌려줄 값인데 7월에 작성해서 7로 일단 작성해두었습니다.
New Date 를 해서 달 값을 변수로 저장해서 넣어놓으면 유동적으로
사용할수 있겠죠
useEffect(() => {
setTotalDate(changeDate(month));
}, [month]);
다음 달 이 변경될때마다 함수를 호출하여 새로운 달을 그려서 state값에 넣어줍니다.
그리고 map함수를 활용하여 뿌려주는 작업을 하였습니다.
이렇게 하면 기본적인 캘린더가 완성 됩니다.
위와 같은 방법을 이해하면 오늘로 복귀하는 것은 쉬운 방법입니다.
오늘의 달을 알아서 새로 그려주고 오늘 날짜에 색을 입혀주면 되는 작업이거든요
저는 goToday함수를 만들어 주었습니다.
const goToday = () => {
let TODAY = new Date().getDate();
let goMonth = new Date().getMonth() + 1;
setMonth(goMonth);
setToday(TODAY);
};
쉽게 달을 받아서 새로 날짜를 그려주고 오늘 일을 찾아줍니다.
오늘일(Date)을 전달 받아서 CSS를 변경해주면 됩니다.
저같은 경우는
findToday={findToday === idx && month === getMonth && findToday}
map에서의 index와 today값이 같을 경우, 달이 같을경우 값을 전달해주도록 설정하였습니다.
그렇다면 기본적인 기능을 하는 달력을 만들수 있습니다.
이전달 다음 달 눌렀을 경우 달이 이동이 되며 오늘 버튼을 클릭하면 붉게 선택이 됩니다.