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

FullCalendar Scheduler:如何为多resources拆分垂直视图为单列日程布局?

Hey there! I get what you're aiming for—stacking each resource's daily agenda vertically instead of laying them out side-by-side. FullCalendar Scheduler doesn't have this layout out of the box, but with a bit of custom view configuration and DOM manipulation, you can absolutely build it. Here's a step-by-step solution I've used in similar projects:

Custom Vertical Resource Layout for FullCalendar Scheduler

1. Set Up a Custom Base View

Start by using the resourceTimeGridDay view as your foundation, since it already handles daily time slots and resource association. We'll extend it and hook into rendering events to rearrange the DOM.

2. Manipulate the DOM to Stack Resources

Use the viewDidMount and viewDidUpdate hooks to restructure the default horizontal resource columns into vertical stacked blocks. Here's the full code example:

document.addEventListener('DOMContentLoaded', function() {
  const calendarEl = document.getElementById('calendar');

  const calendar = new FullCalendar.Calendar(calendarEl, {
    schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
    plugins: ['resourceTimeline', 'resourceTimeGrid', 'interaction'],
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'resourceTimeGridDay'
    },
    // Define a custom view for our vertical layout
    views: {
      verticalResourceDay: {
        type: 'resourceTimeGridDay',
        duration: { days: 1 },
        slotMinTime: '00:00:00',
        slotMaxTime: '23:59:59'
      }
    },
    initialView: 'verticalResourceDay',
    // Your resource data
    resources: [
      { id: 'a', title: 'Room A' },
      { id: 'b', title: 'Room B' },
      { id: 'c', title: 'Room C' },
      { id: 'd', title: 'Room D' }
    ],
    // Sample events
    events: [
      { resourceId: 'a', start: '2024-05-20T09:00:00', end: '2024-05-20T12:00:00', title: 'Client Meeting' },
      { resourceId: 'b', start: '2024-05-20T14:00:00', end: '2024-05-20T16:30:00', title: 'Team Workshop' },
      { resourceId: 'c', start: '2024-05-20T10:00:00', end: '2024-05-20T11:30:00', title: 'Interview' }
    ],
    // Run this when the view first loads
    viewDidMount: function(info) {
      this._rearrangeResources(info);
    },
    // Run this when the view updates (e.g., switching dates)
    viewDidUpdate: function(info) {
      this._rearrangeResources(info);
    },
    // Helper function to restructure the DOM
    _rearrangeResources: function(info) {
      const bodyContainer = info.el.querySelector('.fc-timeGrid-body');
      const resourceColumns = bodyContainer.querySelectorAll('.fc-resource');
      
      // Clear the default horizontal layout
      bodyContainer.innerHTML = '';
      
      resourceColumns.forEach(col => {
        const resourceId = col.dataset.resourceId;
        const resource = calendar.getResourceById(resourceId);
        
        // Create a header for the resource
        const resourceHeader = document.createElement('div');
        resourceHeader.className = 'custom-resource-header';
        resourceHeader.textContent = resource.title;
        resourceHeader.style.cssText = `
          padding: 10px;
          background-color: #f5f5f5;
          border-bottom: 1px solid #ddd;
          font-weight: bold;
        `;
        
        // Extract the time slot content from the original column
        const slotContent = col.querySelector('.fc-timeGrid-slot');
        if (slotContent) {
          slotContent.style.width = '100%';
        }
        
        // Wrap header and slot content into a vertical block
        const resourceBlock = document.createElement('div');
        resourceBlock.className = 'custom-resource-block';
        resourceBlock.style.cssText = `
          margin-bottom: 20px;
          border: 1px solid #ddd;
          border-radius: 4px;
          overflow: hidden;
        `;
        
        resourceBlock.appendChild(resourceHeader);
        if (slotContent) resourceBlock.appendChild(slotContent);
        
        bodyContainer.appendChild(resourceBlock);
      });
    }
  });

  calendar.render();
});

3. Add CSS to Polish the Layout

Tweak the time slot styling to make the vertical layout look clean:

.custom-resource-block .fc-timeGrid-slot {
  display: flex;
  min-height: 40px;
}

.custom-resource-block .fc-slot-label {
  width: 90px;
  border-right: 1px solid #eee;
  padding-right: 8px;
  text-align: right;
  font-size: 0.9em;
  color: #666;
}

.custom-resource-block .fc-slot-content {
  flex: 1;
  padding-left: 8px;
}

/* Adjust event styling if needed */
.custom-resource-block .fc-event {
  cursor: pointer;
}

Key Notes

  • Interaction Testing: After modifying the DOM, test event dragging, resizing, and clicking to ensure they still work as expected. FullCalendar's event system should still recognize the resource association via resourceId, but you might need to adjust event handlers if you run into issues.
  • Performance: If you have a lot of resources, consider adding virtual scrolling or pagination, but for a small set (like your 4 rooms), this approach works smoothly.
  • Dynamic Updates: If resources or events change dynamically, call calendar.rerenderEvents() or trigger a view update to ensure the vertical blocks refresh correctly.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:00:10