React中FullCalendar如何为工作日与周末设置差异化时间分组?
需求实现:FullCalendar timeGridWeek视图工作日/周末差异化时间分组及额外列插入
问题描述
已给FullCalendar的timeGridWeek视图配置左侧时间分组为「6-2、2-10、10-6」,工作日显示正常,但希望周末(周六、周日)将时间分组改为「6am-6pm、6pm-6am」,理想状态下能在周五与周六之间插入额外列实现区分效果。
试过自定义视图等多种方法,但始终无法理清如何扩展现有视图或创建自定义视图,因场景小众,明确需要自定义功能但无从下手,技术栈为React。
当前配置代码
<FullCalendar schedulerLicenseKey="redacted" plugins={[ dayGridPlugin, timeGridPlugin, interactionPlugin, timeLinePlugin, resourceTimelinePlugin, scrollGridPlugin ]} timeZone="GMT" initialView={view} firstDay={1} headerToolbar={showToolbar ? { left: allowNavigation ? 'prev,next today' : '', center: 'title', right: allowNavigation ? 'timeGridWeek,timeGridDay,dayGridMonth' : '' } : false} events={events} contentHeight={750} eventClick={handleEventClick} slotMinTime="06:00:00" slotMaxTime="30:00:00" expandRows={true} stickyHeaderDates={true} nowIndicator={nowIndicator} slotDuration="08:00:00" slotLabelInterval="08:00:00" slotLabelFormat={(arg: { date: { marker: Date } }) => { const hour = arg.date.marker.getHours(); if (hour === 7) return '6-2'; if (hour === 15) return '2-10'; return '10-6'; }} allDaySlot={false} dayHeaderFormat={{ weekday: view === 'dayGridMonth' ? 'short' : 'short', day: view === 'dayGridMonth' ? 'numeric' : 'numeric', omitCommas: true }} views={{ dayGridMonth: { dayHeaderFormat: { weekday: 'long' } }, timeGridWeek: { dayHeaderFormat: { weekday: 'short', day: showDateNumbers ? 'numeric' : undefined } }, timeGridDay: { dayHeaderFormat: { weekday: 'long', day: showDateNumbers ? 'numeric' : undefined, month: 'long' } }, timeGridMonth: { type: 'timeGrid', duration: { months: 1 }, dayMinWidth: 150, buttonText: 'timeline', dayHeaderFormat: { weekday: 'short', day: 'numeric', month: 'short', omitCommas: true }, eventMaxStack: 6, eventContent: (arg) => { const content = renderEventContent({ event: arg.event }); return { html: `<div class="event-content-wrapper">${ typeof content === 'string' ? content : ReactDOMServer.renderToString(content as ReactElement) }</div>` }; } } }} eventClassNames={(arg) => eventClassNames?.({ event: arg.event }) || ''} eventContent={(arg) => renderEventContent({ event: arg.event })} dayMaxEvents={true} />
解决方案
一、工作日/周末差异化时间分组
核心是在slotLabelFormat中结合日期判断周几,动态返回分组标签,同时动态调整slot的时间间隔配置:
- 修改slotLabelFormat回调
通过arg.date.marker获取完整日期,判断是否为周末,返回对应标签:
slotLabelFormat={(arg) => { const date = arg.date.marker; const dayOfWeek = date.getDay(); // 0=周日,1-5=周一至周五,6=周六 const hour = date.getHours(); // 周末逻辑 if (dayOfWeek === 0 || dayOfWeek === 6) { if (hour === 6) return '6am-6pm'; if (hour === 18) return '6pm-6am'; return ''; // 中间小时不显示标签 } // 工作日逻辑 if (hour === 7) return '6-2'; if (hour === 15) return '2-10'; return '10-6'; }}
- 动态调整slotDuration和slotLabelInterval
通过视图钩子监听日期变化,判断当前周是否包含周末,动态修改配置:
import { useRef } from 'react'; const calendarRef = useRef(null); const handleViewUpdate = (info) => { const view = info.view; const startDate = new Date(view.activeStart); const endDate = new Date(view.activeEnd); let hasWeekend = false; // 遍历日期判断是否包含周末 const currentDate = new Date(startDate); while (currentDate < endDate) { const day = currentDate.getDay(); if (day === 0 || day === 6) { hasWeekend = true; break; } currentDate.setDate(currentDate.getDate() + 1); } const calendarApi = calendarRef.current.getApi(); if (hasWeekend) { calendarApi.setOption('slotDuration', '12:00:00'); calendarApi.setOption('slotLabelInterval', '12:00:00'); } else { calendarApi.setOption('slotDuration', '08:00:00'); calendarApi.setOption('slotLabelInterval', '08:00:00'); } }; // 在FullCalendar组件中添加钩子 <FullCalendar ref={calendarRef} // ...其他配置 viewDidMount={handleViewUpdate} viewDidUpdate={handleViewUpdate} />
二、周五与周六之间插入额外列
推荐使用资源视图方案,符合FullCalendar设计规范:
- 切换为resourceTimeGridWeek视图
利用已引入的resourceTimelinePlugin,将日期转为资源,并在周五后插入分隔资源:
const getWeekResources = (startDate) => { const resources = []; const currentDate = new Date(startDate); // firstDay=1(周一),循环7天 for (let i = 0; i < 7; i++) { resources.push({ id: `day-${i}`, title: `${currentDate.toLocaleDateString('en-US', { weekday: 'short', day: 'numeric' })}`, date: new Date(currentDate) }); // 周五是第4个索引(0=周一,4=周五),插入分隔列 if (i === 4) { resources.push({ id: 'separator', title: '', className: 'weekend-separator' }); } currentDate.setDate(currentDate.getDate() + 1); } return resources; }; // 修改FullCalendar配置 <FullCalendar ref={calendarRef} initialView="resourceTimeGridWeek" resources={getWeekResources(new Date())} // 日期切换时更新资源 datesSet={(info) => { const resources = getWeekResources(info.start); calendarRef.current.getApi().removeAllResources(); calendarRef.current.getApi().addResource(resources); }} // ...其他配置 />
- CSS美化分隔列
.weekend-separator { width: 20px; background-color: #f5f5f5; border-left: 2px solid #ddd; }
三、注意事项
- 动态修改配置时依赖FullCalendar的
setOptionAPI,需确保版本兼容性 - 时区为GMT,处理日期时需注意时区转换,避免周几判断错误
- 资源视图方案维护性更强,优先选择;若需快速实现,也可通过DOM操作直接插入列(但需处理视图更新时的重新渲染问题)
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

