以前写过一篇 react-dnd 用法的文章,里面写的可能比较啰嗦了,可是内容比较详细,不少 API 都罗列了出来。目前 React Hooks 出来了,react-dnd 也作了对应的更新,因此本篇使用 React Hooks + TypeSscript 对 react-dnd 用法从新梳理一下。css
react
: 16.9.0
react-dom
: 16.9.0
typescript
: 3.5.3
react-dnd
: 9.3.4
react-dnd-html5-backend
: 9.3.4
脚手架使用的 create-react-app
,全局安装 create-react-app
的命令:npm i create-react-app -g
html
npx create-react-app react-dnd-hooks --typescript
react-dnd
:yarn add react-dnd
react-dnd-html5-backend
:yarn add react-dnd-html5-backend
为了方便统一个标识,'拖拽组件' 使用 'drag 组件' 代替,'目标接收组件' 使用 'drop 组件' 代替html5
想要使用 react-dnd
进行拖拽操做,须要用 DndProvider
标签将根节点包裹起来,并传入一个 backend
参数: index.tsx
文件react
import React from 'react';
import ReactDOM from 'react-dom';
import { DndProvider } from 'react-dnd';
import HTMLBackend from 'react-dnd-html5-backend'
import './index.css';
import App from './App';
ReactDOM.render(
<DndProvider backend={ HTMLBackend }>
<App />
</DndProvider>,
document.getElementById('root'));
复制代码
好比如今有一个 Box 组件,咱们想将其进行拖拽,此时咱们先声明一下这个组件git
Box.tsx
github
import React, { CSSProperties } from 'react';
const style: CSSProperties = {
width: 200,
height: 50,
lineHeight: '50px',
background: 'pink',
margin: '30px auto'
}
const Box = () => {
return (
<div style={ style }>可拖拽组件 Box</div>
)
}
export default Box;
复制代码
这个时候咱们使用鼠标按住 Box 组件,发现尚未办法拖拽 Box 组件typescript
使用 react-dnd
提供的 useDrag
, 返回的第一个值是 collect 方法返回的对象(这里没有使用,因此省略了),返回的第二个值是一个 ref,将其赋值给想要拖拽的元素便可实现组件拖动。 Box.tsx
npm
...
import { useDrag } from 'react-dnd';
...
const Box = () => {
// 使用 useDrag
const [, drager] = useDrag({
item: { type: 'Box' }
})
return (
// 将第二个参数赋值给 ref
<div ref={ drager } style={ style }>可拖拽组件 Box</div>
)
}
export default Box;
复制代码
这个时候咱们就可使用鼠标来回拖拽 Box
组件了,可是只能拖拽,尚未地方可以接收感应到 Box
组件,下面咱们来看看怎么操做。app
使用 react-dnd
提供的 useDrop
,返回的第一个值是 collect 方法返回的对象,返回的第二个值是一个 ref,将其赋值给想要接收的 drop
组件便可感应到 drag 组件。dom
Dustbin
组件:
import React, { CSSProperties } from 'react';
import { useDrop, DropTargetMonitor } from 'react-dnd';
const style: CSSProperties = {
width: 400,
height: 400,
margin: '100px auto',
lineHeight: '60px',
border: '1px dashed black'
}
const Dustbin = () => {
// 第一个参数是 collect 方法返回的对象,第二个参数是一个 ref 值,赋值给 drop 元素
const [collectProps, droper] = useDrop({
// accept 是一个标识,须要和对应的 drag 元素中 item 的 type 值一致,不然不能感应
accept: 'Box',
// collect 函数,返回的对象会成为 useDrop 的第一个参数,能够在组件中直接进行使用
collect: (minoter: DropTargetMonitor) => ({
isOver: minoter.isOver()
})
})
const bg = collectProps.isOver ? 'deeppink' : 'white';
const content = collectProps.isOver ? '快松开,放到碗里来' : '将 Box 组件拖动到这里'
return (
// 将 droper 赋值给对应元素的 ref
<div ref={ droper } style={{ ...style, background: bg }}>{ content }</div>
)
}
export default Dustbin;
复制代码
舒适提示:记得将 Box 和 Dustbin 组件引用到 App.tsx 组件里使用。
drag
组件经常使用的属性:
item
:是一个对象,必需要有一个 type
属性
begin(mintor: DragSourceMonitor)
:组件开始拖拽,必须返回一个对象包含 type
属性,会覆盖 item
属性返回的对象,会被传入 drop 组件 hover 和 drop 方法的第一个参数
end(item, mintor: DragSourceMonitor)
: 组件中止拖拽时触发,item
是 drop
组件在 drop
方法执行时返回的对象,等同于 mintor.getDropResult()
的值
drop
组件经常使用的属性
accept
:字符串,必须和对应 drag
组件的 item
属性中的 type
值一致
hover(item, minoter: DropTargetMonitor)
:drag
组件在 drop
组件上方 hove
时触发
drop(item, minoter: DropTargetMonitor)
:drag
组件拖拽结束后,放到 drop
组件时触发,返回的值会做为参数传递给 drag
组件 end
方法的第一个参数
让组件既能够被拖拽也能够接收拖拽元素
import React, { useRef } from 'react';
import { useDrag, useDrop } from 'react-dnd'
const Card = () => {
const ref = useRef<HTMLDivElement>(null);
const [, drop] = useDrop({
accept: 'Card',
});
const [, drag] = useDrag({
item: { type: 'Card' }
});
// 使用 drag 和 drop 包装 ref
drag(drop(ref));
// 将变量 ref 传给元素的 ref 便可
return (<div ref={ ref }>既能够被拖动也能够接收拖动组件</div>)
}
复制代码
drag
组件想传递一些数据出去
const [, drag] = useDrag({
item: { type: 'Card', id: 1, name: 'card1', kind: 'Card }
});
复制代码
注意:begin 方法的返回值会将 item 属性覆盖,因此必定要传 type 属性
const [, drag] = useDrag({
item: { type: 'Card' },
begin(mintor: DragSourceMonitor) {
return { type: 'Card', id: 1, name: 'card1', kind: 'Card }
}
});
复制代码
dropTarget
接收组件中就能够在 hover 或者 drop 方法的第一个参数中获取到,或者使用 DropTargetMonitor
的 getItem()
函数获取。想要获取到 drag
组件或者 drop
组件的一些状态信息
drag
组件:// collect 函数返回的对象会赋给 useDrop 的第一个参数 collectProps,能够在组件中直接进行使用
const [collectProps, drag] = useDrag({
item: { type: 'Card', id: 1, name: 'card1', kind: 'Card },
collect: (minoter: DropTargetMonitor) => ({
isOver: minoter.isOver(),
})
});
复制代码
drop
组件:// collect 函数返回的对象会赋给 useDrop 的第一个参数 collectProps,能够在组件中直接进行使用
const [collectProps, droper] = useDrop({
accept: 'Box',
collect: (minoter: DropTargetMonitor) => ({
isOver: minoter.isOver(),
})
})
复制代码
一个能够进行拖拽放置并进行拖拽排序的例子,有兴趣的小伙伴能够看看。
欢迎 Star! 欢迎 Fork!