- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
DateRangePicker 是 rsuite 中用于快速输入或选择一个日期和时间范围的组件,同时支持鼠标选择与键盘输入。本文围绕 docs/pages/components/date-range-picker/zh-CN/index.md 的完整知识骨架展开,结合组件源码 src/DateRangePicker 中的实现细节,系统讲解获取组件、格式化、尺寸外观、整周整月选择、禁用日期工具函数、受控与非受控、响应式与可访问性等主题。读完本文,你将掌握 DateRangePicker 的全部核心 Props,并能像源码那样组合出满足复杂业务约束的日期范围选择方案。
获取组件
DateRangePicker 作为 rsuite 的顶层组件导出,与其他组件一样直接从rsuite包导入即可,无需额外安装子包:
import { DateRangePicker } from 'rsuite';组件类型定义与导出入口位于 src/DateRangePicker/index.tsx,核心实现见 src/DateRangePicker/DateRangePicker.tsx。需要注意,禁用日期相关的工具方法(如allowedMaxDays、beforeToday、combine)也是挂在DateRangePicker静态属性上的,直接通过解构获取:
const { combine, allowedMaxDays, beforeToday } = DateRangePicker;基础演示与核心用法
默认
最简单的用法是不传任何 Props,直接渲染:
const App = () => <DateRangePicker />;此时组件使用默认格式dd/MM/yyyy、默认外观default、默认尺寸md,用户点击输入框弹出双日历面板,选择开始日期后再选择结束日期。
自定义日期格式
通过format属性可以自由控制展示的日期格式,character属性用于自定义两个日期之间的分隔符(默认' ~ ')。下面的示例展示了从纯日期、带时间、到 12 小时制的多种组合:
import { DateRangePicker, Stack } from 'rsuite'; const App = () => ( <Stack spacing={10} direction="column" alignItems="flex-start"> <DateRangePicker format="MM/dd/yyyy" character=" – " /> <DateRangePicker format="dd.MM.yyyy" /> <DateRangePicker format="MMM dd, yyyy" /> <DateRangePicker format="MMMM dd, yyyy" /> <DateRangePicker format="yyyy年MM月dd日" /> <DateRangePicker format="MM/dd/yyyy HH:mm" /> <DateRangePicker format="MM/dd/yyyy hh:mm aa" showMeridiem /> <DateRangePicker format="MMM yyyy" caretAs={BsCalendar2MonthFill} ranges={[]} /> <DateRangePicker format="HH:mm:ss" caretAs={FaClock} ranges={[]} /> </Stack> );要点说明:
format支持yyyy、MM、dd、HH、mm、ss、aa(上午/下午)等 token,也可混入中文等任意文本字符。showMeridiem用于显示 12 小时制的时间格式,与format中的aa配合使用。caretAs可以替换右侧箭头图标(例如换成时钟、月历图标),ranges={[]}表示清空默认快捷项,使面板更纯粹。
尺寸
size支持lg、md、sm、xs四档,默认md:
<DateRangePicker size="lg" placeholder="Large" /> <DateRangePicker size="md" placeholder="Medium" /> <DateRangePicker size="sm" placeholder="Small" /> <DateRangePicker size="xs" placeholder="Xsmall" />外观
appearance支持default与subtle两种,默认default。subtle外观下输入框的边框与背景更弱化,适合融入工具栏等紧凑场景:
<DateRangePicker appearance="default" placeholder="Default" w={230} /> <DateRangePicker appearance="subtle" placeholder="Subtle" w={230} />撑满与占位符
block:布尔属性,设置为true时组件撑满整行(块级布局)。placeholder:没有值时的默认显示文本。- 还可以配合
w(宽度)等样式控制实现布局。
选择整周、整月
hoverRange用于点击日期时直接选中一段预定义范围,支持三种形态:
| 形态 | 说明 |
|---|---|
'week' | 点击任意日期时自动选中整个星期 |
'month' | 点击任意日期时自动选中整个月 |
(date: Date) => [Date, Date] | 自定义函数,根据点击的日期计算范围 |
import { subDays } from 'date-fns/subDays'; import { addDays } from 'date-fns/addDays'; <DateRangePicker hoverRange="week" ranges={[]} /> <DateRangePicker hoverRange="week" isoWeek ranges={[]} /> <DateRangePicker hoverRange="week" weekStart={3} ranges={[]} /> <DateRangePicker hoverRange="month" ranges={[]} /> <DateRangePicker ranges={[]} hoverRange={date => [subDays(date, 1), addDays(date, 1)]} />关于星期的起点,需要注意两个相互作用的属性:
isoWeek:遵循 ISO 8601 标准,每个日历星期从星期一开始,星期日为第 7 天。参考 hover-range 示例中的第二个示例。weekStart:一周第一天的索引(0 为星期日,1 为星期一,依此类推),默认0。该属性自 v5.62.0 起提供;当设置了isoWeek时,weekStart会被忽略。例如weekStart={3}表示一周从星期三开始。
因此"整周从星期几开始"完全可由你控制,是hoverRange="week"的核心配套能力。
一键选值(oneTap)
oneTap允许用户点击一次就选定日期范围,常与hoverRange配合使用。它特别适合"选单个星期 / 单个自然月"这类短交互场景:
const ranges = [ { label: 'today', value: [new Date(), new Date()] }, { label: 'yesterday', value: [subDays(new Date(), 1), subDays(new Date(), 1)] } ]; <DateRangePicker oneTap showOneCalendar ranges={ranges} /> <DateRangePicker oneTap showOneCalendar hoverRange="week" ranges={[]} /> <DateRangePicker oneTap showOneCalendar hoverRange="week" isoWeek ranges={[]} /> <DateRangePicker oneTap showOneCalendar hoverRange="week" weekStart={3} ranges={[]} /> <DateRangePicker oneTap showOneCalendar hoverRange="month" ranges={[]} />示例中同时使用了showOneCalendar(只显示一个日历)来配合单次点击的轻量交互。
显示周数与单个日历
showWeekNumbers:布尔属性,在日历面板上显示周数。showOneCalendar:布尔属性,让弹出面板只显示一个日历(默认是两个)。注意文档中的类型写法为boolen,实际按 boolean 使用即可。
禁用与只读:shouldDisableDate 与工具函数
函数签名
shouldDisableDate是一个函数类型属性,它会在渲染日历以及选择日期的地方调用,可以根据业务自定义需要禁用的选项。完整签名如下:
shouldDisableDate( date: Date, // 用于判断是否需要禁用的日期 selectDate: Array<Date>, // 选择的日期 selectedDone: boolean, // 当前是否选择完成。如果为 false, 则只选择了开始日期,等待选择结束日期 target: 'CALENDAR' | 'TOOLBAR_BUTTON_OK' | 'TOOLBAR_SHORTCUT' | 'INPUT' // shouldDisableDate 调用的位置 ) => booleantarget用于标识该函数被调用的位置——日历渲染、点击"确定"按钮、点击快捷项、输入框输入时都会触发校验,这使禁用逻辑可以在不同交互路径上保持一致。类型定义DisabledDateFunction见 src/DateRangePicker/types.ts,实际禁用逻辑实现在 src/DateRangePicker/disabledDateUtils.ts。
内置禁用工具方法
为了更方便地设置需要禁用的日期,DateRangePicker提供了一组静态工具方法:
| 方法 | 类型 | 描述 |
|---|---|---|
after | (date?: string \| Date) => boolean | 禁用指定日期之后的日期 |
afterToday | () => boolean | 禁用今天之后的日期 |
allowedDays | (days: number) => boolean | 只允许指定的天数,其他日期都禁用 |
allowedMaxDays | (days: number) => boolean | 允许指定的最多天数,其他日期都禁用 |
allowedRange | (startDate: string \| Date, endDate: string \| Date) => boolean | 允许指定的日期范围,其他日期都禁用 |
before | (date?: string \| Date) => boolean | 禁用指定日期之前的日期 |
beforeToday | () => boolean | 禁用今天之前的日期 |
combine | (...args) => boolean | 用于组合多个条件 |
组合使用示例:
import { DateRangePicker } from 'rsuite'; const { combine, allowedMaxDays, beforeToday } = DateRangePicker; <DateRangePicker shouldDisableDate={combine(allowedMaxDays(7), beforeToday())} />上面的写法同时满足两个约束:最多只能选 7 天,且不能选今天之前的日期。
源码视角:allowedMaxDays / allowedDays 的实现原理
在 src/DateRangePicker/disabledDateUtils.ts 中,allowedMaxDays(days)的实现以已选中的开始日期为基准:通过DateUtils.addDays(f, -days + 1)与DateUtils.addDays(f, days - 1)计算允许区间的两端,再借助isAfterDay/isBeforeDay判断目标日期是否越界,并且只在target === 'CALENDAR'且尚未选择完成(!selectedDone)时返回禁用:
export function allowedMaxDays(days: number): DisabledDateFunction { return (date, selectValue, selectedDone, target): boolean => { let beforeLimit = false; let afterLimit = false; if (selectValue?.[0]) { const startDate = selectValue[0]; beforeLimit = composeFunctions( f => DateUtils.addDays(f, -days + 1), f => isAfterDay(f, date) )(startDate); afterLimit = composeFunctions( f => DateUtils.addDays(f, days - 1), f => isBeforeDay(f, date) )(startDate); } if (target === 'CALENDAR' && !selectedDone && (beforeLimit || afterLimit)) { return true; } return false; }; }而allowedDays(days)使用!DateUtils.isSameDay判断目标日期是否落在以开始日期为中心、前后各days天的窗口内,并要求beforeLimit && afterLimit同时成立才禁用。可以看到这些工具方法都不是简单地"一刀切",而是借助selectDate与selectedDone动态响应选择进度——这正是shouldDisableDate签名的价值所在。
完整的演示代码还覆盖了disabled(整组件禁用)、readOnly(只读)、plaintext(纯文本展示)三种形态,以及自定义禁用函数写法:
<DateRangePicker disabled /> <DateRangePicker shouldDisableDate={date => isAfter(date, new Date())} /> <DateRangePicker shouldDisableDate={allowedMaxDays(7)} /> <DateRangePicker shouldDisableDate={allowedDays(7)} /> <DateRangePicker shouldDisableDate={allowedRange('2020-10-01', '2021-10-01')} /> <DateRangePicker shouldDisableDate={beforeToday()} /> <DateRangePicker shouldDisableDate={afterToday()} /> <DateRangePicker readOnly defaultValue={[new Date(), new Date()]} /> <DateRangePicker plaintext defaultValue={[new Date(), new Date()]} />禁用输入与加载中状态
DateRangePicker默认是可以通过键盘输入日期和时间的(editable默认true,渲染为 Input 输入框)。如果希望禁用键盘编辑、只允许通过日历选择,可以设置:
<DateRangePicker editable={false} />此外loading(默认false)可以在组件上显示加载中状态指示器;label属性可在按钮开头显示一个标签。
自定义快捷键(ranges)
ranges用于配置弹出层中的快捷项,默认包含今天、昨天、最近 7 天三项。其类型为Range[],每个项包含label与value两个字段。文档给出的默认值构造方式如下:
import { startOfDay, endOfDay, addDays, subDays } from 'date-fns'; const Ranges = [ { label: 'today', value: [startOfDay(new Date()), endOfDay(new Date())] }, { label: 'yesterday', value: [startOfDay(addDays(new Date(), -1)), endOfDay(addDays(new Date(), -1))] }, { label: 'last7Days', value: [startOfDay(subDays(new Date(), 6)), endOfDay(new Date())] } ];自定义时参考上述结构即可,例如只保留"最近 3 天",或新增"本季度"。onShortcutClick(shortcut: Range, event)回调会在点击快捷项时触发。清空默认快捷项用ranges={[]}(在格式化、整周整月等示例中频繁出现)。
受控与非受控的值
与 React 常规模式一致:
- 受控:传入
value与onChange,由外部状态驱动。onChange的回调签名为(value: [Date, Date]) => void。 - 非受控:只传
defaultValue,由组件内部维护状态。 defaultCalendarValue:设置默认日历面板日期(未选择时的初始展示范围)。
const [value, setValue] = React.useState([ new Date('2017-02-01 01:00:00'), new Date('2017-02-02 14:00:00') ]); <DateRangePicker value={value} onChange={setValue} /> <DateRangePicker value={value} onChange={setValue} showMeridiem format="yyyy-MM-dd HH:mm:ss" defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-03-01 23:59:59')]} /> <DateRangePicker defaultValue={[new Date(), new Date()]} />其余回调还包括:onOk(点击"确定"后)、onClean(清除值后)、onOpen/onClose、onEnter/onEntering/onEntered/onExit/onExiting/onExited(动画过渡生命周期)、onSelect(选择日期时)。
其他展示与行为属性
- 自定义日历图标:
caretAs替换右侧箭头图标(见前文格式化示例)。 - 自定义渲染值:
renderValue(date: [Date, Date], format: string) => string可完全接管输入框展示文本;renderCell(date: Date) => ReactNode(v5.77.0 起)可自定义日历面板上的日期单元格;renderTitle(date, calendarKey)可自定义日历面板上的月份标题。 - 不显示头部:
showHeader(默认true)控制日历面板头部是否显示格式化的日期范围,v5.52.0 起提供;设置为false可隐藏头部。 - 时间粒度隐藏:
hideHours/hideMinutes/hideSeconds(均自 v5.71.0 起)分别以(value: number, date: Date) => boolean的形式隐藏指定的小时、分钟、秒选项。 - 日历吸附:
calendarSnapping(v5.69.0 起)为true时,如果用户先选择右侧日历上的日期,则会自动切换到左侧日历上继续选择。 - 年份限制:
limitEndYear(默认1000)与limitStartYear相对当前选择日期设置可选年份的上下限。 - 分隔符:
character默认' ~ ';可清除:cleanable默认true。 - 其他通用属性:
container(渲染容器)、open/defaultOpen(受控/非受控展开)、placement(默认bottomStart,完整取值见 Placement 类型 中引用的_common/types/placement.md)、preventOverflow(防止浮动元素溢出)、popupClassName/popupStyle(弹出层样式)、locale(国际化,详见 i18n 指南 的 DateTimeFormats)、monthDropdownProps(月份下拉框属性,类型见MonthDropdownProps)。
响应式:小屏自动变全宽 Drawer
在超小屏幕上,弹出层默认显示为全宽 Drawer(responsive默认true)。当选择器已经位于 Modal 或 Drawer 中时,可设置responsive={false}保持定位浮层,避免嵌套遮罩造成层级混乱。响应式示例代码见 examples/responsive.tsx。
可访问性(Accessibility)
ARIA 属性
默认拥有 DateRangeInput 组件的 ARIA 属性:
- 当值无效时,
aria-invalid="true"属性被添加到<input>元素。 - 当设置了
label时,aria-labelledby属性被添加到<input>元素和dialog元素上,并将值设置为label的id属性值。 - 拥有
aria-haspopup="dialog"属性,用于指示组件拥有一个可交互的弹出层。
键盘交互
默认拥有 DateRangeInput 组件的键盘交互,支持通过键盘输入日期和时间(在editable开启时)、方向键在日历中移动焦点等标准操作,具体行为与 DateInput 一致。
完整 Props 速查表
| 属性名称 | 类型(默认值) | 描述 | 版本 |
|---|---|---|---|
| appearance | 'default' | 'subtle'('default') | 设置外观 | |
| block | boolean | 堵塞整行 | |
| calendarSnapping | boolean | true时先选右侧日历日期会自动切换到左侧日历 | v5.69.0 |
| caretAs | ElementType | 自定义右侧箭头图标的组件 | |
| character | string(' ~ ') | 两个日期之间的分隔符 | |
| cleanable | boolean(true) | 可以清除选择值 | |
| container | HTMLElement | (() => HTMLElement) | 设置渲染的容器 | |
| defaultCalendarValue | [Date, Date] | 默认日历面板日期 | |
| defaultOpen | boolean | 默认打开 | |
| defaultValue | [Date, Date] | 默认值(非受控) | |
| disabled | boolean | 禁用组件 | |
| editable | boolean(true) | 渲染为 Input 输入框,可以通过键盘输入日期 | |
| format | string('dd/MM/yyyy') | 日期显示格式化 | |
| hideHours | (hour: number, date: Date) => boolean | 隐藏指定的小时选项 | v5.71.0 |
| hideMinutes | (minute: number, date: Date) => boolean | 隐藏指定的分钟选项 | v5.71.0 |
| hideSeconds | (second: number, date: Date) => boolean | 隐藏指定的秒选项 | v5.71.0 |
| hoverRange | 'week' | 'month' | (date: Date) => [Date, Date] | 点击日期时选中的日期范围 | |
| isoWeek | boolean | ISO 8601 标准,每个日历星期从星期一开始,星期日为第 7 天 | |
| label | ReactNode | 在按钮开头显示的标签 | |
| limitEndYear | number(1000) | 相对当前选择日期,设置可选年份上限 | |
| limitStartYear | number | 相对当前选择日期,设置可选年份下限 | |
| loading | boolean(false) | 是否显示加载中状态指示器 | |
| locale | DateTimeFormats | 定义本地化设置 | |
| popupClassName | string | 自定义弹出框的 CSS 类名 | |
| popupStyle | CSSProperties | 自定义弹出框的样式 | |
| monthDropdownProps | MonthDropdownProps | 月份下拉框属性 | |
| onChange | (value: [Date, Date]) => void | 值改变后的回调函数 | |
| onClean | (event) => void | 清除值后的回调函数 | |
| onClose | () => void | 关闭回调函数 | |
| onEnter / onEntered / onEntering | () => void | 显示前/后/中动画过渡回调 | |
| oneTap | boolean | 是否点击一次就选定日期范围,可配合 hoverRange 使用 | |
| onExit / onExited / onExiting | () => void | 退出前/后/中动画过渡回调 | |
| onOk | (value: [Date, Date]) => void | 点击"确定"按钮后的回调 | |
| onOpen | () => void | 打开回调函数 | |
| onSelect | (data: Date) => void | 选择日期的回调函数 | |
| onShortcutClick | (shortcut: Range, event) => void | 点击快捷项的回调函数 | |
| open | boolean | 打开(受控) | |
| placeholder | string | 没有值时默认显示内容 | |
| placement | Placement('bottomStart') | 显示位置 | |
| preventOverflow | boolean | 防止浮动元素溢出 | |
| ranges | Range[](默认今天,昨天,最近 7 天) | 快捷项配置 | |
| renderCell | (date: Date) => ReactNode | 自定义渲染日历面板上的日期单元格 | v5.77.0 |
| renderTitle | (date: Date, calendarKey: 'start' | 'end') => ReactNode | 自定义渲染日历面板上的月份标题 | |
| renderValue | (date: [Date, Date], format: string) => string | 自定义渲染值 | |
| responsive | boolean(true) | 是否在超小屏幕上将弹出层显示为全宽 Drawer | |
| shouldDisableDate | DisabledDateFunction | 禁用日期 | |
| showHeader | boolean(true) | 是否在日历面板头部显示格式化的日期范围 | v5.52.0 |
| showMeridiem | boolean | 显示 12 小时制的时间格式 | |
| showOneCalendar | boolen | 显示一个日历 | |
| showWeekNumbers | boolean | 显示周数 | |
| size | 'lg' | 'md' | 'sm' | 'xs'('md') | 设置组件尺寸 | |
| value | [Date, Date] | 当前值(受控) | |
| weekStart | 0 | 1 | 2 | 3 | 4 | 5 | 6(0) | 一周的第一天索引(0 为星期日),设置了 isoWeek 时忽略此属性 | v5.62.0 |
相关类型定义
ts:DisabledDateFunction
type DisabledDateFunction = ( date: Date, // 用于判断是否需要禁用的日期 selectDate?: Value, // 选择的日期 selectedDone?: boolean, // 是否选择完成;为 false 时只选择了开始日期,等待选择结束日期 target?: DATERANGE_DISABLED_TARGET // 调用位置 ) => boolean;ts:Ranges
import { startOfDay, endOfDay, addDays, subDays } from 'date-fns'; const Ranges = [ { label: 'today', value: [startOfDay(new Date()), endOfDay(new Date())] }, { label: 'yesterday', value: [startOfDay(addDays(new Date(), -1)), endOfDay(addDays(new Date(), -1))] }, { label: 'last7Days', value: [startOfDay(subDays(new Date(), 6)), endOfDay(new Date())] } ];延伸阅读
- DateRangePicker 英文文档
- 禁用日期工具函数的源码实现:src/DateRangePicker/disabledDateUtils.ts
- 组件类型定义:src/DateRangePicker/types.ts
- 组件测试用例:src/DateRangePicker/test/DateRangePicker.spec.tsx 与 src/DateRangePicker/test/disabledDateUtils.spec.tsx
- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
相关推荐
RSuite DateRangePicker 日期范围选择器实战指南:从基础用法到禁用规则与快捷键定制
RSuite DateRangePicker 日期范围选择器实战指南:从基础用法到禁用规则与快捷键定制 DateRangePicker 是 RSuite 组件库
前端UI组件rsuite DateRangePicker 完整指南:日期时间范围选择器的配置、禁用策略与无障碍实现
rsuite DateRangePicker 完整指南:日期时间范围选择器的配置、禁用策略与无障碍实现 DateRangePicker 是 rsuite 中用于
前端UI组件rsuite DateRangePicker 的 block 属性:让日期范围选择器铺满整行的实战指南
rsuite DateRangePicker 的 block 属性:让日期范围选择器铺满整行的实战指南 日期范围选择器(DateRangePicker)默认以“
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考