react 实现拖拽的组件
使用 react-dnd 实现拖拽
react-dnd 是一个流行的 React 拖拽库,基于 HTML5 的拖拽 API 实现。安装 react-dnd 和它的 HTML5 后端依赖:
npm install react-dnd react-dnd-html5-backend
创建一个可拖拽的组件:
import { useDrag } from 'react-dnd';
function 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,
cursor: 'move',
}}
>
{text}
</div>
);
}
创建一个可放置的区域:
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 ? 'lightblue' : 'white',
minHeight: '200px',
border: '1px dashed gray',
}}
>
Drop here
</div>
);
}
在应用中使用这些组件:
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
function App() {
const handleDrop = (id) => {
console.log(`Dropped item with id: ${id}`);
};
return (
<DndProvider backend={HTML5Backend}>
<div>
<DraggableItem id={1} text="Drag me" />
<DropZone onDrop={handleDrop} />
</div>
</DndProvider>
);
}
使用 react-beautiful-dnd 实现列表拖拽
react-beautiful-dnd 专注于列表的拖拽排序。安装库:
npm install react-beautiful-dnd
实现一个可排序的列表:
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
function SortableList({ items, onReorder }) {
const handleDragEnd = (result) => {
if (!result.destination) return;
onReorder(result.source.index, result.destination.index);
};
return (
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="list">
{(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: '8px',
margin: '4px',
backgroundColor: 'white',
border: '1px solid lightgray',
}}
>
{item.text}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}
使用原生 HTML5 拖拽 API
对于简单的需求,可以直接使用 HTML5 的拖拽 API:
function NativeDraggable() {
const handleDragStart = (e) => {
e.dataTransfer.setData('text/plain', e.target.id);
};
const handleDragOver = (e) => {
e.preventDefault();
};
const handleDrop = (e) => {
e.preventDefault();
const id = e.dataTransfer.getData('text/plain');
const draggedElement = document.getElementById(id);
e.target.appendChild(draggedElement);
};
return (
<div>
<div
id="draggable"
draggable
onDragStart={handleDragStart}
style={{
padding: '10px',
backgroundColor: 'lightgray',
margin: '10px',
display: 'inline-block',
}}
>
Drag me
</div>
<div
onDragOver={handleDragOver}
onDrop={handleDrop}
style={{
width: '200px',
height: '200px',
border: '1px dashed black',
padding: '10px',
}}
>
Drop here
</div>
</div>
);
}
性能优化建议
对于大型列表,使用 react-window 或 react-virtualized 来虚拟化渲染:
import { FixedSizeList } from 'react-window';
import { Droppable, Draggable } from 'react-beautiful-dnd';
function VirtualizedList({ items }) {
const Row = ({ index, style }) => (
<Draggable draggableId={items[index].id} index={index}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{
...provided.draggableProps.style,
...style,
}}
>
{items[index].text}
</div>
)}
</Draggable>
);
return (
<DragDropContext onDragEnd={handleDragEnd}>
<Droppable droppableId="list">
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef}>
<FixedSizeList
height={500}
itemCount={items.length}
itemSize={50}
width={300}
>
{Row}
</FixedSizeList>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}






