react 组件 实现拖拽
实现拖拽功能的 React 组件
使用 HTML5 原生拖拽 API
HTML5 提供了原生拖拽 API,可以通过 draggable 属性、onDragStart、onDragOver 和 onDrop 等事件实现基础拖拽功能。
import React, { useState } from 'react';
const DragAndDrop = () => {
const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);
const [draggedItem, setDraggedItem] = useState(null);
const handleDragStart = (index) => {
setDraggedItem(items[index]);
};
const handleDragOver = (index, e) => {
e.preventDefault();
const newItems = [...items];
const draggedOverItem = newItems[index];
if (draggedItem === draggedOverItem) return;
newItems.splice(items.indexOf(draggedItem), 1);
newItems.splice(index, 0, draggedItem);
setItems(newItems);
};
return (
<div>
{items.map((item, index) => (
<div
key={item}
draggable
onDragStart={() => handleDragStart(index)}
onDragOver={(e) => handleDragOver(index, e)}
style={{
padding: '10px',
margin: '5px',
backgroundColor: '#f0f0f0',
cursor: 'move'
}}
>
{item}
</div>
))}
</div>
);
};
export default DragAndDrop;
使用第三方库 react-dnd
对于更复杂的拖拽场景,推荐使用 react-dnd 库,它提供了更强大的功能和更好的性能。
import React from 'react';
import { DndProvider, useDrag, useDrop } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
const ItemType = 'ITEM';
const DraggableItem = ({ item, index, moveItem }) => {
const [{ isDragging }, drag] = useDrag({
type: ItemType,
item: { index },
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
const [, drop] = useDrop({
accept: ItemType,
hover: (draggedItem) => {
if (draggedItem.index !== index) {
moveItem(draggedItem.index, index);
draggedItem.index = index;
}
},
});
return (
<div
ref={(node) => drag(drop(node))}
style={{
opacity: isDragging ? 0.5 : 1,
padding: '10px',
margin: '5px',
backgroundColor: '#f0f0f0',
cursor: 'move'
}}
>
{item}
</div>
);
};
const DragAndDropList = () => {
const [items, setItems] = React.useState(['Item 1', 'Item 2', 'Item 3']);
const moveItem = (fromIndex, toIndex) => {
const newItems = [...items];
const [removed] = newItems.splice(fromIndex, 1);
newItems.splice(toIndex, 0, removed);
setItems(newItems);
};
return (
<div>
{items.map((item, index) => (
<DraggableItem
key={item}
item={item}
index={index}
moveItem={moveItem}
/>
))}
</div>
);
};
const App = () => (
<DndProvider backend={HTML5Backend}>
<DragAndDropList />
</DndProvider>
);
export default App;
使用 react-beautiful-dnd 库
react-beautiful-dnd 是另一个流行的拖拽库,特别适合列表重排序场景。
import React, { useState } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
const DragAndDropList = () => {
const [items, setItems] = useState([
{ id: '1', content: 'Item 1' },
{ id: '2', content: 'Item 2' },
{ id: '3', content: 'Item 3' },
]);
const onDragEnd = (result) => {
if (!result.destination) return;
const newItems = Array.from(items);
const [removed] = newItems.splice(result.source.index, 1);
newItems.splice(result.destination.index, 0, removed);
setItems(newItems);
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
{items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
...provided.draggableProps.style,
padding: '10px',
margin: '5px',
backgroundColor: '#f0f0f0',
}}
>
{item.content}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
};
export default DragAndDropList;
性能优化建议
对于大型列表,应该考虑虚拟化技术(如 react-window)与拖拽库结合使用。react-beautiful-dnd 提供了与 react-window 的集成方案。
所有拖拽操作都应考虑无障碍访问,确保键盘操作可用并为屏幕阅读器提供适当的 ARIA 属性。







