В настоящее время я использую React для создания компонента выбора даты, где вы можете установить диапазон дат. В качестве образца и модели я использовал пакет даты реакции . Теперь мне удалось построить функциональность средства выбора даты, но я не знаю, как добиться изменения цвета всех дат между начальной и конечной датой. Потому что в версии airbnb, как только вы установите дату начала, она автоматически устанавливает все дни между датой начала и курсором мыши в другом цвете. Этот эффект также присутствует, когда установлены как начальная, так и конечная дата (см. Приложение для справки).
![Date Picker Hover effect](https://i.stack.imgur.com/4NHar.png)
Вот мой код, Я также рад за каждое предложение по улучшению:)
import React, { useState, useEffect } from 'react';
//component
function Test() {
const currentDate = new Date();
//state for the datepicker month and year heading
let [datePicker, setDatePicker] = useState({
currentMonth: currentDate.getMonth(),
currentYear: currentDate.getFullYear(),
});
//state that stores start and end date and keeps track which date is currently selected to be overridden
let [dateRange, setDateRange] = useState({
selectStartDate: true,
selectEndDate: false,
startDate: null,
endDate: null,
});
//useEffect that colors the current start and end date in a different color
useEffect(() => {
let startClass = document.querySelector('.start-date');
let endClass = document.querySelector('.end-date');
if (startClass) startClass.classList.remove('start-date');
if (endClass) endClass.classList.remove('end-date');
if (dateRange.startDate) {
let startDateAttribute = getDateFormatted(dateRange.startDate);
let start = document.querySelectorAll(`[day="${startDateAttribute}"]`)[0];
if (start) start.classList.add('start-date');
}
if (dateRange.endDate) {
let endDateAttribute = getDateFormatted(dateRange.endDate);
let end = document.querySelectorAll(`[day="${endDateAttribute}"]`)[0];
if (end) end.classList.add('end-date');
}
}, [dateRange.startDate, dateRange.endDate, datePicker.currentMonth, datePicker.currentYear]);
//initializes the grid and gets the days of the current month and year
const monthGrid = [];
getMonthGrid(datePicker.currentYear, datePicker.currentMonth, monthGrid);
//takes the monthgrid and maps it to day elements that are then displayed on the page
const days = monthGrid.map((element, id) => {
if (element === null) {
return <div className='day empty-day' key={id}></div>;
}
let date = new Date(datePicker.currentYear, datePicker.currentMonth, element);
date = getDateFormatted(date);
return (
<div className='day' key={date} day={date} onClick={(e) => onClickDateRange(e)}>
{element}
</div>
);
});
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
}}
>
<div className='date-picker'>
<div className='input-container'>
<input
type='text'
name='start-date'
className='date-picker__input'
placeholder='Start Date'
value={dateRange.startDate ? getDateFormatted(dateRange.startDate) : ''}
onClick={onInputStartClick}
/>
<input
type='text'
name='end-date'
className='date-picker__input'
placeholder='End Date'
value={dateRange.endDate ? getDateFormatted(dateRange.endDate) : ''}
onClick={onInputEndClick}
/>
</div>
<div className='year-container'>
<button className='prev-month' onClick={prevMonth}>
Prev
</button>
<h2>{`${getMonthTitle(datePicker.currentMonth)} ${datePicker.currentYear}`}</h2>
<button className='next-month' onClick={nextMonth}>
Next
</button>
</div>
<div className='week-container'>
<div>Mo</div>
<div>Tu</div>
<div>We</div>
<div>Th</div>
<div>Fr</div>
<div>Sa</div>
<div>So</div>
</div>
<div className='days'>{days}</div>
<button onClick={getNumberOfDays}>Submit</button>
<button onClick={clearDateRange}>Clear</button>
</div>
</div>
);
//MAIN FUNCTIONS
//gets the days of the current month and year
function getMonthGrid(year, month, monthGrid) {
const firstDayType = new Date(year, month, 1).getDay();
const lastDay = new Date(year, month + 1, 0);
let lastDayType = lastDay.getDay();
const numberOfDays = lastDay.getDate();
if (firstDayType === 0) {
for (let i = 1; i < 7; i++) {
monthGrid.push(null);
}
} else {
for (let i = 1; i < firstDayType; i++) {
monthGrid.push(null);
}
}
for (let i = 0; i < numberOfDays; i++) {
monthGrid.push(i + 1);
}
if (lastDayType !== 0) {
for (lastDayType; lastDayType < 7; lastDayType++) {
monthGrid.push(null);
}
}
}
//on click function that is called whenever a day element is clicked
function onClickDateRange(e) {
//gets the date of the element that was clicked
let date = new Date(datePicker.currentYear, datePicker.currentMonth, e.target.innerText);
//end date is selected to be overridden, but date is out of bounds (smaller than start date)
if (dateRange.selectEndDate && dateRange.startDate && date < dateRange.startDate) {
setDateRange({
selectStartDate: false,
selectEndDate: true,
startDate: date,
endDate: null,
});
return;
}
//start date is selected to be overridden, but date is out of bounds (bigger than end date)
if (dateRange.selectStartDate && dateRange.endDate && date > dateRange.endDate) {
setDateRange({
selectStartDate: false,
selectEndDate: true,
startDate: date,
endDate: null,
});
return;
}
//there is no start date but an end date and date is out of bounds (bigger than end date)
if (!dateRange.startDate && dateRange.endDate && date > dateRange.endDate) {
setDateRange({
selectStartDate: false,
selectEndDate: true,
startDate: date,
endDate: null,
});
return;
}
//there is no start date but an end date
if (!dateRange.startDate && dateRange.endDate) {
setDateRange({
...dateRange,
selectStartDate: false,
selectEndDate: true,
startDate: date,
});
return;
}
//base case if end date is selected
if (dateRange.selectEndDate) {
setDateRange({
...dateRange,
endDate: date,
});
return;
}
//base case if start date is selected
if (dateRange.selectStartDate) {
setDateRange({
...dateRange,
selectStartDate: false,
selectEndDate: true,
startDate: date,
});
return;
}
}
//Handles clicks on the Inputs => sets which dates have to be overwritten
function onInputStartClick() {
setDateRange({ ...dateRange, selectStartDate: true, selectEndDate: false });
}
function onInputEndClick() {
setDateRange({ ...dateRange, selectStartDate: false, selectEndDate: true });
}
//HELPER FUNCTIONS
//gets the name of the current month
function getMonthTitle(month) {
const months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
];
return months[month];
}
//onclick function that sets the state of the datepicker to preview or next month
function prevMonth() {
if (datePicker.currentMonth - 1 < 0) {
setDatePicker({ currentMonth: 11, currentYear: datePicker.currentYear - 1 });
return;
}
setDatePicker({ ...datePicker, currentMonth: datePicker.currentMonth - 1 });
}
function nextMonth() {
if (datePicker.currentMonth + 1 > 11) {
setDatePicker({ currentMonth: 0, currentYear: datePicker.currentYear + 1 });
return;
}
setDatePicker({ ...datePicker, currentMonth: datePicker.currentMonth + 1 });
}
//onclick function of submmit button that calculates the number of days set in the date range
function getNumberOfDays() {
const difference = (dateRange.endDate - dateRange.startDate) / (1000 * 60 * 60 * 24);
console.log(difference);
}
//onclick function that clears the date range
function clearDateRange() {
setDateRange({
selectStartDate: true,
selectEndDate: false,
startDate: null,
endDate: null,
});
}
//function that takes a date object as imput and formats it as dd/mm/yyyy
function getDateFormatted(date) {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return `${day}/${month}/${year}`;
}
}
export default Test;
Я благодарен за любую помощь, которую я могу получить с этим, поскольку я не знаю, как достичь этого эффекта. Спасибо:)