FullCalendar.js时间线日历交叉悬停效果行高适配问题
解决FullCalendar时间线日历交叉悬停行高错位问题
你的问题核心在于静态叠加表格的行高无法同步FullCalendar动态变化的行高——当事件是多行描述、同时间段多事件挤在一起时,日历行高会自动调整,但你手动加的表格行高还是固定值,自然会出现悬停层重叠错位。
下面是直接可行的解决方案,放弃静态叠加表格,基于FullCalendar自身DOM结构实现动态悬停:
1. 核心思路
- 利用FullCalendar的
datesRender事件(日历渲染/更新时触发),实时同步行的位置和尺寸,生成动态悬停触发层 - 通过事件委托或直接绑定行元素的悬停事件,实现行+列的交叉高亮
- 完全依赖日历自身DOM的实时尺寸,避免静态元素的错位问题
2. 具体代码实现
JavaScript 部分
document.addEventListener('DOMContentLoaded', function() { const calendarEl = document.getElementById('calendar'); const calendar = new FullCalendar.Calendar(calendarEl, { // 保留你原来的日历配置(视图、事件数据等) initialView: 'timeGridWeek', events: [ // 你的事件数据 ], // 每次日历渲染/更新时同步悬停层 datesRender: function(info) { // 先清除旧的悬停层 document.querySelectorAll('.hover-overlay').forEach(el => el.remove()); const timelineContainer = info.el.querySelector('.fc-timeGridWeek-view .fc-time-grid'); // 获取所有日历行(包括事件行和空白槽位) const timelineRows = timelineContainer.querySelectorAll('.fc-time-grid-event-harness, .fc-time-grid-slot'); timelineRows.forEach(row => { // 创建悬停触发层(覆盖整行,仅用于捕获鼠标事件) const overlay = document.createElement('div'); overlay.className = 'hover-overlay'; // 同步行的位置和尺寸 const rowRect = row.getBoundingClientRect(); const containerRect = timelineContainer.getBoundingClientRect(); overlay.style.position = 'absolute'; overlay.style.top = `${rowRect.top - containerRect.top}px`; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = `${rowRect.height}px`; overlay.style.pointerEvents = 'auto'; overlay.style.opacity = '0'; // 透明不影响视觉 timelineContainer.appendChild(overlay); // 绑定悬停事件 overlay.addEventListener('mouseenter', () => { // 高亮当前行 row.classList.add('row-hover-highlight'); // 高亮鼠标对应的列 highlightCurrentColumn(timelineContainer, event.clientX); }); overlay.addEventListener('mouseleave', () => { row.classList.remove('row-hover-highlight'); clearColumnHighlight(timelineContainer); }); }); } }); calendar.render(); }); // 辅助函数:高亮鼠标所在列 function highlightCurrentColumn(container, clientX) { const containerRect = container.getBoundingClientRect(); const x = clientX - containerRect.left; const columns = container.querySelectorAll('.fc-day'); columns.forEach(col => { const colRect = col.getBoundingClientRect(); const colLeft = colRect.left - containerRect.left; const colRight = colRect.right - containerRect.left; if (x >= colLeft && x <= colRight) { col.classList.add('column-hover-highlight'); } }); } // 辅助函数:清除列高亮 function clearColumnHighlight(container) { container.querySelectorAll('.column-hover-highlight').forEach(el => { el.classList.remove('column-hover-highlight'); }); }
CSS 部分
/* 行高亮样式 */ .row-hover-highlight { background-color: rgba(102, 178, 255, 0.15); } /* 列高亮样式 */ .column-hover-highlight { background-color: rgba(102, 178, 255, 0.15); } /* 日历容器需要开启相对定位,让悬停层能基于它定位 */ .fc-time-grid { position: relative; }
3. 为什么之前的方法无效?
- 静态表格的行高是预先设定的,无法响应FullCalendar动态调整的行高(比如多行事件、多事件叠加导致的行高拉伸)
clientHeight只能获取初始渲染的行高,无法监听后续行高变化;鼠标定位容易受滚动、缩放影响,精度不足pointer-events:none会让悬停层失去事件捕获能力,无法触发高亮逻辑
内容的提问来源于stack exchange,提问作者user9737577
相关产品推荐
相关产品推荐

