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

如何在React FullCalendar中通过触摸事件实现周视图转月视图?

实现FullCalendar触摸下拉切换视图的可行方案

方案1:原生触摸事件监听+FullCalendar实例控制

这是无需额外依赖的直接实现方式,通过监听日历容器的触摸事件,判断下拉动作后调用FullCalendar的视图切换API完成功能。

实现步骤

  1. 给FullCalendar组件添加ref,用于获取日历实例
  2. 在组件挂载阶段,给日历容器绑定touchstart、touchmove、touchend事件
  3. 记录触摸起始位置,计算下拉位移,达到设定阈值且当前为周视图时,触发视图切换

代码示例(结合你的现有代码修改)

import { useRef, useEffect, useState } from 'react';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';

// 根据你实际使用的周视图类型调整,比如timeGridWeek
const WEEK_VIEW = 'dayGridWeek';
const MONTH_VIEW = 'dayGridMonth';
const PULL_THRESHOLD = 50; // 触发切换的最小下拉距离

const CalendarComponent = () => {
  const calendarRef = useRef(null);
  const [touchStartY, setTouchStartY] = useState(null);

  useEffect(() => {
    const calendarEl = calendarRef.current?.getApi().el;
    if (!calendarEl) return;

    const handleTouchStart = (e) => {
      setTouchStartY(e.touches[0].clientY);
    };

    const handleTouchMove = (e) => {
      if (touchStartY === null) return;
      const currentY = e.touches[0].clientY;
      const diff = currentY - touchStartY;
      
      // 下拉距离达标且当前是周视图时,切换到月视图
      if (diff > PULL_THRESHOLD && calendarRef.current.getApi().view.type === WEEK_VIEW) {
        calendarRef.current.getApi().changeView(MONTH_VIEW);
        setTouchStartY(null); // 重置起始位置,避免重复触发
      }
    };

    const handleTouchEnd = () => {
      setTouchStartY(null);
    };

    calendarEl.addEventListener('touchstart', handleTouchStart);
    calendarEl.addEventListener('touchmove', handleTouchMove);
    calendarEl.addEventListener('touchend', handleTouchEnd);

    return () => {
      calendarEl.removeEventListener('touchstart', handleTouchStart);
      calendarEl.removeEventListener('touchmove', handleTouchMove);
      calendarEl.removeEventListener('touchend', handleTouchEnd);
    };
  }, [touchStartY]);

  // 你的原有事件处理函数
  const handleDateClick = (arg) => {
    // ...你的业务逻辑
  };

  const renderEventContent = (arg) => {
    // ...你的业务逻辑
  };

  return (
    <FullCalendar
      ref={calendarRef} // 添加ref获取日历实例
      timeZone="local"
      weekNumberCalculation="ISO"
      plugins={[dayGridPlugin, interactionPlugin]}
      initialView={MONTH_VIEW}
      dateClick={handleDateClick}
      eventContent={renderEventContent}
      headerToolbar={{
        start: "title myCustomDatePickerButton",
        center: "",
        end: "myCustomStepButton myCustomSettingsButton",
      }}
      titleFormat={function (date) {
        return date.date.year + "" + (date.date.month + 1) + "";
      }}
      customButtons={{
        myCustomDatePickerButton: {
          click: ""
        },
        myCustomStepButton: {
          text: "",
        },
        myCustomSettingsButton: {
          click: function () {
            window.location.href = "";
          },
        },
      }}
      dayHeaderContent={function (arg) {
        return Day_Names[arg.date.getDay()];
      }}
      weekends={true}
      showNonCurrentDates={false}
      firstDay={false}
      formatDate={(day) => day.toLocaleString("en", { day: "numeric" })}
      events={events}
      droppable={true}
    />
  );
};

export default CalendarComponent;

注意事项

  • 需根据实际使用的周视图类型调整WEEK_VIEW变量
  • 可根据产品需求修改PULL_THRESHOLD数值,避免误触
  • 触摸事件绑定在日历容器上,确保事件能正确捕获

方案2:使用手势库简化触摸处理

如果需要更精准的手势识别(比如区分滑动速度、过滤误触),可以使用成熟的手势库react-use-gesture来简化逻辑。

实现步骤

  1. 安装依赖:npm install react-use-gesture
  2. 使用useGesture钩子监听下拉手势
  3. 触发FullCalendar的视图切换API

代码示例

import { useRef, useEffect } from 'react';
import { useGesture } from 'react-use-gesture';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';

const WEEK_VIEW = 'dayGridWeek';
const MONTH_VIEW = 'dayGridMonth';

const CalendarComponent = () => {
  const calendarRef = useRef(null);

  useEffect(() => {
    calendarRef.current?.getApi().el;
  }, []);

  // 绑定下拉手势监听
  const bind = useGesture({
    onDrag: ({ down, movement: [_, y], cancel }) => {
      if (!down) return;
      // 下拉距离达标且当前是周视图时切换
      if (y > 50 && calendarRef.current.getApi().view.type === WEEK_VIEW) {
        calendarRef.current.getApi().changeView(MONTH_VIEW);
        cancel(); // 终止后续手势事件,防止重复触发
      }
    },
    eventOptions: { passive: true } // 优化触摸事件性能
  });

  return (
    <div {...bind()} style={{ touchAction: 'pan-y' }}>
      <FullCalendar
        ref={calendarRef}
        // ...你的原有属性
      />
    </div>
  );
};

注意事项

  • 设置touchAction: 'pan-y'可避免浏览器默认滚动行为干扰手势识别
  • 可通过调整y的阈值来控制切换的灵敏度

内容的提问来源于stack exchange,提问作者iseank

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 16:35:25