react实现组件拖拽
实现拖拽功能的基本方法
使用HTML5的拖放API结合React状态管理实现基础拖拽。需要监听dragstart、dragend、dragover和drop事件。
import { useState } from 'react';
function DraggableComponent() {
const [isDragging, setIsDragging] = useState(false);
const handleDragStart = (e) => {
e.dataTransfer.setData('text/plain', 'drag-data');
setIsDragging(true);
};
const handleDragEnd = () => {
setIsDragging(false);
};
return (
<div
draggable
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
style={{
opacity: isDragging ? 0.5 : 1,
cursor: 'move'
}}
>
Drag me
</div>
);
}
实现拖放目标区域
创建可放置区域需要处理dragover和drop事件,阻止默认行为是关键。

function DropZone() {
const [hasDropped, setHasDropped] = useState(false);
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
const data = e.dataTransfer.getData('text/plain');
console.log('Dropped data:', data);
setHasDropped(true);
};
return (
<div
onDragOver={handleDragOver}
onDrop={handleDrop}
style={{
width: '200px',
height: '200px',
border: '2px dashed gray',
backgroundColor: hasDropped ? 'lightgreen' : 'white'
}}
>
Drop here
</div>
);
}
使用第三方库react-dnd
对于复杂拖拽场景,推荐使用react-dnd库。安装命令:npm install react-dnd react-dnd-html5-backend
import { useDrag, useDrop } from 'react-dnd';
function DraggableItem({ id, text, moveItem }) {
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',
backgroundColor: 'lightblue',
cursor: 'move'
}}
>
{text}
</div>
);
}
function DropContainer({ children }) {
const [, drop] = useDrop({
accept: 'ITEM',
drop: (item, monitor) => {
console.log('Dropped item:', item);
}
});
return (
<div
ref={drop}
style={{
width: '300px',
minHeight: '200px',
border: '2px solid gray',
padding: '16px'
}}
>
{children}
</div>
);
}
实现列表排序拖拽
结合react-dnd实现可排序列表需要处理hover状态和位置交换。

function SortableList({ items, onMove }) {
return (
<DropContainer>
{items.map((item, index) => (
<SortableItem
key={item.id}
index={index}
item={item}
onMove={onMove}
/>
))}
</DropContainer>
);
}
function SortableItem({ item, index, onMove }) {
const [, drop] = useDrop({
accept: 'ITEM',
hover(draggedItem) {
if (draggedItem.index !== index) {
onMove(draggedItem.index, index);
draggedItem.index = index;
}
}
});
const [{ isDragging }, drag] = useDrag({
type: 'ITEM',
item: { ...item, index },
collect: (monitor) => ({
isDragging: !!monitor.isDragging()
})
});
return (
<div
ref={(node) => drag(drop(node))}
style={{
opacity: isDragging ? 0.5 : 1,
padding: '8px',
margin: '4px',
backgroundColor: 'lightblue',
cursor: 'move'
}}
>
{item.text}
</div>
);
}
性能优化建议
对于大型列表实现拖拽时,考虑使用react-window或react-virtualized进行虚拟滚动。避免在拖拽过程中频繁重渲染整个列表。
自定义拖拽预览可以通过useDrag的preview选项实现,或者使用HTML5的setDragImage方法。
const [, drag, preview] = useDrag({
type: 'ITEM',
item: { id }
});
useEffect(() => {
const img = new Image();
img.src = 'preview.png';
preview(img);
}, [preview]);






