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 | 默认日期 | Date | nowDate |
className | 组件额外的 CSS className | string | -- |
style | 组件额外的 CSS style | CSSProperties | -- |
组件源码
组件源码
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