拖拽react组件实现
实现拖拽React组件的核心方法
使用React DnD库 React DnD是一个流行的拖放库,专为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 }}>
{text}
</div>
);
};
const DropZone = ({ onDrop }) => {
const [{ canDrop }, drop] = useDrop(() => ({
accept: 'ITEM',
drop: (item) => onDrop(item.id),
collect: (monitor) => ({
canDrop: !!monitor.canDrop(),
}),
}));
return (
<div ref={drop} style={{ background: canDrop ? 'lightgreen' : 'white' }}>
Drop here
</div>
);
};
const App = () => (
<DndProvider backend={HTML5Backend}>
<DraggableItem id={1} text="Drag me" />
<DropZone onDrop={(id) => console.log(`Dropped item ${id}`)} />
</DndProvider>
);
使用react-beautiful-dnd库 适用于列表重排序场景。安装:
npm install react-beautiful-dnd
列表拖拽示例:
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
const items = [{id: '1', content: 'Item 1'}, {id: '2', content: 'Item 2'}];
function 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}
>
{item.content}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}
原生HTML5拖拽API实现 不需要额外依赖的基础方案:
function Draggable() {
const dragStart = (e) => {
e.dataTransfer.setData('text/plain', e.target.id);
e.target.style.opacity = '0.4';
};
const dragEnd = (e) => {
e.target.style.opacity = '1';
};
return (
<div
id="draggable-item"
draggable="true"
onDragStart={dragStart}
onDragEnd={dragEnd}
>
Drag me
</div>
);
}
function DropZone() {
const allowDrop = (e) => e.preventDefault();
const drop = (e) => {
e.preventDefault();
const data = e.dataTransfer.getData('text');
e.target.appendChild(document.getElementById(data));
};
return (
<div onDrop={drop} onDragOver={allowDrop}>
Drop here
</div>
);
}
关键注意事项
性能优化 对于大量可拖拽项目,使用shouldComponentUpdate或React.memo避免不必要的渲染。react-beautiful-dnd内置了虚拟列表支持。
触摸设备支持
HTML5 API在移动端支持有限,React DnD需要通过touch-backend替代默认后端:
import { TouchBackend } from 'react-dnd-touch-backend';
<DndProvider backend={TouchBackend} options={{ enableMouseEvents: true }}>
状态管理 拖拽操作通常需要与全局状态同步,建议结合Redux或Context API管理拖拽状态。
视觉反馈 通过useDrag/useDrop的collect函数或react-beautiful-dnd的provided props实现拖拽过程中的样式变化,增强用户体验。
无障碍支持 添加ARIA属性确保屏幕阅读器可访问:
<div
role="button"
aria-grabbed={isDragging}
tabIndex={0}
>






