react-日期选择器封装

文件

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 = firstDayOfMonth
    while (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;
}

效果图

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值