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

如何实现React Big Calendar外部元素拖拽至日历内?

实现外部元素拖拽到React Big Calendar的方案

首先得确保你已经安装了所需依赖:

npm install react-big-calendar react-dnd react-dnd-html5-backend

接下来分步骤改造组件,把外部元素变成可拖拽源,让日历成为可投放目标,亲测这个流程能完美实现你要的效果~

1. 打造可拖拽的外部组件(External)

我们用react-dnd的useDrag钩子把普通组件改成可拖拽元素,这里定义拖拽类型为"EXTERNAL_EVENT",同时传递拖拽的初始事件数据:

import { useDrag } from 'react-dnd';

const External = () => {
  const [{ isDragging }, dragRef] = useDrag(() => ({
    type: "EXTERNAL_EVENT",
    item: {
      title: "新增外部事件",
      start: new Date(),
      end: new Date(new Date().getTime() + 60 * 60 * 1000) // 默认1小时时长
    },
    collect: (monitor) => ({
      isDragging: monitor.isDragging()
    })
  }));

  return (
    <div
      ref={dragRef}
      style={{
        padding: '10px',
        backgroundColor: isDragging ? '#e0e0e0' : '#2196f3',
        color: 'white',
        cursor: 'move',
        width: '200px',
        marginBottom: '20px'
      }}
    >
      拖拽我到日历里
    </div>
  );
};

2. 改造Calendar组件支持外部拖拽投放

这里用react-dnd的useDrop钩子监听我们定义的拖拽类型,同时结合React Big Calendar的内置方法,把拖拽位置转换成对应的日期时间,最后将新事件添加到日历列表中:

import { Calendar as BigCalendar, momentLocalizer } from 'react-big-calendar';
import moment from 'moment';
import { useDrop } from 'react-dnd';

const localizer = momentLocalizer(moment);

const Calendar = ({ events, onAddEvent }) => {
  const [{ isOver }, dropRef] = useDrop(() => ({
    accept: "EXTERNAL_EVENT",
    drop: (item, monitor) => {
      const calendarElement = dropRef.current;
      if (!calendarElement) return;

      // 获取鼠标在日历内的坐标
      const offset = monitor.getClientOffset();
      const rect = calendarElement.getBoundingClientRect();
      const x = offset.x - rect.left;
      const y = offset.y - rect.top;

      // 利用日历内置方法把坐标转成对应日期
      const date = calendarElement.getDateFromPoint(x, y);
      if (date) {
        const newEvent = {
          ...item,
          start: date,
          end: new Date(date.getTime() + 60 * 60 * 1000)
        };
        onAddEvent(newEvent);
      }
    },
    collect: (monitor) => ({
      isOver: monitor.isOver()
    })
  }));

  return (
    <div
      ref={dropRef}
      style={{
        height: '500px',
        border: isOver ? '2px dashed #2196f3' : '1px solid #eee'
      }}
    >
      <BigCalendar
        localizer={localizer}
        events={events}
        startAccessor="start"
        endAccessor="end"
        style={{ height: '100%' }}
      />
    </div>
  );
};

3. 整合到Application组件

最后把两个组件整合起来,维护好事件列表的状态:

import { useState } from 'react';

const Application = () => {
  const [events, setEvents] = useState([]);

  const handleAddEvent = (newEvent) => {
    setEvents([...events, newEvent]);
  };

  return (
    <div style={{ display: 'flex', gap: '20px', padding: '20px' }}>
      <External />
      <Calendar events={events} onAddEvent={handleAddEvent} />
    </div>
  );
};

关键注意点

  • 一定要在应用顶层组件包裹DndProvider,引入html5后端,否则拖拽功能会失效:
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

function App() {
  return (
    <DndProvider backend={HTML5Backend}>
      <Application />
    </DndProvider>
  );
}
  • getDateFromPoint是React Big Calendar DOM元素的内置方法,能直接把坐标转换成对应日期,省去了自己计算时间的麻烦
  • 拖拽过程中的样式反馈(比如isDragging、isOver状态)可以让用户更清晰感知拖拽状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:28:46