You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FullCalendar长周期事件如何禁用节假日等指定日期

FullCalendar 长周期课程事件跳过节假日展示方案

核心实现逻辑不需要修改原始业务事件数据,通过事件加载阶段的预处理拆分长周期事件,即可实现节假日时段自动隐藏长课程,不影响固定日期的短课程正常展示,步骤如下:

  • 先维护本地节假日日期集合,统一使用YYYY-MM-DD格式存储,避免时分秒、时区问题导致匹配失效:
// 节假日日期集合,可根据每年官方放假安排动态更新
const holidaySet = new Set([
  '2022-06-03',
  '2022-09-10',
  '2022-10-01',
  '2022-10-02',
  '2022-10-03'
  // 其余节假日按相同格式补充即可
])
  • 替换原有静态events配置为动态回调,在回调里区分两类事件处理:
    • 带multi_day: "selected"标记的固定日期短事件(单次音乐/拳击/语言课),本身不会排期在节假日,直接透传展示即可
    • 带end字段的跨月长周期课程,遍历事件覆盖的日期区间,遇到节假日就截断事件段,自动跳过假期拆分出多个连续的非假期事件段,交给日历渲染
  • 完整配置示例:
const calendarEl = document.getElementById('calendar')
const calendar = new FullCalendar.Calendar(calendarEl, {
  initialView: 'dayGridMonth',
  // 替换原有静态events配置
  events: (fetchInfo, successCallback) => {
    // 原始事件数据,直接替换为你现有接口返回/本地定义的events数组即可
    const rawEvents = [
      {
        "title": "selected dates Events",
        "allDay": false,
        "start": "2022-06-16T15:03:00",
        "unformated_date": "June 16, 2022",
        "url": "http://localhost:8888/boxingstudio/product/selected-dates-events/",
        "post_id": 536,
        "multi_day": "selected",
        "color": "#16a75d",
        "textColor": "#ffffff",
        "in_stock": "yes"
      },
      {
        "title": "selected dates Events",
        "allDay": false,
        "start": "2022-06-23T15:03:00",
        "unformated_date": "",
        "url": "http://localhost:8888/boxingstudio/product/selected-dates-events/",
        "post_id": 536,
        "multi_day": "selected",
        "color": "#16a75d",
        "textColor": "#ffffff",
        "in_stock": "yes"
      },
      {
        "title": "selected dates Events",
        "allDay": false,
        "start": "2022-06-25T15:03:00",
        "unformated_date": "June 25, 2022",
        "url": "http://localhost:8888/boxingstudio/product/selected-dates-events/",
        "post_id": 536,
        "multi_day": "selected",
        "color": "#16a75d",
        "textColor": "#ffffff",
        "in_stock": "yes"
      },
      {
        "title": "selected dates Events",
        "allDay": false,
        "start": "2022-06-26T15:03:00",
        "unformated_date": "June 26, 2022",
        "url": "http://localhost:8888/boxingstudio/product/selected-dates-events/",
        "post_id": 536,
        "multi_day": "selected",
        "color": "#16a75d",
        "textColor": "#ffffff",
        "in_stock": "yes"
      },
      {
        "title": "selected dates Events",
        "allDay": false,
        "start": "2022-06-29T15:03:00",
        "unformated_date": "June 29, 2022",
        "url": "http://localhost:8888/boxingstudio/product/selected-dates-events/",
        "post_id": 536,
        "multi_day": "selected",
        "color": "#16a75d",
        "textColor": "#ffffff",
        "in_stock": "yes"
      },
      {
        "title": "New Kick Boxing Product 1233",
        "allDay": false,
        "start": "2022-06-23T00:00:00",
        "unformated_date": "June 23, 2022",
        "url": "http://localhost:8888/boxingstudio/product/new-kick-boxing-product-1233/",
        "post_id": 535,
        "color": "#16a75d",
        "textColor": "#ffffff",
        "end": "2024-04-19T00:00:00",
        "unformated_end_date": "April 19, 2024",
        "in_stock": "yes"
      },
      {
        "title": "Kick Boxing Test",
        "allDay": false,
        "start": "2022-06-20T03:02:00",
        "unformated_date": "June 20, 2022",
        "url": "http://localhost:8888/boxingstudio/product/kick-boxing-test/",
        "post_id": 531,
        "color": "#16a75d",
        "textColor": "#ffffff",
        "end": "2022-07-18T14:02:00",
        "unformated_end_date": "July 18, 2022",
        "in_stock": "yes"
      }
    ]
    const processed = []

    rawEvents.forEach(ev => {
      // 短事件直接透传
      if (!ev.end || ev.multi_day === 'selected') {
        processed.push(ev)
        return
      }

      // 拆分长周期事件
      const evStart = new Date(ev.start)
      const evEnd = new Date(ev.end)
      let segStart = new Date(evStart)
      const curDate = new Date(evStart)

      while (curDate <= evEnd) {
        const dateStr = curDate.toISOString().split('T')[0]
        // 碰到节假日,截断之前的非假期段
        if (holidaySet.has(dateStr)) {
          if (segStart < curDate) {
            processed.push({
              ...ev,
              start: new Date(segStart),
              end: new Date(curDate)
            })
          }
          // 跳过假期,设置新段起点为假期后一天
          segStart = new Date(curDate)
          segStart.setDate(segStart.getDate() + 1)
        }
        curDate.setDate(curDate.getDate() + 1)
      }

      // 补入最后一段非假期区间
      if (segStart < evEnd) {
        processed.push({
          ...ev,
          start: new Date(segStart),
          end: new Date(evEnd)
        })
      }
    })

    successCallback(processed)
  }
})
calendar.render()

版本兼容提示:如果使用v4及更早版本的FullCalendar,把上述事件拆分逻辑挪到eventDataTransform钩子中执行即可,核心判断逻辑不需要改动。

  • 后续维护技巧:如果需要动态更新节假日列表,更新holidaySet集合后调用calendar.refetchEvents()就能即时刷新日历视图,不需要重新初始化实例。

内容的提问来源于stack exchange,提问作者Karthikvijayaveni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:57:14