날짜를 선택하는 캘린더를 적용하고 싶어서 react-datepicker 라이브러리를 사용하였다.
다양한 커스텀이 가능하며, 예제코드는 아래 공식사이트에서 확인할 수 있다.
설치
install
npm install react-datepicker --save
TypeScript
npm install --save @types/react-datepicker
적용
기본 Default 적용시
import { useState } from 'react';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
//scss 모듈적용
import styles from './calendarCommon.module.scss';
import classNames from 'classnames/bind';
const cx = classNames.bind(styles); //scss 모듈적용
export default function CalendarCommon() {
const [startDate, setStartDate] = useState<Date | null>(new Date());
return (
<div>
{/* <p className={styles['date-picker']}></p> */}
<p className={cx('date-picker')}></p>
<DatePicker
selected={startDate}
onChange={(date) => setStartDate(date)}
//커스텀
/>
</div>
);
}
커스텀
*달력:현재 보여지는 월말고 다른 월은 회색글자로 처리
css
.react-datepicker__day--outside-month {
color: #a8a8a8 !important;
pointer-events: none;
} //보여지는달력 해당월아닌 다른월 날짜는 회색컬러로 글자처리
+ 또 다른 커스텀 예제
<커스텀2>
import { forwardRef, useEffect, useState } from 'react';
import DatePicker, { registerLocale } from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import ko from 'date-fns/locale/ko';
import { getMonth, getYear, getDate } from 'date-fns';
import dayjs from 'dayjs';
import './calendarCustomThree.scss';
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
registerLocale('ko', ko); //날짜 한국어로 표시
const CustomInput = forwardRef((props: any, ref) => {
return (
<div className='calendar-input-wrap'>
<input {...props} ref={ref} type='text' />
<CalendarMonthIcon />
</div>
);
});
export default function CalendarCustomThree() {
const [startDate, setStartDate] = useState<Date | null>(new Date());
const _ = require('lodash');
registerLocale('ko', ko); //날짜 한국어로 표시
// 연도 선택 select box에 보여질 데이터 : range(시작 연도, 끝 연도, 연도 간격)
// const years = _.range(1990, getYear(new Date()) + 1, 1);
const years = _.range(getYear(new Date()) - 10, getYear(new Date()) + 1, 1);
// 월 선택 select box에 보여질 데이터
const months = [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
];
// const currentMonth = getMonth(new Date());
//선택날짜
const date = dayjs(startDate).format('YYYY-MM-DD');
// console.log(date);
return (
<div className='custom-wrap3'>
<DatePicker
//Input 커스텀
customInput={<CustomInput />}
//header 커스텀
renderCustomHeader={({
date,
changeYear,
changeMonth,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}) => (
<div
style={{
margin: 10,
display: 'flex',
justifyContent: 'center',
}}
>
<button onClick={decreaseMonth} disabled={prevMonthButtonDisabled}>
<ArrowBackIosIcon />
</button>
<select
value={getYear(date)}
onChange={({ target: { value } }) => changeYear(Number(value))}
className='selectbox'
>
{years.map((option: string) => (
<option key={option} value={option}>
{option}년
</option>
))}
</select>
<select
value={months[getMonth(date)]}
onChange={({ target: { value } }) =>
changeMonth(months.indexOf(value))
}
className='selectbox'
>
{months.map((option) => (
<option key={option} value={option}>
{option}월
</option>
))}
{/* 이렇게 하면 범위에 따라 나타나지만, 2023년에서 3월선택후 2013년 3월가면 select에서 7월부터 시작되도록 범위정했지만 3월로 인식되어짐 /사용 X
{getYear(date) === years[0]
? months.slice(currentMonth, 12).map((option) => (
<option key={option} value={option}>
{option}
</option>
))
: months.map((option) => (
<option key={option} value={option}>
{option}
</option>
))} */}
</select>
<button onClick={increaseMonth} disabled={nextMonthButtonDisabled}>
<ArrowForwardIosIcon />
</button>
</div>
)}
selected={startDate}
onChange={(date) => setStartDate(date)}
dayClassName={(d) => 'custom-day'}
dateFormat='yyyy.MM.dd'
disabledKeyboardNavigation //다른달에도 해당일자에 색표시되는거 제거
locale='ko' //한국어로 설정
//최소(minDate),최대날짜(maxDate) 범위 지정(바꿔도 됨)
//minDate : '최소 시작 날짜'를 적용해야 <이전버튼눌러도 안넘어가짐(select안에있는 년도랑 다를수있으니 범위 한정 짓기)
// minDate={new Date(`01-01-${getYear(new Date()) - 10}`)} //01-01-2013(월/일/현재년도에서-10) 기준으로 해놓음
minDate={
new Date(
`${getMonth(new Date()) + 1}-${getDate(new Date())}-${
getYear(new Date()) - 10
}`
)
} //현재 월, 현재 일, 지정 년도(현재에서 -10년전)/ex: 현재날짜가 07.19.2023이면 07.19.2013년으로 해놓음
maxDate={new Date()} //일단 현재날짜까지로 최대날짜 적용시킴
/>
</div>
);
}
CSS
.custom-wrap3 {
.react-datepicker__day--outside-month {
color: #a8a8a8 !important;
pointer-events: none;
} //보여지는달력 해당월아닌 다른월 날짜는 회색컬러로 글자처리
.react-datepicker__day-name {
width: 28px; //달력 요일
color: #fff;
}
.react-datepicker {
font-size: 1.2rem; //달력 글씨
}
.custom-day {
width: 28px;
height: 28px;
line-height: 2.8;
} //달력일
.react-datepicker__header {
background-color: rgb(64 123 128);
color: #fff;
}
/* .react-datepicker__day--selected {
background-color: rgb(77, 182, 191);
} */ //달력 선택 일
.react-datepicker__triangle {
display: none;
} //세모 말꼬리
.react-datepicker-popper {
padding-top: 0;
}
.selectbox {
padding: 4px 6px;
border: none;
margin: 0 4px;
}
.calendar-input-wrap {
border: 1px solid #999;
height: 24px;
text-indent: 4px;
font-size: 1.8rem;
width: 128px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4px;
}
.react-datepicker__input-container input {
font-size: 1.8rem;
border: none;
padding: 0;
width: 100px;
}
}
<커스텀3>
import { forwardRef, useEffect, useState } from 'react';
import DatePicker, { registerLocale } from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import ko from 'date-fns/locale/ko';
import { getMonth, getYear, getDate } from 'date-fns';
import dayjs from 'dayjs';
import './calendarCustomThree.scss';
import ArrowBackIosIcon from '@mui/icons-material/ArrowBackIos';
import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
registerLocale('ko', ko); //날짜 한국어로 표시
const CustomInput = forwardRef((props: any, ref) => {
return (
<div className='calendar-input-wrap'>
<input {...props} ref={ref} type='text' />
<CalendarMonthIcon />
</div>
);
});
export default function CalendarCustomFour() {
//시작날짜
const [startDate, setStartDate] = useState<Date | null>(
new Date(
`${getMonth(new Date()) + 1}-${getDate(new Date()) - 1}-${getYear(
new Date()
)}`
)
);
//종료날짜
const [endDate, setEndDate] = useState<Date | null>(new Date());
const _ = require('lodash');
registerLocale('ko', ko); //날짜 한국어로 표시
// 연도 선택 select box에 보여질 데이터 : range(시작 연도, 끝 연도, 연도 간격)
// const years = _.range(1990, getYear(new Date()) + 1, 1);
const years = _.range(getYear(new Date()) - 10, getYear(new Date()) + 1, 1);
// 월 선택 select box에 보여질 데이터
const months = [
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
];
//최종 선택 날짜
const selectStartDate = dayjs(startDate).format('YYYY-MM-DD');
const selectEndDate = dayjs(endDate).format('YYYY-MM-DD');
// console.log('시작:', selectStartDate);
// console.log('종료', selectEndDate);
//+ 추가 적용: 만약 버튼 클릭시 해당 년도로 startDate를 바꾸고 싶을 경우
const handleClickYear = (year: number) => {
const startYears = new Date(
`${getMonth(new Date()) + 1}-${getDate(new Date())}-${
getYear(new Date()) - year
}`
);
setStartDate(startYears);
};
const handleClickMonth = (month: number) => {
const startYears = new Date(
`${getMonth(new Date()) + 1 - month}-${getDate(new Date())}-${getYear(
new Date()
)}`
);
setStartDate(startYears);
};
return (
<div className='custom-wrap3 custom-wrap4'>
<div>
<p className='input-start-date' onClick={() => handleClickYear(10)}>
최대 10년
</p>
<p className='input-start-date' onClick={() => handleClickYear(5)}>
5년
</p>
<p className='input-start-date' onClick={() => handleClickMonth(3)}>
3개월
</p>
<p className='input-start-date' onClick={() => handleClickMonth(1)}>
1개월
</p>
</div>
<div className='date-picker-wrap'>
<DatePicker
//Input 커스텀
customInput={<CustomInput />}
//header 커스텀
renderCustomHeader={({
date,
changeYear,
changeMonth,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}) => (
<div
style={{
margin: 10,
display: 'flex',
justifyContent: 'center',
}}
>
<button
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
>
<ArrowBackIosIcon />
</button>
<select
value={getYear(date)}
onChange={({ target: { value } }) => changeYear(Number(value))}
className='selectbox'
>
{years.map((option: string) => (
<option key={option} value={option}>
{option}년
</option>
))}
</select>
<select
value={months[getMonth(date)]}
onChange={({ target: { value } }) =>
changeMonth(months.indexOf(value))
}
className='selectbox'
>
{months.map((option) => (
<option key={option} value={option}>
{option}월
</option>
))}
{/* 이렇게 하면 범위에 따라 나타나지만, 2023년에서 3월선택후 2013년 3월가면 select에서 7월부터 시작되도록 범위정했지만 3월로 인식되어짐 /사용 X
{getYear(date) === years[0]
? months.slice(currentMonth, 12).map((option) => (
<option key={option} value={option}>
{option}
</option>
))
: months.map((option) => (
<option key={option} value={option}>
{option}
</option>
))} */}
</select>
<button
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
>
<ArrowForwardIosIcon />
</button>
</div>
)}
dayClassName={(d) => 'custom-day'}
dateFormat='yyyy.MM.dd'
disabledKeyboardNavigation //다른달에도 해당일자에 색표시되는거 제거
locale='ko' //한국어로 설정
//최소(minDate),최대날짜(maxDate) 범위 지정(바꿔도 됨)
//minDate : '최소 시작 날짜'를 적용해야 <이전버튼눌러도 안넘어가짐(select안에있는 년도랑 다를수있으니 범위 한정 짓기)
// minDate={new Date(`01-01-${getYear(new Date()) - 10}`)} //01-01-2013(월/일/현재년도에서-10) 기준으로 해놓음
minDate={
new Date(
`${getMonth(new Date()) + 1}-${getDate(new Date())}-${
getYear(new Date()) - 10
}`
)
} //현재 월, 현재 일, 지정 년도(현재에서 -10년전)/ex: 현재날짜가 07.19.2023이면 07.19.2013년으로 해놓음
maxDate={new Date()} //일단 현재날짜까지로 최대날짜 적용시킴
/////
selected={startDate}
onChange={(date) => setStartDate(date)}
selectsStart
startDate={startDate}
endDate={endDate}
/>
<p className='wave'> ~ </p>
<DatePicker
customInput={<CustomInput />}
renderCustomHeader={({
date,
changeYear,
changeMonth,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}) => (
<div
style={{
margin: 10,
display: 'flex',
justifyContent: 'center',
}}
>
<button
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
>
<ArrowBackIosIcon />
</button>
<select
value={getYear(date)}
onChange={({ target: { value } }) => changeYear(Number(value))}
className='selectbox'
>
{years.map((option: string) => (
<option key={option} value={option}>
{option}년
</option>
))}
</select>
<select
value={months[getMonth(date)]}
onChange={({ target: { value } }) =>
changeMonth(months.indexOf(value))
}
className='selectbox'
>
{months.map((option) => (
<option key={option} value={option}>
{option}월
</option>
))}
</select>
<button
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
>
<ArrowForwardIosIcon />
</button>
</div>
)}
dayClassName={(d) => 'custom-day'}
dateFormat='yyyy.MM.dd'
disabledKeyboardNavigation
locale='ko'
maxDate={new Date()}
/////
selected={endDate}
onChange={(date) => setEndDate(date)}
selectsEnd
startDate={startDate}
endDate={endDate}
minDate={startDate}
/>
</div>
</div>
);
}
CSS
.custom-wrap4 {
.date-picker-wrap {
display: flex;
margin-top: 2rem;
}
//달력 header
.react-datepicker__header {
background-color: rgb(124 196 183);
}
//✨ 시작~종료 달력일자 구간 선택 hover안되었을경우(원래 회색이었는데 안나타게함)
.react-datepicker__day {
&--in-range:not(&--in-selecting-range) {
background-color: transparent;
color: #000;
} //:not() => :not() 선택자는 괄호 안의 선택자를 포함하지 않는 요소를 선택합니다.
//&--in-range => .react-datepicker__day--in-range
//:not(&--in-selecting-range) => react-datepicker__day--in-selecting-range 클래스를 갖지 않은 것
}
//시작~종료 달력일자 구간 선택 컬러
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range {
background-color: rgb(151 212 207);
}
//시작, 종료 달력일자 선택 컬러
.react-datepicker__day--selecting-range-start,
.react-datepicker__day--selecting-range-end {
background-color: rgb(77, 182, 191);
}
//my 추가
.wave {
line-height: 1.5;
}
.input-start-date {
background-color: rgb(77, 182, 191);
padding: 1rem 1.4rem;
color: #fff;
margin-right: 1rem;
cursor: pointer;
}
//위 커스텀 CSS와 동일
.react-datepicker__day--outside-month {
color: #a8a8a8 !important;
pointer-events: none;
} //보여지는달력 해당월아닌 다른월 날짜는 회색컬러로 글자처리
.react-datepicker__day-name {
width: 28px; //달력 요일
color: #fff;
}
.react-datepicker {
font-size: 1.2rem; //달력 글씨
}
.custom-day {
width: 28px;
height: 28px;
line-height: 2.8;
} //달력일
.react-datepicker__header {
background-color: rgb(64 123 128);
color: #fff;
}
/* .react-datepicker__day--selected {
background-color: rgb(77, 182, 191);
} */ //달력 선택 일
.react-datepicker__triangle {
display: none;
} //세모 말꼬리
.react-datepicker-popper {
padding-top: 0;
}
.selectbox {
padding: 4px 6px;
border: none;
margin: 0 4px;
}
.calendar-input-wrap {
border: 1px solid #999;
height: 24px;
text-indent: 4px;
font-size: 1.8rem;
width: 128px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 4px;
}
.react-datepicker__input-container input {
font-size: 1.8rem;
border: none;
padding: 0;
width: 100px;
}
}
참고사이트)
'React' 카테고리의 다른 글
[React] 쿠키 저장하기 (react-cookie/서브 도메인 달라도 쿠키 공유) (0) | 2023.07.27 |
---|---|
[React] 숫자 세자리마다 , 콤마 붙이기 (0) | 2023.07.26 |
[React] 소셜로그인- 카카오톡 로그아웃 Logout (0) | 2023.07.07 |
[React] file 전송, formdata API전송시 에러 해결 (0) | 2023.06.20 |
[React] 스켈레톤 로딩 구현하기 (0) | 2023.06.08 |