FullCalendar动态时段时长设置问题:时段选择时间不匹配
问题
我们使用FullCalendar实现排球场预订功能,预订时段为10:00-23:00。需求为:10:00-15:00(原表述03:00应为笔误,实际为下午3点)设置1小时的时段时长,15:00-23:00设置1.5小时的时段时长,以对应不同定价,但目前无法实现该配置。
当前问题:使用select范围钩子时,出现开始时间与结束时间不匹配的情况,导致无法创建事件。例如点击19:00-20:30的时段,select返回的却是18:00-19:00,与实际选择不符。
附当前Calendar组件配置代码:
<Calendar schedulerLicenseKey="CC-Attribution-NonCommercial-NoDerivatives" initialView={view} dayMaxEventRows={3} snapDuration="01:00:00" slotLabelFormat={{ month:"long"}} defaultRangeSeparator="to" select={onSelectRange} aspectRatio={3} datesSet={handleDatesSet} // Set custom keys when dates are set dateClick={handleDateClick} // Handle click on dates longPressDelay={1} resourceAreaWidth={smUp?150:100} height={smUp?dummyResources.length*65:dummyResources.length*60} showNonCurrentDates={false} selectMirror slotMinutes= {5} eventDrop={arg => { onDropEvent(arg, updateEvent); }} eventResize={arg => { onResizeEvent(arg, updateEvent); }} slotDuration="01:00:00" slotMinTime="10:00:00" slotMaxTime="23:00:00" slotLabelContent={arg=>slotGenerator.next().value?.time} viewDidMount={arg => { console.log(arg.view.calendar,'mew------------------------------------------------') }} resourcesInitiallyExpanded initialResources={dummyResources} resourceLabelContent={({ resource }) => resource.title} plugins={[ listPlugin, dayGridPlugin, timelinePlugin, timeGridPlugin, resourceTimelinePlugin, resourceTimeGridPlugin, interactionPlugin, ]} />
解决方案
一、修复select时间不匹配问题
当前配置里的snapDuration="01:00:00"会强制将选择时间对齐到1小时间隔,这就是点击19:00-20:30却返回18:00-19:00的核心原因。
- 直接删除
snapDuration="01:00:00"配置,让选择时间完全跟随用户点击范围。 - 后续结合分时段逻辑调整
slotDuration相关配置。
二、实现分时段时长配置
FullCalendar没有原生支持分时段设置不同slotDuration的功能,需通过自定义逻辑实现:
1. 自定义选择范围修正
在onSelectRange钩子中,根据开始时间所属时段自动调整结束时间,确保符合时长规则:
const onSelectRange = (info) => { let start = info.start; let end = info.end; const startHour = start.getHours(); // 10:00-15:00 强制1小时时长 if (startHour >= 10 && startHour < 15) { // 对齐开始时间到整点,结束时间+1小时 const alignedStart = new Date(start.setMinutes(0, 0, 0)); const alignedEnd = new Date(alignedStart.getTime() + 60 * 60 * 1000); // 若结束时间超过15:00则截断 if (alignedEnd.getHours() > 15) { alignedEnd.setHours(15, 0, 0, 0); } // 使用修正后的时间创建事件 createEvent(alignedStart, alignedEnd); } // 15:00-23:00 强制1.5小时时长 else if (startHour >=15 && startHour <23) { // 对齐开始时间到最近的整点/半点 const minutes = start.getMinutes(); const alignedMinutes = minutes <30 ? 0 :30; const alignedStart = new Date(start.setMinutes(alignedMinutes, 0, 0)); const alignedEnd = new Date(alignedStart.getTime() + 90 *60 *1000); // 若结束时间超过23:00则截断 if (alignedEnd.getHours() >23) { alignedEnd.setHours(23,0,0,0); } createEvent(alignedStart, alignedEnd); } };
2. 限制合法选择范围
添加selectAllow回调,直接禁止不符合时长规则的选择操作:
selectAllow={(info) => { const start = info.start; const end = info.end; const duration = (end - start) / (1000 *60); const startHour = start.getHours(); if (startHour >=10 && startHour <15) { // 仅允许1小时范围且不超过15:00 return duration ===60 && end.getHours() <=15; } else if (startHour >=15 && startHour <23) { // 仅允许90分钟范围且不超过23:00 return duration ===90 && end.getHours() <=23; } return false; }}
3. 自定义槽位显示(可选)
如果需要在日历上直观区分不同时段,可修改slotLabelContent添加标识:
slotLabelContent={arg => { const hour = arg.date.getHours(); if (hour >=10 && hour <15) { return <span>{arg.date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})} (1小时时段)</span>; } else if (hour >=15 && hour <23) { return <span>{arg.date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})} (1.5小时时段)</span>; } return ''; }}
三、最终配置调整要点
- 移除
snapDuration配置,避免强制时间对齐。 - 保留
slotMinTime="10:00:00"和slotMaxTime="23:00:00"限制可预订时段。 - 添加
selectAllow回调控制合法选择范围。 - 在
onSelectRange中完成时间规则修正。
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

