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:
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

