React中FullCalendar(v5.11)滚动监听失效,自定义右键菜单无法隐藏求助
解决思路
1. 监听FullCalendar内部的滚动容器而非document
你的问题核心是FullCalendar时间轴的滚动并非触发document的scroll事件,而是其内部容器的滚动。直接监听document自然不会触发,而用捕获模式会监听全局所有滚动事件,导致频繁触发回调引发卡顿。
FullCalendar v5的时间轴滚动容器通常带有fc-scroller类(更精确的可以用.fc-timeline .fc-scroller区分时间轴容器),只需监听这个容器的scroll事件即可。
2. 结合React状态优化监听逻辑
可以通过FullCalendar的ref获取实例,进而找到内部滚动容器;同时只在右键菜单显示时添加监听,隐藏时移除,减少不必要的性能消耗:
import { useRef, useEffect, useState } from 'react'; import FullCalendar from '@fullcalendar/react'; import timelinePlugin from '@fullcalendar/timeline'; function TimelineCalendar() { const calendarRef = useRef(null); const [contextMenu, setContextMenu] = useState({ toggled: false, x: 0, y: 0 }); const resetContextMenu = () => { setContextMenu({ toggled: false, x: 0, y: 0 }); }; useEffect(() => { let scrollContainer = null; // 通过FullCalendar实例获取内部滚动容器 if (calendarRef.current) { const calendarApi = calendarRef.current.getApi(); scrollContainer = calendarApi.el.querySelector('.fc-timeline .fc-scroller'); } if (!scrollContainer) return; const handleScroll = () => { if (contextMenu.toggled) resetContextMenu(); }; // 仅当菜单显示时绑定滚动监听 if (contextMenu.toggled) { scrollContainer.addEventListener('scroll', handleScroll); } // 组件卸载或菜单隐藏时移除监听 return () => { scrollContainer.removeEventListener('scroll', handleScroll); }; }, [contextMenu.toggled]); // 依赖菜单显示状态,动态更新监听 return ( <div> <FullCalendar ref={calendarRef} plugins={[timelinePlugin]} initialView="timelineWeek" // 其他FullCalendar配置项 /> {/* 自定义右键菜单 */} {contextMenu.toggled && ( <div style={{ position: 'absolute', left: contextMenu.x, top: contextMenu.y, background: '#fff', border: '1px solid #ddd', padding: '8px' }} > {/* 菜单选项 */} <div>选项1</div> <div>选项2</div> </div> )} </div> ); }
3. 防抖优化(可选)
如果滚动时菜单隐藏的逻辑仍有性能问题,可以给resetContextMenu添加防抖,避免滚动过程中频繁触发:
import { debounce } from 'lodash'; // 在组件内定义防抖函数 const debouncedReset = useCallback( debounce(() => { if (contextMenu.toggled) resetContextMenu(); }, 50), // 50ms延迟,可根据需求调整 [contextMenu.toggled] ); // 修改handleScroll const handleScroll = () => { debouncedReset(); };
内容的提问来源于stack exchange,提问作者Minos
相关产品推荐
相关产品推荐

