- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
导读
RSUITE 的DateRangePicker组件默认以dd/MM/yyyy格式展示日期范围,但在真实业务中我们往往需要携带具体时刻、切换 12 小时制,甚至只选择时间段。本文以官方文档示例 format-date-time.md 为骨架,系统讲解如何通过format、showMeridiem、defaultCalendarValue、ranges等属性组合出「日期+时间范围」「纯时间范围」「12 小时制(AM/PM)」三类典型场景,并结合 DateRangePicker 源码 揭示format字符串是如何驱动日历面板、时间选择器与输入框行为的。读完本文,你将能根据自己的业务任意定制日期时间格式,并理解其背后的实现原理。
一、示例总览:三种典型时间格式
官方文档 format-date-time.md 给出了一个覆盖三种典型场景的完整示例:
import { DateRangePicker } from 'rsuite'; const App = () => ( <div className="field"> <p>Date Time Range</p> <DateRangePicker format="yyyy-MM-dd HH:mm:ss" defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} /> <p>Time Range</p> <DateRangePicker format="HH:mm:ss" ranges={[]} defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} /> <p>Meridiem format</p> <DateRangePicker format="hh:mm aa" showMeridiem defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} /> </div> ); ReactDOM.render(<App />, document.getElementById('root'));三组示例分别对应:
| 场景 | format 取值 | 关键属性 |
|---|---|---|
| 日期 + 时间范围 | yyyy-MM-dd HH:mm:ss | defaultCalendarValue |
| 纯时间范围 | HH:mm:ss | ranges={[]}、defaultCalendarValue |
| 12 小时制(Meridiem) | hh:mm aa | showMeridiem、defaultCalendarValue |
三组示例都通过defaultCalendarValue预先指定日历面板的默认展示区间,保证打开弹层时前后两个日历月处于2022-02与2022-05,让示例效果稳定可复现。
二、认识 format:组件的“显示与行为”开关
format是DateRangePicker的核心属性之一。根据 官方 Props 文档:
- 属性名:
format - 类型:
string - 默认值:
'dd/MM/yyyy' - 作用:设置日期范围在输入框中渲染时的格式
在 DateRangePicker 源码 中,format的解析起点是:
const formatStr = format || locale?.shortDateFormat || 'yyyy-MM-dd'; const rangeFormatStr = `${formatStr}${character}${formatStr}`;即:未显式传入format时,会回退到locale.shortDateFormat,最后兜底为yyyy-MM-dd;而输入框最终展示的字符串是「起始日期格式化结果 + 分隔符character+ 结束日期格式化结果」,character默认值为' ~ '(见同文件character = ' ~ '的默认参数解构)。
format使用的是类 date-fns 的令牌(token)语法,常见令牌如下:
| 令牌 | 含义 | 示例输出 |
|---|---|---|
yyyy | 四位数年份 | 2022 |
MM | 两位数月份 | 02 |
MMM/MMMM | 缩写 / 全称月份 | Feb/February |
dd | 两位数日期 | 01 |
HH | 24 小时制小时(00–23) | 14 |
hh | 12 小时制小时(01–12) | 02 |
mm | 分钟 | 30 |
ss | 秒 | 45 |
aa | AM / PM 标记 | AM、PM |
除英文字母令牌外,格式串中也可以嵌入任意文字,例如yyyy年MM月dd日,这一点在 format.md 示例 中直接使用。
format 决定面板形态:源码级原理
format不仅是显示格式,还直接决定了日历弹层“长什么样”。源码在 DateRangePicker.tsx 中通过useDateMode对格式串做模式判定:
const { mode, has } = useDateMode(formatStr); // Show only the calendar month panel. formatStr = 'yyyy-MM' const onlyShowMonth = mode === DateMode.Month; // Only show the time panel. formatStr = 'HH:mm:ss' const onlyShowTime = mode === DateMode.Time; // Allows two calendar panels to display the same month. const allowSameMonth = onlyShowMonth || showOneCalendar || onlyShowTime; // Default gap between two calendars, if `showOneCalendar` is set, the gap is 0 const calendarGap = allowSameMonth ? 0 : 1;模式判定逻辑实现在 useDateMode.ts 与 formatCheck.ts 中:
shouldRenderTime(format):正则/([Hhms])/,只要格式串包含H、h、m、s中的任一字符即视为含时间;shouldOnlyRenderTime(format):包含[Hhms]且不包含[YyMDd](如HH:mm:ss),判定为纯时间模式DateMode.Time;shouldRenderDate(format):同时包含[Yy]、[ML]、[Dd],判定为日期模式DateMode.Date;- 日期与时间同时存在时判定为
DateMode.DateTime。
由此可以理解本文示例的三种行为差异:
format="yyyy-MM-dd HH:mm:ss"→DateTime模式:同时渲染双月日历与时间选择器;format="HH:mm:ss"→Time模式(onlyShowTime为 true):弹层只展示时间选择面板,不再渲染日历网格,这也是该示例需要配合ranges={[]}的原因——面板上只有时间可操作;format="hh:mm aa"→ 同样是纯时间模式,但配合showMeridiem以 12 小时制呈现。
在Time模式下,两个日历面板允许展示同一个月(allowSameMonth为 true),calendarGap变为 0;而在普通日期模式下,前后两个日历默认间隔 1 个月(源码中getSafeCalendarDate的默认区间为「当月 + 下月」)。
时间模式下改变日期会保留时间
当格式同时包含日期与时间时,用户点击日期只会改变年月日,而不会重置时分秒。这一行为由 DateRangePicker.tsx 中的copyTime保证:
// The time should remain the same when the dates in the date range are changed. if ( has('time') && dateRange?.length && (eventName === 'changeDate' || eventName === 'changeMonth') ) { const startDate = copyTime({ from: getCalendarDatetime('start'), to: dateRange[0] }); const endDate = copyTime({ from: getCalendarDatetime('end'), to: dateRange.length === 1 ? addMonths(startDate, calendarGap) : dateRange[1] }); nextValue = [startDate, endDate]; }即:日期变更事件(changeDate/changeMonth)发生时,从当前日历基准时间getCalendarDatetime('start'/'end')中取出时分秒,拷贝到新选中的日期上,从而保证「先选日期、后调时间」的交互符合预期。
三、场景一:日期 + 时间范围(Date Time Range)
<DateRangePicker format="yyyy-MM-dd HH:mm:ss" defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} />要点说明:
format="yyyy-MM-dd HH:mm:ss"让输入框按「年-月-日 时:分:秒」显示,例如2022-02-01 00:00:00 ~ 2022-05-01 23:59:59;defaultCalendarValue的类型为[Date, Date],作用是设置日历面板的默认展示日期(而非输入框的值),源码中在getSafeCalendarDate({ value: value ?? defaultCalendarValue ?? null, allowSameMonth })处被消费(DateRangePicker.tsx)。当组件没有受控值或默认值时,弹层打开即定位到该区间;- 用户可在日历上先后点击起始日期与结束日期完成范围选择,再通过面板内的时间选择器(时/分/秒下拉)微调具体时刻,最后点击 OK 确认。
需要区分的是:defaultCalendarValue只影响日历面板的初始展示月份,与defaultValue(非受控默认值)是两个不同概念,详见 官方 Props 表。
四、场景二:纯时间范围(Time Range)
<DateRangePicker format="HH:mm:ss" ranges={[]} defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} />要点说明:
format="HH:mm:ss"由于不包含任何年/月/日令牌,被 formatCheck.ts 判定为纯时间模式,日历弹层只渲染时间选择面板;ranges={[]}清空预置快捷范围。ranges默认提供Today、Yesterday、Last 7 days三个快捷选项(见 官方 Props 表 中ranges的默认说明);纯时间场景下这些日期快捷项没有意义,因此置空;- 时间选择器通过点击即可完成开始时间与结束时间的两次选择。测试用例中也验证了纯时间格式的行为——DateRangePicker.spec.tsx 中以
format="hh:mm:ss"渲染组件后,通过设置起始时间的时/分/秒为 6:6:6 断言时间选择生效。
五、场景三:12 小时制(Meridiem)格式
<DateRangePicker format="hh:mm aa" showMeridiem defaultCalendarValue={[new Date('2022-02-01 00:00:00'), new Date('2022-05-01 23:59:59')]} />要点说明:
format="hh:mm aa"中hh表示 12 小时制小时(01–12),aa表示 AM/PM 标记,两者必须配合使用;showMeridiem是布尔属性,源码注释为「Meridiem format for 12-hour time」(DateRangePicker.tsx),它在时间选择面板中展示 AM/PM 切换项。注意源码中还存在已废弃的showMeridian属性,注释明确建议「UseshowMeridieminstead」;showMeridiem会被透传给日历组件(calendarProps中的showMeridiem),并参与时间选项的渲染(见 DateRangePicker.tsx)。
实际渲染效果类似02:00 AM ~ 05:00 PM。需要 24 小时制时使用HH:mm且不要设置showMeridiem。
六、与 format 强相关的配套属性
除了format本身,官方文档 中还有一批属性与日期时间格式配合使用,在定制格式时常被一并调整:
| 属性 | 类型 / 默认值 | 说明 |
|---|---|---|
character | string,默认' ~ ' | 两个日期之间的分隔符,例如设为' – '后展示为2022-02-01 – 2022-05-01 |
defaultCalendarValue | [Date, Date] | 日历面板默认展示的日期区间 |
defaultValue | [Date, Date] | 非受控模式下的默认选中值 |
value | [Date, Date] | 受控模式下的当前值 |
editable | boolean,默认true | 是否允许通过键盘在输入框内直接输入日期时间 |
placeholder | string | 输入框占位提示 |
showHeader | boolean,默认true | 是否在日历顶部展示格式化后的日期范围(v5.52.0 起) |
ranges | Range[] | 预置快捷范围,纯时间或纯月份场景通常置为[] |
其中editable值得注意:DateRangePicker默认允许键盘直接录入日期时间(editable={true}),输入内容同样按formatStr解析校验;若希望禁止键盘输入、只允许点选,可设editable={false}。
更多 format 组合示例
format.md 还提供了大量可直接套用的组合,摘录如下:
<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={[]} /> <DateRangePicker format="dd MMM yyyy hh:mm:ss aa" showMeridiem caretAs={FaCalendar} ranges={[]} />其中format="MMM yyyy"仅含年与月,会被判定为DateMode.Month模式,弹层直接展示月份选择面板(onlyShowMonth);caretAs则用于替换输入框右侧的日历图标,与纯时间/纯月份场景搭配更语义化。
七、源码验证:格式与输入渲染
format还参与输入框尺寸的计算与值的渲染:
- getInputHtmlSize 会按
rangeFormatStr(或选中值经formatDate格式化后的完整字符串)的长度动态计算输入框 HTML 宽度,因此长格式(如yyyy-MM-dd HH:mm:ss)会自动获得更宽的输入框; - 输入框展示值由
formatDate(startDate, formatStr)与formatDate(endDate, formatStr)拼接而成,formatDate来自useCustom('DateRangePicker', props)的国际化格式化函数; - 日历顶部的
Header同样接收formatStr与character,将当前选中/悬停区间实时格式化展示(DateRangePicker.tsx)。
测试用例也验证了格式化渲染结果,例如 DateRangePicker.spec.tsx 中:
const template = 'MM/dd/yyyy hh:mm:ss'; render(<DateRangePicker value={value} format={template} />); expect(screen.getByRole('textbox')).to.have.value('11/11/2019 01:00:00 ~ 11/12/2019 01:00:00');即输入框严格按起始值 + character(' ~ ') + 结束值的规则渲染,与 format-date-time.md 示例中的预期展示一致。
八、实践建议与小结
- 先定业务粒度,再写 format:只要日期 →
yyyy-MM-dd类;日期+时刻 → 追加HH:mm或HH:mm:ss;只要时刻 → 纯时间格式并配ranges={[]};只要月份 →yyyy-MM或MMM yyyy; - 12 小时制必须成对使用:
hh+aa+showMeridiem,缺一不可;24 小时制使用HH且不设置showMeridiem; - 注意默认值对象粒度:
defaultCalendarValue是[Date, Date]形式的 Date 对象数组,传入的起始时刻(如00:00:00、23:59:59)会成为该侧日历的时间基准,配合copyTime机制在后续日期变更时被保留; - 纯时间/纯月份场景记得清空
ranges,避免出现语义不符的「Today / Yesterday」快捷项; - 若希望展示更紧凑,可同时调整
character分隔符(如' – '),该字符同样会出现在日历头部与输入框渲染结果中。
通过format+showMeridiem+defaultCalendarValue+ranges的组合,DateRangePicker足以覆盖绝大多数业务中的日期时间范围选择需求;而理解useDateMode对格式串的模式判定,能帮助你预判日历面板的最终形态,做到「改一行 format,面板随之自适应」。
- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
相关推荐
RSuite DateRangeInput 日期格式自定义完全指南:format 与 character 深入解析
RSuite DateRangeInput 日期格式自定义完全指南:format 与 character 深入解析 DateRangeInput 是 RSuit
前端UI组件rsuite DateInput 日期格式定制指南:掌握 `format` 属性的全部写法
rsuite DateInput 日期格式定制指南:掌握 format 属性的全部写法 导读 DateInput 是 rsuite 中允许用户 通过键盘逐段输入
前端UI组件antd DatePicker 日期格式化实战:用 format 属性自定义 yyyy/MM/dd 等显示格式
antd DatePicker 日期格式化实战:用 format 属性自定义 yyyy/MM/dd 等显示格式 format 是 ant design(antd
UI组件前端设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考