跳到主要内容

DatePicker 日期选择器

日期选择器 实现日、月、年面板的日期选择

日、月、年选择面板的实现交互:

  • 日面板:实现点击日期选择具体日期,点击头部面部左右箭头可前往上一年/下一年、上一月/下一月
  • 月面板:点击日面板头部月份进入,点击月份则选择具体月份并返回日面板,点击头部面部左右箭头前往上一年/下一年
  • 年面板:点击日面板头部月份进入,以十年为区间,点击年份则选择该年并返回日面板,点击头部面部左右箭头前往上个十年/下个十年
  • 根据输入框更改输入实时变换日期

代码演示

基本使用

nowDate:
2023
9
Sun
Mon
Tue
Wed
Thu
Fri
Sat
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
2020年——2029
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2023
1
2
3
4
5
6
7
8
9
10
11
12
收起源代码
import React, { useState } from 'react'
import { DatePicker, Space } from '@dance-ui/ui'

export default () => {
const [selectDateString, setSelectDateString] = useState('')
const onChange = (date, dateString) => {
console.log({ date, dateString })
setSelectDateString(dateString)
}
return (
<Space direction="vertical">
<div>nowDate: {selectDateString}</div>
<DatePicker onChange={onChange} />
</Space>
)
}

API

  • 支持默认日期的设置 defaultDate 通过设置 defaultDate 为 dayjs 对象实现默认日期的设置
  • 支持日期的获取 onDateChange 通过日期变化的回调函数获取当前日期,返回 dayjs 对象
属性名描述类型默认值
onChange日期变化时的回调函数(date: Dayjs, dateString?: string) => void--
defaultDate默认日期DatenowDate
className组件额外的 CSS classNamestring--
style组件额外的 CSS styleCSSProperties--

组件源码

组件源码
import classNames from 'classnames'
import dayjs from 'dayjs'
import React, { useCallback, useRef, useState } from 'react'
import { useClickAway } from 'react-use'
import Icon, { IconType } from '../Icon'
import DayPanel from './DayPanel'
import MonthPanel from './MonthPanel'
import YearPanel from './YearPanel'

export type DatePickerProps = {
/** 日期变化时的回调函数 */
onChange?: (date: dayjs.Dayjs, dateString?: string) => void
/**
* 默认日期
* @default nowDate
*/
defaultDate?: Date
/** 组件额外的 CSS className */
className?: string
/** 组件额外的 CSS style */
style?: React.CSSProperties
}
// TODO: 封装Input、Modal组件
const DatePicker = ({ defaultDate, onChange, className, style }: DatePickerProps) => {
const containerRef = useRef<HTMLDivElement>(null)
const [curDate, setCurDate] = useState(() => (dayjs(defaultDate).isValid() ? dayjs(defaultDate) : dayjs()))
const [dateString, setDateString] = useState(curDate.format('YYYY-MM-DD'))
const [open, setOpen] = useState(false)
const [panelType, setPanelType] = useState('Date')

useClickAway(containerRef, () => {
setOpen(false)
})

const changeDate = (date: dayjs.Dayjs) => {
setCurDate(date)
setDateString(date.format('YYYY-MM-DD'))
onChange?.(date, date.format('YYYY-MM-DD'))
setOpen(false)
}

const openPanel = useCallback(
(type = 'Date') => {
setOpen(true)
setPanelType(type ?? 'Date')
},
[setOpen, setPanelType],
)

const openDatePanel = useCallback(() => {
openPanel('Date')
}, [openPanel])

const openMonthPanel = useCallback(() => {
openPanel('Month')
}, [openPanel])

const openYearPanel = useCallback(() => {
openPanel('Year')
}, [openPanel])

const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const nowValue = e?.target?.value
setDateString(nowValue)
const newDate = dayjs(nowValue)
if (newDate.isValid()) changeDate(newDate)
}

return (
<div
className={classNames(
'group relative inline-flex items-center rounded border border-solid border-gray-400 bg-white px-2 py-1 hover:border-blue-500 focus:border-blue-500',
className,
)}
style={style}
ref={containerRef}>
<input
className="border-none bg-white text-base text-gray-400 outline-none group-hover:text-blue-500"
placeholder="请输入日期"
onFocus={openDatePanel}
value={dateString}
onChange={onInputChange}
/>
<Icon type={IconType.DATE_PICKER} className="text-xl text-gray-400 group-hover:text-blue-500" />
<DayPanel
close={() => {
setOpen(false)
}}
className="min-h-[300px] min-w-[300px]"
active={open && panelType === 'Date'}
curDate={curDate}
changeDate={changeDate}
handleYear={openYearPanel}
handleMonth={openMonthPanel}
/>
<YearPanel
className="min-h-[300px] min-w-[300px]"
active={open && panelType === 'Year'}
curDate={curDate}
onChange={changeDate}
openDayPanel={openDatePanel}
/>
<MonthPanel
className="min-h-[300px] min-w-[300px]"
active={open && panelType === 'Month'}
curDate={curDate}
onChange={changeDate}
openDayPanel={openDatePanel}
/>
</div>
)
}
export default DatePicker