react-dnd
一款强大的 React 拖放库,支持多种拖放类型,提供了许多可复用的组件和钩子,可以方便地实现基本的拖放效果。
npm install --save react-dnd
npm install --save react-dnd-html5-backend
import React from 'react'
import App from './App'
import { DndProvider } from 'react-dnd'
import { HTML5Backend } from 'react-dnd-html5-backend'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<DndProvider backend={HTML5Backend}>
<App />
</DndProvider>
)
import React from 'react';
import { HTML5Backend } from 'react-dnd-html5-backend'
import { useDrag,useDrop,DndProvider } from 'react-dnd'
interface DragComponentProps {
}
const DragComponent: React.FC<DragComponentProps> = () => {
const matchDrag = useDrag({
type: "FILE"
});
const matchDrop = useDrop({
accept: "FILE",
drop: function (item, monitor) {
console.log("dropped");
}
});
return (
<div >
<DndProvider backend={HTML5Backend}>
<div ref={matchDrag[1]}>Drag</div>
</DndProvider>
<DndProvider backend={HTML5Backend}>
<div ref={matchDrop[1]}>Drop</div>
</DndProvider>
</div>
)
}
export default DragComponent
上面的例子如果有多个起始节点,有问题;下面的可以有多个起始节点
import React from 'react';
import { HTML5Backend } from 'react-dnd-html5-backend'
import { useDrag,useDrop,DndProvider } from 'react-dnd'
const style = {
border: '1px dashed gray',
backgroundColor: 'white',
padding: '0.5rem 1rem',
marginRight: '1.5rem',
marginBottom: '1.5rem',
cursor: 'move',
float: 'left',
};
const Box = (props) => {
const { name } = props;
const [{ isDragging }, drag] = useDrag(() => ({
type: 'box',
item: () => ({ name }),
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
end: (item, monitor) => {
// 拖拽元素放下时,drop 结果
const dropResult = monitor.getDropResult();
// 如果 drop 结果存在,就弹出 alert 提示
if (dropResult) {
alert(`You dropped ${item.name} into ${dropResult.name}!`);
}
},
}));
const opacity = isDragging ? 0.4 : 1;
// 使用 connectDragSource 包裹住 DOM 节点,使其可以接受各种拖动 API
// connectDragSource 包裹住的 DOM 节点才可以被拖动
return (
<div style={{ ...style, opacity }} ref={drag}>
{name}
</div>
);
};
const style2 = {
height: '12rem',
width: '12rem',
marginRight: '1.5rem',
marginBottom: '1.5rem',
color: 'white',
padding: '1rem',
textAlign: 'center',
fontSize: '1rem',
lineHeight: 'normal',
float: 'left',
};
const Dustbin = () => {
const [{ canDrop, isOver }, drop] = useDrop(() => ({
accept: 'box',
collect: (monitor) => ({
canDrop: monitor.canDrop(),
isOver: monitor.isOver(),
}),
drop: () => ({ name: 'Dustbin' }),
}));
const isActive = canDrop && isOver;
let backgroundColor = '#222';
// 拖拽组件此时正处于 drag target 区域时,当前组件背景色变为 darkgreen
if (isActive) {
backgroundColor = 'darkgreen';
}
// 当前组件可以放置 drag source 时,背景色变为 pink
else if (canDrop) {
backgroundColor = 'darkkhaki';
}
// 使用 connectDropTarget 包裹住 DOM 节点,使其可以接收对应的 drag source 组件
// connectDropTarget 包裹住的 DOM 节点才能接收 drag source 组件
return (
<div ref={drop} style={{ ...style2, backgroundColor }}>
{isActive ? 'Release to drop' : 'Drag a box here'}
</div>
);
};
interface DragComponentProps {
}
const DragComponent: React.FC<DragComponentProps> = () => {
return (
<div >
<DndProvider backend={HTML5Backend}>
<Box name="Glass" />
<Box name="Banana" />
<Box name="Paper" />
<Dustbin></Dustbin>
</DndProvider>
</div>
)
}
export default DragComponent
https://react-dnd.github.io/react-dnd/about
https://stackblitz.com/edit/react-ts-f5nxsy?file=index.tsx,components%2FBoard.tsx
https://juejin.cn/post/6844903801120358407