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

实现FullCalendar在dayGridMonth模式下按时间比例渲染事件

FullCalendar dayGridMonth模式按时间比例渲染事件

需求与问题

  • 目标:在只读的dayGridMonth视图中,事件按起止时间的比例渲染,避免同一天内非重叠事件(如11:00结束和15:00开始的事件)重叠;支持跨多日期的事件,不显示时间标签,例如15:00开始的事件从单元格宽度的62.5%位置开始。
  • 当前问题:默认渲染会让事件占满整个日期单元格,导致非重叠事件出现重叠;尝试slotEventOverlap: false、slotDuration: '01:00:00'及eventDidMount/eventPositioned原生回调均未达到预期效果。

解决方案

核心思路是通过eventDidMount回调手动计算每个事件在对应日期单元格内的位置和宽度,基于事件的起止时间与全天时长的比例来调整样式。

完整代码示例

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='utf-8' />
  <script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.5/index.global.min.js'></script>
  <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/6.1.5/main.min.css' />
  <style>
    #calendar {
      width: 60vw;
      height: 70vh;
      margin: auto;
    }
    /* 移除事件默认内边距,避免样式冲突 */
    .fc-daygrid-event {
      padding: 2px !important;
      border-radius: 2px;
    }
  </style>
  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const calendarEl = document.getElementById('calendar');
      const DAY_MINUTES = 1440; // 一天总分钟数

      const calendar = new FullCalendar.Calendar(calendarEl, {
        initialView: 'dayGridMonth',
        headerToolbar: {
          left: 'prev,next today',
          center: 'title',
          right: ''
        },
        eventStartEditable: false,
        eventDurationEditable: false,
        defaultAllDay: false,
        displayEventTime: false,
        displayEventEnd: false,
        events: [
          { start: '2023-04-16T15:00:00', end: '2023-04-19T11:00:00' },
          { start: '2023-04-19T15:00:00', end: '2023-04-22T11:00:00' },
          { start: '2023-04-22T15:00:00', end: '2023-04-25T11:00:00' },
          { start: '2023-04-25T15:00:00', end: '2023-05-10T11:00:00' }
        ],
        eventDidMount: function(info) {
          const eventEl = info.el;
          const event = info.event;
          const startDate = event.start;
          const endDate = event.end;
          
          // 获取事件覆盖的所有日期单元格
          const dayEls = eventEl.querySelectorAll('.fc-daygrid-event-harness');
          
          dayEls.forEach((dayEl, index) => {
            // 计算当前单元格对应的日期
            const cellDate = new Date(dayEl.closest('.fc-daygrid-day').dataset.date);
            cellDate.setHours(0, 0, 0, 0);
            
            let startMinutes, endMinutes;
            
            if (index === 0) {
              // 事件起始日期:计算当天内的开始和结束分钟
              startMinutes = startDate.getHours() * 60 + startDate.getMinutes();
              endMinutes = Math.min(DAY_MINUTES, (endDate > cellDate ? DAY_MINUTES : endDate.getHours() * 60 + endDate.getMinutes()));
            } else if (index === dayEls.length - 1) {
              // 事件结束日期:计算当天内的开始和结束分钟
              startMinutes = 0;
              endMinutes = endDate.getHours() * 60 + endDate.getMinutes();
            } else {
              // 中间日期:事件占满全天
              startMinutes = 0;
              endMinutes = DAY_MINUTES;
            }
            
            // 计算位置和宽度比例
            const startRatio = (startMinutes / DAY_MINUTES) * 100;
            const widthRatio = ((endMinutes - startMinutes) / DAY_MINUTES) * 100;
            
            // 应用样式
            const eventContentEl = dayEl.querySelector('.fc-daygrid-event');
            eventContentEl.style.position = 'absolute';
            eventContentEl.style.left = `${startRatio}%`;
            eventContentEl.style.width = `${widthRatio}%`;
            eventContentEl.style.top = '2px';
            eventContentEl.style.bottom = '2px';
          });
        }
      });
      
      calendar.render();
    });
  </script>
</head>
<body>
  <div id='calendar'></div>
</body>
</html>

关键逻辑说明

  1. 时间比例计算:以一天1440分钟为基准,将事件的起止时间转换为分钟数,计算出在当天的占比。
  2. 分日期处理:
    • 起始日期:事件从当天的startRatio位置开始,宽度为当天持续时间的比例。
    • 结束日期:事件从当天0点开始,宽度为当天持续时间的比例。
    • 中间日期:事件占满整个单元格。
  3. 样式调整:通过绝对定位设置事件的left和width,确保按比例渲染。

注意事项

  • 确保事件的allDay属性为false,FullCalendar才会识别为定时事件。
  • 替换了旧版本的FullCalendar样式文件,避免版本不兼容问题。
  • 自定义样式时移除默认事件的内边距,保证定位准确。

内容的提问来源于stack exchange,提问作者Andrew at the beach

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 12:37:49