react实现组合拖拽
React 实现组合拖拽
在 React 中实现组合拖拽功能可以通过多种方式完成,常见的方法是使用第三方库如 react-dnd 或 react-beautiful-dnd。以下是两种主要实现方式:
使用 react-dnd
react-dnd 是一个基于 HTML5 拖拽 API 的 React 拖拽库,适合复杂的拖拽场景。
安装依赖:
npm install react-dnd react-dnd-html5-backend
基本实现:

import { useDrag, useDrop, DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
const DraggableItem = ({ id, text }) => {
const [{ isDragging }, drag] = useDrag(() => ({
type: 'ITEM',
item: { id },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
}));
return (
<div
ref={drag}
style={{
opacity: isDragging ? 0.5 : 1,
padding: '8px',
margin: '4px',
border: '1px solid #ccc',
}}
>
{text}
</div>
);
};
const DropZone = ({ onDrop }) => {
const [{ isOver }, drop] = useDrop(() => ({
accept: 'ITEM',
drop: (item) => onDrop(item.id),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
}),
}));
return (
<div
ref={drop}
style={{
background: isOver ? '#f0f0f0' : '#fff',
padding: '16px',
border: '2px dashed #999',
}}
>
Drop here
</div>
);
};
const App = () => {
const handleDrop = (id) => {
console.log(`Item ${id} dropped`);
};
return (
<DndProvider backend={HTML5Backend}>
<div style={{ display: 'flex' }}>
<div>
<DraggableItem id="1" text="Item 1" />
<DraggableItem id="2" text="Item 2" />
</div>
<DropZone onDrop={handleDrop} />
</div>
</DndProvider>
);
};
使用 react-beautiful-dnd
react-beautiful-dnd 是另一个流行的拖拽库,适合列表重排序等场景。
安装依赖:

npm install react-beautiful-dnd
基本实现:
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
const items = [
{ id: '1', text: 'Item 1' },
{ id: '2', text: 'Item 2' },
];
const App = () => {
const [state, setState] = useState(items);
const onDragEnd = (result) => {
if (!result.destination) return;
const newItems = Array.from(state);
const [removed] = newItems.splice(result.source.index, 1);
newItems.splice(result.destination.index, 0, removed);
setState(newItems);
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{state.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
padding: '8px',
margin: '4px',
border: '1px solid #ccc',
...provided.draggableProps.style,
}}
>
{item.text}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
};
自定义实现
如果需要更轻量级的解决方案,可以直接使用 HTML5 拖拽 API:
const Draggable = ({ id, text }) => {
const handleDragStart = (e) => {
e.dataTransfer.setData('text/plain', id);
};
return (
<div
draggable
onDragStart={handleDragStart}
style={{ padding: '8px', margin: '4px', border: '1px solid #ccc' }}
>
{text}
</div>
);
};
const DropZone = ({ onDrop }) => {
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
const id = e.dataTransfer.getData('text/plain');
onDrop(id);
};
return (
<div
onDragOver={handleDragOver}
onDrop={handleDrop}
style={{ padding: '16px', border: '2px dashed #999' }}
>
Drop here
</div>
);
};
性能优化
对于大量拖拽项,使用 react-window 或 react-virtualized 进行虚拟滚动可以提升性能。
import { FixedSizeList } from 'react-window';
const Row = ({ data, index, style }) => (
<Draggable
id={data[index].id}
text={data[index].text}
style={style}
/>
);
const VirtualizedList = ({ items }) => (
<FixedSizeList
height={400}
width={300}
itemCount={items.length}
itemSize={50}
itemData={items}
>
{Row}
</FixedSizeList>
);





