如何实现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
相关产品推荐
相关产品推荐

