# react-dnd
开发实例:可拖拽Table|开发实例:可拖拽List(Card)
dnd
React DnD 是一组 React 高阶组件,使用的时候只需要使用对应的 API 将目标组件进行包裹,即可实现拖动或接受拖动元素的功能。将拖动的事件转换成对象中对应状态的形式,不需要开发者自己判断拖动状态,只需要在传入的 spec 对象中各个状态属性中做对应处理即可。
yarn add react-dnd react-dnd-html5-backend
1
# DragSource:使组件能够被拖拽
使用
DragSource包裹住组件,使其可以进行拖动。
import React, { Component } from 'react';
import { DragSource } from 'react-dnd';
const spec = {
beginDrag(props, monitor, component) {
// 这里 return 出去的对象属性自行选择,这里只是用 id 作为演示
return { id: props.id }
}
endDrag(props, monitor, component) {
...
}
canDrag(props, monitor) {
...
}
isDragging(props, monitor) {
...
}
}
const collect = (connect, monitor) => ({
// 这里返回一个对象,会将对象的属性都赋到组件的 props 中去。这些属性需要自己定义。
connectDropTarget: connect.dropTarget(),
id: monitor.getItem().id
})
@DragSource(type, spec, collect)
class MyComponent extends Component {
/* ... */
}
export default MyComponent;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
type: 必填。字符串,ES6符号或返回给定组件的函数props。只有为相同类型注册的 drop targets 才会对此拖动源生成的项目做出反应spec:必填。一个普通的JavaScript对象,上面有一些允许的方法。它描述了拖动源如何对拖放事件做出反应。collect:必填。收集功能。它应该返回一个普通的对象注入你的组件。它接收两个参数:connect和monitor。options:可选的。一个普通的对象。
# spec 对象中的方法
beginDrag(props, monitor, component):必填。当拖动开始时,beginDrag 被调用。您必须返回描述被拖动数据的纯 JavaScript 对象。您返回的内容会被放置到 monitor.getItem() 获取到的对象中。endDrag(props, monitor, component):可选的。当拖动停止时,endDrag 被调用。对于每个 beginDrag,endDrag 都会对应。canDrag(props, monitor): 可选的。用它来指定当前是否允许拖动。如果您想要始终允许它,只需省略此方法即可。注意:您可能无法调用monitor.canDrag() 此方法。isDragging(props, monitor): 可选的。默认情况下,仅启动拖动操作的拖动源被视为拖动。注意:您可能无法调用 monitor.isDragging() 此方法。
# 方法中的参数 props, monitor, component
props:当前组件的 propsmonitor:一个 DragSourceMonitor 实例。使用它来查询有关当前拖动状态的信息,例如当前拖动的项目及其类型,当前和初始坐标和偏移,以及它是否已被删除。component:指定时,它是组件的实例。使用它来访问底层DOM节点以进行位置或大小测量,或调用 setState 以及其他组件方法。isDragging、 canDrag 方法里获取不到 component 这个参数,因为它们被调用时实例可能不可用
# collect 中的 connect 和 monitor 参数
connect: 一个 DragSourceConnector 实例。它有两种方法:dragPreview()和dragSource()。dragSource() => (elementOrNode, options?):常用方法,返回一个函数,传递给组件用来将 source DOM 和 React DnD Backend 连接起来dragPreview():返回一个函数,传递给组件用来将拖动时预览的 DOM 节点 和 React DnD Backend 连接起来
monitor:一个 DragSourceMonitor 实例。包含下面各种方法:
| 方法 | 含义 |
|---|---|
canDrag() | 是否可以被拖拽。如果没有正在进行拖动操作,则返回 true |
isDragging() | 是否正在被拖动。如果正在进行拖动操作,则返回 true |
getItemType() | 返回标识当前拖动项的类型的字符串或ES6符号。 如果没有拖动项目,则返回 null |
getItem() | 返回表示当前拖动项的普通对象。 每个拖动源都必须通过从其beginDrag()方法返回一个对象来指定它。 如果没有拖动项目,则返回 null |
getDropResult() | 返回表示最后记录的放置 drop result 对象 |
didDrop() | 如果某个 drop target 处理了 drop 事件,则返回 true,否则返回 false。即使 target 没有返回 drop 结果,didDrop() 也会返回true。 在 endDrag() 中使用它来测试任何放置目标是否已处理掉落。 如果在 endDrag() 之外调用,则返回 false |
getInitialClientOffset() | 返回当前拖动操作开始时指针的{x,y} client 偏移量。 如果没有拖动项目,则返回 null |
getInitialSourceClientOffset() | 返回当前拖动操作开始时 drag source 组件的根DOM节点的{x,y}client 偏移量。 如果没有拖动项目,则返回 null |
getClientOffset() | 拖动操作正在进行时,返回指针的最后记录的{x,y}client 偏移量。 如果没有拖动项目,则返回 null |
getDifferenceFromInitialOffset() | 返回当前拖动操作开始时鼠标的最后记录 client 偏移量与 client 偏移量之间的{x,y}差异。 如果没有拖动项目,则返回 null |
getSourceClientOffset() | 返回 drag source 组件的根DOM节点的预计{x,y} client 偏移量,基于其在当前拖动操作开始时的位置以及移动差异。 如果没有拖动项目,则返回 null |
# DropTarget:使组件能够放置拖拽组件
import React, { Component } from 'react';
import { DropTarget } from 'react-dnd';
const spec = {
drop(props, monitor, component) {
// 这里 return 出去的对象属性自行选择,这里只是用 id 作为演示
return { id: props.id }
}
hover(props, monitor, component) {
...
}
canDrop(props, monitor) {
...
}
}
const collect = (connect, monitor) => ({
// 这里返回一个对象,会将对象的属性都赋到组件的 props 中去。这些属性需要自己定义。
connectDropTarget: connect.dropTarget()
})
@DropTarget(type, spec, collect)
class MyComponent extends Component {
/* ... */
}
export default MyComponent;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
type: 必填。字符串,ES6符号或返回给定组件的函数props。此放置目标仅对指定类型的 drag sources 项目做出反应- 当 source组件的type 和 target组件的type 一致时,target组件可以接受source组件。
spec:必填。一个普通的JavaScript对象,上面有一些允许的方法。它描述了放置目标如何对拖放事件做出反应。collect:必填。收集功能。它应该返回一个普通的道具对象注入你的组件。它接收两个参数:connect 和 monitor。options:可选的。一个普通的对象。
# DropTarget中spec 对象中的方法
drop(props, monitor, component): 可选的。在目标上放置兼容项目时调用。可以返回 undefined 或普通对象。如果返回一个对象,它将成为放置结果,可以使用 monitor.getDropResult() 获取到。hover(props, monitor, component): 可选的。当项目悬停在组件上时调用。您可以检查 monitor.isOver({ shallow: true }) 以测试悬停是仅发生在当前目标上还是嵌套上。canDrop(props, monitor): 可选的。使用它来指定放置目标是否能够接受该项目。如果想要始终允许它,只需省略此方法即可。
文档没有提供按目的处理进入或离开事件的方法。而是 monitor.isOver() 从收集函数返回调用结果,以便我们可以使用 componentDidUpdateReact 钩子函数来处理组件中的进入和离开事件。
# DropTarget方法中的参数 props, monitor, component
props:当前组件的 propsmonitor:一个 DropTargetMonitor 实例。使用它来查询有关当前拖动状态的信息,例如当前拖动的项目及其类型,当前和初始坐标和偏移,是否超过当前目标,以及是否可以删除它。component:指定时,它是组件的实例。使用它来访问底层DOM节点以进行位置或大小测量,或调用 setState 以及其他组件方法。canDrag 方法里获取不到 component 这个参数,因为它们被调用时实例可能不可用。
# DropTarget collect 中的 connect 和 monitor 参数
connect: 一个 DropTargetConnector 实例。它只有一种 dropTarget() 方法。dropTarget() => (elementOrNode):常用方法,返回一个函数,传递给组件用来将 target DOM 和 React DnD Backend 连接起来。通过{ connectDropTarget: connect.dropTarget() }从收集函数返回,可以将任何React元素标记为可放置节点。monitor:一个 DropTargetMonitor 实例。包含下面各种方法:
| 方法 | 含义 |
|---|---|
canDrop() | 是否可以被放置。如果正在进行拖动操作,则返回true |
isOver(options) | drag source 是否悬停在 drop target 区域。可以选择传递{ shallow: true }以严格检查是否只有 drag source 悬停,而不是嵌套目标 |
getItemType() | 返回标识当前拖动项的类型的字符串或ES6符号。如果没有拖动项目则返回 null |
getItem() | 返回表示当前拖动项的普通对象,每个拖动源都必须通过从其beginDrag()方法返回一个对象来指定它。如果没有拖动项目则返回 null |
getDropResult() | 返回表示最后记录的放置 drop result 对象 |
didDrop() | 如果某个 drop target 处理了 drop 事件,则返回 true,否则返回 false。即使 target 没有返回 drop 结果,didDrop() 也会返回true。 在 endDrag() 中使用它来测试任何放置目标是否已处理掉落。 如果在 endDrag() 之外调用,则返回 false |
getInitialClientOffset() | 返回当前拖动操作开始时指针的{x,y} client 偏移量。 如果没有拖动项目,则返回 null |
getInitialSourceClientOffset() | 返回当前拖动操作开始时 drag source 组件的根DOM节点的{x,y}client 偏移量。 如果没有拖动项目,则返回 null |
getClientOffset() | 拖动操作正在进行时,返回指针的最后记录的{x,y}client 偏移量。 如果没有拖动项目,则返回 null |
getDifferenceFromInitialOffset() | 返回当前拖动操作开始时鼠标的最后记录 client 偏移量与 client 偏移量之间的{x,y}差异。 如果没有拖动项目,则返回 null |
getSourceClientOffset() | 返回 drag source 组件的根DOM节点的预计{x,y} client 偏移量,基于其在当前拖动操作开始时的位置以及移动差异。 如果没有拖动项目,则返回 null |
# DragDropContext & DragDropContextProvider
注意
使用 DragSource 和 DropTarget 包裹的组件,必须放在: DragDropContext 包裹的根组件内部,或者 DragDropContextProvider 根标签的内部。
# DragDropContext
使用 DragDropContext 包装应用程序的根组件以启用 React DnD。
import React, { Component } from 'react';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContext } from 'react-dnd';
@DragDropContext(HTML5Backend)
class YourApp extends Component {
/* ... */
}
export default YourApp;
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
backend:必填。一个 React DnD 后端。除非您正在编写自定义的,否则建议使用 React DnD 附带的 HTML5Backend。context:backend 依赖。用于自定义后端的上下文对象。例如,HTML5Backend可以为iframe场景注入自定义窗口对象。
# DragDropContextProvider
作为 DragDropContext 的替代方法,您可以使用 DragDropContextProvider 元素为应用程序启用React DnD。与 DragDropContext 类似,这可以通过 backendprop 注入后端,但也可以注入一个 window 对象。
import React, { Component } from 'react';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragDropContextProvider } from 'react-dnd';
export default class YourApp extends Component {
render() {
return (
<DragDropContextProvider backend={HTML5Backend}>
/* ... */
</DragDropContextProvider>
)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
backend:必填。一个 React DnD 后端。除非您正在编写自定义的,否则建议使用 React DnD 附带的 HTML5Backend。context:backend 依赖。用于自定义后端的上下文对象。例如,HTML5Backend可以为iframe场景注入自定义窗口对象。