如何在时间线视图中按自定义天数设置自定义插槽标签?
当然可行!完全不用修改monthName数组,你可以通过FullCalendar的内置配置和事件,轻松实现按自定义天数划分的阶段标签。下面给你两种实用的实现思路,按需选择:
方案1:利用
slotLabelFormat自定义槽位标签 这种方式适合只想在时间槽上显示阶段名称的场景,通过回调函数计算每个日期所属的阶段,精准控制标签显示时机。
document.addEventListener('DOMContentLoaded', function() { // 先定义你的阶段规则:[阶段名称, 该阶段天数] const phaseConfig = [ { name: '阶段1', days: 20 }, { name: '阶段2', days: 55 }, { name: '阶段3', days: 150 } ]; const calendar = new FullCalendar.Calendar(document.getElementById('calendar'), { defaultView: 'timeline12Month', views: { timeline12Month: { type: 'timeline', duration: { week: 52 }, slotDuration: { day: 1 }, // 强制每个槽位对应1天,确保计算精准 slotLabelFormat: function(date) { // 计算当前日期与视图起始日的天数差 const viewStart = calendar.view.activeStart; const dayDifference = Math.floor((date - viewStart) / (1000 * 60 * 60 * 24)); // 匹配对应的阶段 let currentPhase = '后续阶段'; let cumulativeDays = 0; for (let phase of phaseConfig) { cumulativeDays += phase.days; if (dayDifference < cumulativeDays) { currentPhase = phase.name; break; } } // 只在阶段的第一天显示标签,避免重复刷屏 const phaseStartDays = phaseConfig.reduce((acc, cur, idx) => { acc.push(idx === 0 ? 0 : acc[idx-1] + cur.days); return acc; }, []); if (phaseStartDays.includes(dayDifference)) { return currentPhase; } return ''; // 非阶段起始日不显示标签 } } } }); calendar.render(); });
方案2:通过
datesRender事件手动添加阶段标签(带样式) 如果需要更灵活的视觉效果(比如给阶段加背景色、标签居中显示),可以用视图渲染事件手动生成标签和样式,自由度更高。
document.addEventListener('DOMContentLoaded', function() { const phaseConfig = [ { name: '阶段1', days: 20, bgColor: '#e8f5e9' }, { name: '阶段2', days: 55, bgColor: '#fff3e0' }, { name: '阶段3', days: 150, bgColor: '#f3e5f5' } ]; const calendar = new FullCalendar.Calendar(document.getElementById('calendar'), { defaultView: 'timeline12Month', views: { timeline12Month: { type: 'timeline', duration: { week: 52 }, slotDuration: { day: 1 } } }, datesRender: function(info) { // 先清除旧标签,避免重复渲染 info.el.querySelectorAll('.custom-phase-tag').forEach(tag => tag.remove()); const viewStart = info.view.activeStart; let dayOffset = 0; phaseConfig.forEach(phase => { // 计算当前阶段的起止日期 const phaseStart = new Date(viewStart); phaseStart.setDate(viewStart.getDate() + dayOffset); const phaseEnd = new Date(viewStart); phaseEnd.setDate(viewStart.getDate() + dayOffset + phase.days - 1); // 给阶段内的所有槽位添加背景色 const allSlots = info.el.querySelectorAll('.fc-slats .fc-time-grid-slot'); let phaseSlotCount = 0; allSlots.forEach(slot => { const slotDate = new Date(slot.dataset.date); if (slotDate >= phaseStart && slotDate <= phaseEnd) { slot.style.backgroundColor = phase.bgColor; phaseSlotCount++; } }); // 在阶段中间位置添加居中标签 if (phaseSlotCount > 0) { const firstSlot = info.el.querySelector(`.fc-slats .fc-time-grid-slot[data-date="${phaseStart.toISOString().split('T')[0]}"]`); if (firstSlot) { const tagEl = document.createElement('div'); tagEl.className = 'custom-phase-tag'; tagEl.textContent = phase.name; tagEl.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-weight: bold; width: ${phaseSlotCount * (100 / info.view.slotCount)}%; margin-left: -${(phaseSlotCount * (100 / info.view.slotCount))/2}%; `; firstSlot.appendChild(tagEl); } } dayOffset += phase.days; }); } }); calendar.render(); });
注意事项
- 两种方案都依赖
slotDuration: { day: 1 },确保每个时间槽对应一天,天数计算不会出错。 - 如果视图的起始日期动态变化,代码会自动基于当前视图的起始日重新计算阶段,无需额外调整。
内容的提问来源于stack exchange,提问作者Dimka Ganin
相关产品推荐
相关产品推荐

