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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 16:42:51