文件
import { useMemo, useState, useEffect } from "react"
import dayjs, { Dayjs } from "dayjs"
import "dayjs/locale/zh-cn"
import "./App.css"
dayjs.locale("zh-cn")function SimpleCalendar() {// 当前时间对象const [month, setMonth] = useState(dayjs())// 当前日期const [currentDate, setCurrentDate] = useState('')// 结束日期const [endDate, setEndDate] = useState<any>('')// 时间段const [perioDate, setPerioDate] = useState<String[]>()// 获取一个月得天数const getDaysOfMonth = (year: number, month: number) => {// 每个月得第一天let firstDayOfMonth = dayjs(`${year}-${month}-1`)// 每个月最后一天let lastDayOfMonth = dayjs(`${year}-${month + 1}-1`).subtract(1, "day")// 开始补全第一天前的日期while (firstDayOfMonth.day() !== 0) {firstDayOfMonth = firstDayOfMonth.subtract(1, "day")}// 开始补全最后一天后的日期while (lastDayOfMonth.day() !== 6) {lastDayOfMonth = lastDayOfMonth.add(1, "day")}const days = []let tempDate = firstDayOfMonthwhile (tempDate.isBefore(lastDayOfMonth) || tempDate.isSame(lastDayOfMonth)) {days.push(tempDate)tempDate = tempDate.add(1, "day")}return days}const days = useMemo(() => {return getDaysOfMonth(month.year(), month.month() + 1)}, [month])// 标题const weekTitles = useMemo(() => {return [...Array(7)].map((_, weekInx) => {return dayjs().day(weekInx)})}, [])// 月份修改const onMonthSwitch = (action: number) => {setMonth((month) => {return month.add(action, "month")})}// 判断选中是否为本月天数const selectDays = (monthDay: Dayjs) => {const dayTiem = monthDay.format('YYYY-MM-DD')// 获取当前月份的第一天const firstDay = month.startOf("month").format('YYYY-MM-DD')return dayTiem >= firstDay ? true : false// // 获取当前月份的总天数// const totalDays = firstDay.daysInMonth()// // 生成包含本月所有日期的数组// const allDaysArray = Array.from({ length: totalDays }, (_, index) =>// firstDay.add(index, "day").format("YYYY-MM-DD")// )// 选中日期// const selectedDate = monthDay.format("YYYY-MM-DD")// return allDaysArray.includes(selectedDate)}// 设置开始结束日期const timePeriod = (day: Dayjs) => {const dayTime = day.format('YYYY-MM-DD')// 开始日期if (!currentDate) {setCurrentDate(day.format('YYYY-MM-DD'))console.log(dayTime)// 有开始日期没有结束日期} else if (currentDate && !endDate) {// 开始和结束同一天if (dayTime == currentDate) {setEndDate(dayTime)}// 结束日期比开始日期小的时候if (dayTime < currentDate) {setCurrentDate('')return}setEndDate(day.format('YYYY-MM-DD'))const daysDiff = day.diff(currentDate, 'day')// 中间日期添加样式const middleDates = []for (let i = 1; i < daysDiff; i++) {const middleDate = dayjs(currentDate).add(i, 'day')middleDates.push(middleDate.format('YYYY-MM-DD'))}middleDates.push(dayTime)setPerioDate(middleDates)// 开始和结束日期都有后清空} else if (currentDate && endDate) {setCurrentDate('')setEndDate('')setPerioDate([])}}return (<div className="App"><div className="calendar"><div className="calendar-month"><div className="calendar-month-switch" onClick={() => onMonthSwitch(-1)}>{"<"}</div><div>{month.format("MMM YYYY")}</div><div className="calendar-month-switch" onClick={() => onMonthSwitch(1)}>{">"}</div></div><div className="calendar-title">{weekTitles.map((title, index) => {return (<div key={index} className="calendar-week">{title.format("dd")}</div>)})}</div><div className="calendar-content">{days.map((day: Dayjs, index) => {const dayTime = day.format('YYYY-MM-DD')const dynamicClassName = `calendar-day ${selectDays(day) ? 'thisMonth' : 'non'} ${dayTime == currentDate ? 'active' : ''} ${perioDate?.includes(dayTime) ? 'perioDate' : ''} `return (<div key={index} onClick={() => timePeriod(day)} className={dynamicClassName}>{day.format("DD")}</div>)})}</div></div><div>开始日期:{currentDate}</div><div>结束日期:{endDate}</div></div>)
}export default SimpleCalendar
样式
.calendar {display: flex;flex-direction: column;width: 350px;height: 400px;font-size: 16px;
}.calendar-month {display: flex;align-items: center;justify-content: space-between;width: 350px;height: 44px;Margin-bottom: 16px
}.calendar-month-switch {display: flex;align-items: center;justify-content: center;cursor: pointer;width: 44px;height: 44px;Background-color: white;
}
.calendar-month-switch:hover {background-color: #e6e6e6;
}.calendar-title {display: grid;grid-template-columns: repeat(7, 1fr);padding-bottom: 8px;
}.calendar-content {width: 100%;display: grid;grid-template-columns: repeat(7, 1fr);
}.calendar-week {display: flex;align-items: center;justify-content: center;
}.calendar-day {display: flex;align-items: center;justify-content: center;aspect-ratio: 1;width: 50px;height: 36px;cursor: pointer;
}
.calendar-day:hover{background-color: #e6e6e6;
}.non{cursor:not-allowed;
}.active{background-color:#FFFF76;
}.perioDate{background-color: #006EDC;
}
效果图