Обычно мы, как разработчики, не изобретаем велосипед. В большинстве случаев мы просто используем стороннюю библиотеку для календаря. Но в некоторых случаях сторонний календарь не подходит для нашего дизайна и функциональности. Так что, когда выбора нет, нужно придумать свой календарь.
Давайте начнем, ниже приведены пакеты, которые мы собираемся использовать.
Я не буду подробно объяснять приведенную выше библиотеку, пожалуйста, обратитесь по ссылке, если вы не знакомы с приведенной выше библиотекой.
Настройте свой проект React, выполнив команду ниже
npx create-react-app custom-calendar && cd custom-calendar
npm install dates-generator --save
npm install styled-components --save
styled-components
используется для применения стилей css к компонентам, и мне проще писать стили css, используя styled-components
Теперь давайте отредактируем /src/App.js
import React, { useState, useEffect } from 'react';
import styled from 'styled-components'
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const Container = styled.div`
width: 300px;
border: 1px solid black;
margin: 0 auto;
box-shadow: 10px 10px 0px black;
`
const MonthText = styled.div`
font-size: 26px;
font-weight: bold;
text-align: center;
`
const App = () => {
const [selectedDate, setSelectedDate] = useState(new Date());
const [dates, setDates] = useState([]);
const [calendar, setCalendar] = useState({
month: selectedDay.getMonth(),
year: selectedDay.getFullYear(),
});
useEffect(() => {}, [])
return (
<div style={{ width: '100%', paddingTop: 50 }}>
<Container>
<MonthText>
{months[calendar.month]}
</MonthText>
</Container>
</div>
);
}
export default App;
Если вы запустите это, вы увидите, что текущий месяц отображается в вашем браузере.
selectedDate
— это дата, которую мы выбрали в календаре. По умолчанию дата является текущей датой.
dates
— это состояние, в котором будут храниться все даты данного месяца.
calendar
— это состояние, в котором будут храниться месяц и год для календаря.
Теперь давайте заполним календарь датами, по умолчанию календарь будет календарем текущего месяца.
...
const [calendar, setCalendar] = useState({
month: selectedDay.getMonth(),
year: selectedDay.getFullYear(),
});
useEffect(() => {
const body = {
month: calendar.month,
year: calendar.year
};
const { dates, nextMonth, nextYear, previousMonth, previousYear } = datesGenerator(body);
setDates([ ...dates ]);
setCalendar({
...calendar,
nextMonth,
nextYear,
previousMonth,
previousYear
});
}, [])
...
Как видите, мы добавили useEffect
внутрь нашего компонента. Внутри useEffect
мы запускаем функцию datesGenerator
, предоставляемую dates-generator
.
Эта функция вернет все даты, доступные для данного месяца. Мы предоставили месяц и год, передав body
внутри функции datesGenerator
. Мы можем использовать атрибуты previousMonth/nextMonth
и previousYear/nextYear
, чтобы получить календарные даты предыдущего/следующего месяца.
Подробнее о том, как работает dates-generator
, читайте здесь
Поскольку сейчас мы уже храним все даты в состоянии, давайте отобразим его в нашем браузере.
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
...
return (
<div style={{ width: '100%', paddingTop: 50 }}>
<Container>
<MonthText>
{months[calendar.month]}
</MonthText>
<div>
<div>
<table style={{ width: '100%' }}>
<tbody>
<tr>
{days.map((day) => (
<td key={day} style={{ padding: '5px 0' }}>
<div style={{ textAlign: 'center', padding: '5px 0' }}>
{day}
</div>
</td>
))}
</tr>
{dates.length > 0 && dates.map((week) => (
<tr key={JSON.stringify(week[0])}>
{week.map((each) => (
<td key={JSON.stringify(each)} style={{ padding: '5px 0' }}>
<div style={{ textAlign: 'center', padding: '5px 0' }}>
{each.date}
</div>
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
</Container>
</div>
);
...
Я добавил переменную days для отображения поверх дат. Если вы сейчас посмотрите в свой браузер, то увидите календарь на текущий месяц.
Теперь давайте напишем еще 3 функции:
onClickNext
- перейти к календарю на следующий месяцonClickPrevious
- перейти к календарю предыдущего месяцаonSelectDate
- установить выбранную пользователем дату
const onClickNext = () => {
const body = { month: calendar.nextMonth, year: calendar.nextYear };
const { dates, nextMonth, nextYear, previousMonth, previousYear } = datesGenerator(body);
setDates([ ...dates ]);
setCalendar({
...calendar,
month: calendar.nextMonth,
year: calendar.nextYear,
nextMonth,
nextYear,
previousMonth,
previousYear
});
}
const onClickPrevious = () => {
const body = { month: calendar.previousMonth, year: calendar.previousYear };
const { dates, nextMonth, nextYear, previousMonth, previousYear } = datesGenerator(body);
setDates([ ...dates ]);
setCalendar({
...calendar,
month: calendar.previousMonth,
year: calendar.previousYear,
nextMonth,
nextYear,
previousMonth,
previousYear
});
}
const onSelectDate = (date) => {
setSelectedDate(new Date(date.year, date.month, date.date))
}
...
return (
...
<div style={{ padding: 10 }}>
<div onClick={onClickPrevious} style={{ float: 'left', width: '50%' }}>
Previous
</div>
<div onClick={onClickNext} style={{ float: 'left', width: '50%', textAlign: 'right' }}>
Next
</div>
</div>
<MonthText>
{months[calendar.month]}
</MonthText>
...
<div onClick={() => onSelectDate(each.jsDate)} style={{ textAlign: 'center', padding: '5px 0' }}>
{each.date}
</div>
...
<div style={{ padding: 10 }}>
Selected Date: {selectedDate.toDateString()}
</div>
</Container>
...
)
...
Теперь дата, которую вы нажмете, будет отображаться в нижней части календаря. если вы посмотрите в свой браузер, вы увидите этот календарь:
Вот и все, теперь у вас есть базовый календарь, вы можете настроить его по своему усмотрению. Это все от меня.
Полный код для /App.js
можно получить по этому адресу здесь
Обратная связь приветствуется.
Первоначально опубликовано на https://dev.to 4 мая 2020 г.