☰
rsuite DateRangePicker 日期范围选择器完整指南:从基础用法到源码级禁用逻辑
2026/9/28 19:14:59 网站建设 项目流程
  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

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 调用的位置 ) => boolean

target用于标识该函数被调用的位置——日历渲染、点击"确定"按钮、点击快捷项、输入框输入时都会触发校验,这使禁用逻辑可以在不同交互路径上保持一致。类型定义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')设置外观
blockboolean堵塞整行
calendarSnappingbooleantrue时先选右侧日历日期会自动切换到左侧日历v5.69.0
caretAsElementType自定义右侧箭头图标的组件
characterstring(' ~ ')两个日期之间的分隔符
cleanableboolean(true)可以清除选择值
containerHTMLElement | (() => HTMLElement)设置渲染的容器
defaultCalendarValue[Date, Date]默认日历面板日期
defaultOpenboolean默认打开
defaultValue[Date, Date]默认值(非受控)
disabledboolean禁用组件
editableboolean(true)渲染为 Input 输入框,可以通过键盘输入日期
formatstring('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]点击日期时选中的日期范围
isoWeekbooleanISO 8601 标准,每个日历星期从星期一开始,星期日为第 7 天
labelReactNode在按钮开头显示的标签
limitEndYearnumber(1000)相对当前选择日期,设置可选年份上限
limitStartYearnumber相对当前选择日期,设置可选年份下限
loadingboolean(false)是否显示加载中状态指示器
localeDateTimeFormats定义本地化设置
popupClassNamestring自定义弹出框的 CSS 类名
popupStyleCSSProperties自定义弹出框的样式
monthDropdownPropsMonthDropdownProps月份下拉框属性
onChange(value: [Date, Date]) => void值改变后的回调函数
onClean(event) => void清除值后的回调函数
onClose() => void关闭回调函数
onEnter / onEntered / onEntering() => void显示前/后/中动画过渡回调
oneTapboolean是否点击一次就选定日期范围,可配合 hoverRange 使用
onExit / onExited / onExiting() => void退出前/后/中动画过渡回调
onOk(value: [Date, Date]) => void点击"确定"按钮后的回调
onOpen() => void打开回调函数
onSelect(data: Date) => void选择日期的回调函数
onShortcutClick(shortcut: Range, event) => void点击快捷项的回调函数
openboolean打开(受控)
placeholderstring没有值时默认显示内容
placementPlacement('bottomStart')显示位置
preventOverflowboolean防止浮动元素溢出
rangesRange[](默认今天,昨天,最近 7 天)快捷项配置
renderCell(date: Date) => ReactNode自定义渲染日历面板上的日期单元格v5.77.0
renderTitle(date: Date, calendarKey: 'start' | 'end') => ReactNode自定义渲染日历面板上的月份标题
renderValue(date: [Date, Date], format: string) => string自定义渲染值
responsiveboolean(true)是否在超小屏幕上将弹出层显示为全宽 Drawer
shouldDisableDateDisabledDateFunction禁用日期
showHeaderboolean(true)是否在日历面板头部显示格式化的日期范围v5.52.0
showMeridiemboolean显示 12 小时制的时间格式
showOneCalendarboolen显示一个日历
showWeekNumbersboolean显示周数
size'lg' | 'md' | 'sm' | 'xs'('md')设置组件尺寸
value[Date, Date]当前值(受控)
weekStart0 | 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 .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询