react拖拽实现
实现拖拽的基本步骤
安装依赖库react-dnd和react-dnd-html5-backend:
npm install react-dnd react-dnd-html5-backend
创建可拖拽组件需要使用useDrag钩子:
import { useDrag } from 'react-dnd';
function DraggableItem({ item }) {
const [{ isDragging }, drag] = useDrag(() => ({
type: 'ITEM',
item: { id: item.id },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
}));
return (
<div ref={drag} style={{ opacity: isDragging ? 0.5 : 1 }}>
{item.content}
</div>
);
}
创建放置区域
使用useDrop钩子实现放置区域:
import { useDrop } from 'react-dnd';
function DropZone({ onDrop }) {
const [{ isOver }, drop] = useDrop(() => ({
accept: 'ITEM',
drop: (item) => onDrop(item.id),
collect: (monitor) => ({
isOver: !!monitor.isOver(),
}),
}));
return (
<div ref={drop} style={{ backgroundColor: isOver ? 'lightgreen' : 'white' }}>
放置区域
</div>
);
}
组合组件并管理状态
在父组件中管理拖拽状态:

import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
function App() {
const [items, setItems] = useState([...]);
const [droppedItems, setDroppedItems] = useState([]);
const handleDrop = (id) => {
const item = items.find(i => i.id === id);
setDroppedItems([...droppedItems, item]);
};
return (
<DndProvider backend={HTML5Backend}>
<div>
{items.map(item => (
<DraggableItem key={item.id} item={item} />
))}
<DropZone onDrop={handleDrop} />
</div>
</DndProvider>
);
}
高级自定义选项
实现自定义拖拽预览:
const [{ isDragging }, drag, preview] = useDrag(() => ({
type: 'ITEM',
item: { id },
}));
return (
<>
<div ref={preview} style={{ position: 'absolute', opacity: 0 }}>
预览内容
</div>
<div ref={drag}>实际内容</div>
</>
);
添加拖拽限制条件:

useDrop(() => ({
accept: 'ITEM',
canDrop: (item) => item.type === 'ALLOWED_TYPE',
drop: (item) => {...},
}));
触摸设备支持
对于移动设备,需要安装react-dnd-touch-backend:
npm install react-dnd-touch-backend
然后替换backend:
import { TouchBackend } from 'react-dnd-touch-backend';
<DndProvider backend={TouchBackend} options={{ enableMouseEvents: true }}>
...
</DndProvider>
性能优化建议
对于大量可拖拽项,使用useMemo优化:
const items = useMemo(() => data.map(item => (
<DraggableItem key={item.id} item={item} />
)), [data]);
避免不必要的重渲染,将拖拽逻辑与展示组件分离。






