关于 syncfusion-react-daterangepicker
面向开发者的 Syncfusion React DateRangePicker 实现指南,涵盖范围选择、校验、格式化、事件、样式及进阶用法。
主要功能
- 01日期范围选择与预设
- 02范围约束与校验
- 03日期及区域格式化
- 04事件与命令式方法
- 05主题、RTL 与移动模式
- 06API 与进阶用法指南
适用场景
- 01为报表面板添加日期范围
- 02校验预订表单中的日期范围
- 03定制本地化日期输入
- 04处理选择器事件与状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ syncfusion/ react-ui-components-skills --skill syncfusion-react-daterangepicker安装后在 Claude Code 中输入/syncfusion-react-daterangepicker确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/advanced-patterns.mdapi-reference.mdcustomization-and-styling.mddate-range-formatting.mddate-range-selection.mdevents-and-methods.mdgetting-started.md详细介绍
实现 Syncfusion React DateRangePicker 组件
Syncfusion React DateRangePicker 组件提供直观的日期范围选择方式,支持预设范围、日期验证、多种日期格式、键盘导航和针对移动设备优化的全屏模式。
文档导航指南
入门
📄 阅读: references/getting-started.md
- 通过 npm(@syncfusion/ej2-react-calendars)安装
- CSS 导入和主题配置
- 基本的 DateRangePicker 实现
- 类组件与函数组件设置
- 组件初始化和结构
- 运行开发服务器
- 常见故障排查
日期范围选择
📄 阅读: references/date-range-selection.md
- 开始日期和结束日期属性
- 日期范围验证模式
- 最小和最大日期限制
- 禁用日期配置
- 日期范围预设(最近 7 天、最近 30 天等)
- 值绑定和双向更新
- 只读和禁用状态
- 占位符和标签
日期范围格式设置
📄 阅读: references/date-range-formatting.md
- 日期格式字符串选项(MM/dd/yyyy、dd-MMM-yyyy 等)
- 显示格式与输入格式
- 基于区域设置的日期格式
- 开始日期和结束日期之间的自定义分隔符
- 浮动标签类型(Never、Always、Auto)
- 自定义占位文本
- 用于 DOM 属性的 htmlAttributes
事件和方法
📄 阅读: references/events-and-methods.md
- 事件处理程序(change、open、close、blur、focus、select)
- 事件参数结构
- 方法(show、hide、focusIn、focusOut、reset、destroy)
- 使用 useRef 进行命令式控制
- 生命周期事件(created、destroyed)
- 事件模式和最佳实践
- 清除值和重置状态
- DateRangeSelectingEvent 和 ChangedEventArgs
自定义和样式设置
📄 阅读: references/customization-and-styling.md
- 使用 cssClass 自定义 CSS 类
- 主题选项(Material、Bootstrap、Fluent、Tailwind、Fabric)
- 移动设备全屏模式
- RTL(从右向左)语言支持
- 自定义预设范围
- Z-index 管理
- 宽度和高度配置
- 无障碍功能和 ARIA 属性
API 参考
📄 阅读: references/api-reference.md
- 完整的属性列表(35 个以上属性)
- 所有方法及其签名(8 个方法)
- 所有事件及其事件参数(12 个事件)
- 类型定义和接口
- 默认值和限制
- 各属性和方法的使用场景
高级模式
📄 阅读: references/advanced-patterns.md
- 使用日期范围验证提交表单
- 键盘快捷键和按键导航
- 处理服务器时区偏移
- 持久化和 localStorage
- 多组件集成(开始日期/结束日期绑定)
- 使用延迟加载优化性能
- 错误处理和验证模式
- 复杂日期范围场景(财年、季度)
快速开始
import { DateRangePickerComponent } from '@syncfusion/ej2-react-calendars';
import * as React from 'react';
import '@syncfusion/ej2-base/styles/material3.css';
import '@syncfusion/ej2-buttons/styles/material3.css';
import '@syncfusion/ej2-lists/styles/material3.css';
import '@syncfusion/ej2-inputs/styles/material3.css';
import '@syncfusion/ej2-popups/styles/material3.css';
import '@syncfusion/ej2-calendars/styles/material3.css';
function App() {
const [selectedRange, setSelectedRange] = React.useState<[Date, Date] | null>(null);
const handleDateRangeChange = (e: any) => {
setSelectedRange([e.startDate, e.endDate]);
};
return (
<div style={{ padding: '20px' }}>
<h2>Select Date Range</h2>
<DateRangePickerComponent
id="daterangepicker"
placeholder="Select a range"
change={handleDateRangeChange}
/>
{selectedRange && (
<p>
Selected: {selectedRange[0]?.toLocaleDateString()} - {selectedRange[1]?.toLocaleDateString()}
</p>
)}
</div>
);
}
export default App;
常见模式
模式 1:带预设选项的日期范围
import { DateRangePickerComponent } from '@syncfusion/ej2-react-calendars';
import * as React from 'react';
function ReportingDashboard() {
const [dateRange, setDateRange] = React.useState<[Date, Date] | null>(null);
const getDateRangePresets = () => {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(today.getDate() - 1);
const last7Days = new Date(today);
last7Days.setDate(today.getDate() - 7);
const last30Days = new Date(today);
last30Days.setDate(today.getDate() - 30);
const thisMonth = new Date(today.getFullYear(), today.getMonth(), 1);
const lastMonth = new Date(today.getFullYear(), today.getMonth(), 0);
return [
{ text: 'Today', value: [today, today] },
{ text: 'Yesterday', value: [yesterday, yesterday] },
{ text: 'Last 7 Days', value: [last7Days, today] },
{ text: 'Last 30 Days', value: [last30Days, today] },
{ text: 'This Month', value: [thisMonth, today] },
{ text: 'Last Month', value: [new Date(today.getFullYear(), today.getMonth() - 1, 1), lastMonth] },
];
};
const handlePresetClick = (start: Date, end: Date) => {
setDateRange([start, end]);
};
return (
<div style={{ padding: '20px' }}>
<h3>Analytics Report</h3>
<DateRangePickerComponent
id="daterangepicker"
placeholder="Select report date range"
startDate={dateRange?.[0]}
endDate={dateRange?.[1]}
change={(e: any) => setDateRange([e.startDate, e.endDate])}
/>
<div style={{ marginTop: '15px' }}>
{getDateRangePresets().map((preset) => (
<button
key={preset.text}
onClick={() => handlePresetClick(preset.value[0], preset.value[1])}
style={{ marginRight: '10px', padding: '5px 10px' }}
>
{preset.text}
</button>
))}
</div>
</div>
);
}
export default ReportingDashboard;
模式 2:带验证的日期范围
import { DateRangePickerComponent } from '@syncfusion/ej2-react-calendars';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import * as React from 'react';
function BookingForm() {
const [dateRange, setDateRange] = React.useState<[Date, Date] | null>(null);
const [validationError, setValidationError] = React.useState<string>('');
const minDate = new Date();
const maxDate = new Date();
maxDate.setDate(maxDate.getDate() + 90); // 90 days from now
const handleDateRangeChange = (e: any) => {
setValidationError('');
if (!e.startDate || !e.endDate) {
return;
}
const start = new Date(e.startDate);
const end = new Date(e.endDate);
// Validation checks
if (start > end) {
setValidationError('Start date must be before end date');
return;
}
const daysDifference = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24);
if (daysDifference > 30) {
setValidationError('Date range cannot exceed 30 days');
return;
}
setDateRange([start, end]);
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (dateRange && !validationError) {
console.log('Booking dates:', {
checkIn: dateRange[0].toLocaleDateString(),
checkOut: dateRange[1].toLocaleDateString(),
});
}
};
return (
<form onSubmit={handleSubmit} style={{ padding: '20px', maxWidth: '500px' }}>
<h3>Book Your Stay</h3>
<label style={{ display: 'block', marginBottom: '8px' }}>
Select Check-in and Check-out Dates (Max 30 days)
</label>
<DateRangePickerComponent
id="daterangepicker"
placeholder="Select check-in and check-out"
min={minDate}
max={maxDate}
startDate={dateRange?.[0]}
endDate={dateRange?.[1]}
change={handleDateRangeChange}
style={{ width: '100%', marginBottom: '8px' }}
/>
{validationError && (
<div style={{ color: 'red', marginBottom: '10px', fontSize: '14px' }}>
⚠️ {validationError}
</div>
)}
<ButtonComponent
type="submit"
isPrimary={true}
disabled={!dateRange || !!validationError}
>
Book Now
</ButtonComponent>
</form>
);
}
export default BookingForm;
模式 4:事件处理和状态管理
import { DateRangePickerComponent } from '@syncfusion/ej2-react-calendars';
import * as React from 'react';
function EventTrackingExample() {
const [dateRange, setDateRange] = React.useState<[Date, Date] | null>(null);
const [eventLog, setEventLog] = React.useState<string[]>([]);
const handleSelect = (e: any) => {
setEventLog(prev => [
...prev,
`Selected: ${e.startDate?.toLocaleDateString()} to ${e.endDate?.toLocaleDateString()}`
]);
};
const handleChange = (e: any) => {
setDateRange([e.startDate, e.endDate]);
setEventLog(prev => [...prev, `Changed: ${new Date().toLocaleTimeString()}`]);
};
const handleOpen = (e: any) => {
setEventLog(prev => [...prev, `Popup opened at ${new Date().toLocaleTimeString()}`]);
};
const handleClose = (e: any) => {
setEventLog(prev => [...prev, `Popup closed at ${new Date().toLocaleTimeString()}`]);
};
const clearLog = () => {
setEventLog([]);
};
return (
<div style={{ padding: '20px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>
<div>
<h3>DateRangePicker</h3>
<DateRangePickerComponent
id="daterangepicker"
placeholder="Select date range"
select={handleSelect}
change={handleChange}
open={handleOpen}
close={handleClose}
/>
</div>
<div style={{ padding: '10px', border: '1px solid #ccc', borderRadius: '4px' }}>
<h3>Event Log</h3>
<button
onClick={clearLog}
style={{
padding: '5px 10px',
marginBottom: '10px',
backgroundColor: '#f0f0f0',
border: '1px solid #ccc',
cursor: 'pointer'
}}
>
Clear Log
</button>
<ul style={{ maxHeight: '300px', overflowY: 'auto', margin: 0, paddingLeft: '20px' }}>
{eventLog.map((event, idx) => (
<li key={idx} style={{ marginBottom: '5px', fontSize: '12px' }}>
{event}
</li>
))}
</ul>
</div>
</div>
);
}
export default EventTrackingExample;
模式 5:自定义日期范围格式
import { DateRangePickerComponent } from '@syncfusion/ej2-react-calendars';
import * as React from 'react';
function DateFormatDemo() {
const [formatType, setFormatType] = React.useState<'short' | 'long' | 'custom'>('short');
const [dateRange, setDateRange] = React.useState<[Date, Date] | null>(null);
const getFormat = () => {
switch (formatType) {
case 'short':
return 'M/d/yyyy';
case 'long':
return 'MMMM d, yyyy';
case 'custom':
return 'dd-MMM-yy';
default:
return 'M/d/yyyy';
}
};
return (
<div style={{ padding: '20px' }}>
<h3>Date Range Format Options</h3>
<div style={{ marginBottom: '15px' }}>
<label style={{ marginRight: '10px' }}>Format Type:</label>
{(['short', 'long', 'custom'] as const).map((format) => (
<label key={format} style={{ marginRight: '15px' }}>
<input
type="radio"
name="format"
value={format}
checked={formatType === format}
onChange={(e) => setFormatType(e.target.value as any)}
/>
{format.charAt(0).toUpperCase() + format.slice(1)}
</label>
))}
</div>
<div style={{ marginBottom: '10px', padding: '10px', backgroundColor: '#f5f5f5' }}>
<strong>Format String:</strong> {getFormat()}
</div>
<DateRangePickerComponent
id="daterangepicker"
placeholder="Select date range"
format={getFormat()}
startDate={dateRange?.[0]}
endDate={dateRange?.[1]}
change={(e: any) => setDateRange([e.startDate, e.endDate])}
/>
{dateRange && (
<div style={{ marginTop: '15px', padding: '10px', backgroundColor: '#e8f5e9' }}>
<p>
<strong>Formatted Output:</strong> {dateRange[0].toLocaleDateString('en-US')} - {dateRange[1].toLocaleDateString('en-US')}
</p>
</div>
)}
</div>
);
}
export default DateFormatDemo;
关键属性参考
- 属性:
startDate:类型:Date— 默认值:null— 范围的初始开始日期。 - 属性:
endDate:类型:Date— 默认值:null— 范围的初始结束日期。 - 属性:
min:类型:Date— 默认值:new Date(1900, 0, 1)— 可选择的最小日期。 - 属性:
max:类型:Date— 默认值:new Date(2099, 11, 31)— 可选择的最大日期。 - 属性:
value:类型:Date[] | DateRange— 默认值:null— 获取或设置开始日期和结束日期。 - 属性:
format:类型:string | RangeFormatObject— 默认值:null— 日期显示和输入格式。 - 属性:
placeholder:类型:string— 默认值:null— 输入占位文本。 - 属性:
enabled:类型:boolean— 默认值:true— 启用或禁用组件(使用enabled,而非disabled)。 - 属性:
readonly:类型:boolean— 默认值:false— 只读状态;禁止编辑。 - 属性:
allowEdit:类型:boolean— 默认值:true— 允许手动编辑输入文本。 - 属性:
cssClass:类型:string— 默认值:''— 为根元素添加自定义 CSS 类。 - 属性:
floatLabelType:类型:FloatLabelType | string— 默认值:Never— 浮动标签行为(Never、Always、Auto)。 - 属性:
separator:类型:string— 默认值:'-'— 输入中开始日期和结束日期之间的分隔符。 - 属性:
locale:类型:string— 默认值:'en-US'— 用于格式化和本地化的区域设置。 - 属性:
inputFormats:类型:string[] | RangeFormatObject[]— 默认值:null— 可接受的输入解析格式。 - 属性:
keyConfigs:类型:object— 默认值:null— 自定义键盘快捷键映射。 - 属性:
firstDayOfWeek:类型:number— 默认值:null— 日历中每周的第一天。 - 属性:
dayHeaderFormat:类型:DayHeaderFormats— 默认值:Short— 标题中星期名称的格式。 - 属性:
start:类型:CalendarView— 默认值:Month— 弹出窗口打开时的初始日历视图。 - 属性:
depth:类型:CalendarView— 默认值:Month— 日历导航的最大深度。 - 属性:
weekNumber:类型:boolean— 默认值:false— 在日历行中显示周数。 - 属性:
weekRule:类型:WeekRule— 默认值:FirstDay— 定义一年中第一周的规则。 - 属性:
minDays:类型:number— 默认值:null— 所选范围允许的最小天数。 - 属性:
maxDays:类型:number— 默认值:null— 所选范围允许的最大天数。 - 属性:
strictMode:类型:boolean— 默认值:false— 为 true 时,只能输入有效范围。 - 属性:
showClearButton:类型:boolean— 默认值:true— 切换清除按钮的显示状态。 - 属性:
fullScreenMode:类型:boolean— 默认值:false— 在移动设备上使用全屏弹出窗口。 - 属性:
htmlAttributes:类型:{ [key: string]: string }— 默认值:{}— 应用于组件元素的其他 HTML 属性。 - 属性:
serverTimezoneOffset:类型:number— 默认值:null— 处理初始值时使用的服务器时区偏移量(分钟)。 - 属性:
width:类型:number | string— 默认值:''— 组件输入框的宽度。 - 属性:
zIndex:类型:number— 默认值:1000— 弹出元素的 z-index。
相关技能
- 实现 Calendar - 用于选择单个日期
- 实现 DatePicker - 用于基本日期选择
- 实现 TimePicker - 用于选择范围内的时间
后续步骤:
- 阅读 references/getting-started.md,安装并设置你的第一个 DateRangePicker
- 查看 references/date-range-selection.md,了解范围选择模式
- 查看 references/date-range-formatting.md,了解格式选项
- 阅读 references/advanced-patterns.md,了解复杂场景
- 参考 references/api-reference.md,获取完整的 API 文档
评论
支持 Markdown