文章首發個人我的blog : 原文連接html
學習 React DnD 的最初緣由是閱讀《如何寫一個拖拽日曆組件》附的源碼時,看不懂拖拽組件 React DnD 的相關代碼,因而行動力極強地學習了React DnD這個組件。html5
本文會經過 在根組件(Contaier.jsx)展現將垃圾(Box.jsx)扔進垃圾桶(Dustbin.jsx)的例子,解釋如何使用React DnD最基本的拖拽用法。react
預覽 垃圾桶效果git
查看 垃圾桶源碼github
想要靈活使用,就先知道幾個核心APIapp
DragSource
和 DropTarget
都須要包裹在DragDropContex
內DragDropContex
相似,用 DragDropContextProvider
元素包裹拖拽根組件。大體理解這幾個API的概念後,垃圾(Box.jsx)扔進垃圾桶(Dustbin.jsx)的代碼將會是:ide
// Box.jsx
import { DragSource } from 'react-dnd';
@DragSource(type, spec, collect)
export default class Box {
/* ... */
}
// Dustbin.jsx
import { DropTarget } from 'react-dnd';
@DropTarget(types, spec, collect)
export default class Contaier {
/* ... */
}
// Contaier.jsx (DragDropContex)
import { DragDropContext } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import Box from './Box';
import Dustbin from './Dustbin';
@DragDropContext(HTML5Backend)
export default class Contaier extends Component {
render() {
return (
<div> <Dustbin/> <Box/> </div>
);
}
}
// 也能夠寫成 Contaier.jsx (DragDropContextProvider)
import { DragDropContextProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import Box from './Box';
import Dustbin from './Dustbin';
export default class DustbinContaier extends Component {
render() {
return (
<DragDropContextProvider backend = { HTML5Backend }> <div> <Dustbin/> <Box/> </div> </DragDropContextProvider>
);
}
}
複製代碼
上面的代碼函數
@DragSource(type, spec, collect)
@DropTarget(types, spec, collect)
複製代碼
能夠看到 DragSource
, DropTarget
分別有三個參數:post
connect
and monitor
,必填。下面約定 source組件 爲DragSource包裝的組件(本示例爲Box.jsx),target組件 爲DropTarget包裝的組件(本示例爲Dustbin.jsx)。學習
當 source組件
的type 和 target組件
的type 一致時,target組件
能夠接受source組件
。
type的類型能夠是 string,symbol,也能夠是用一個函數來返回該組件的其餘 props。
翻譯爲代碼:
// ItemTypes.js 定義類型
export default {
BOX: 'box',
}
// Box.jsx
import ItemTypes from './ItemTypes'
@DragSource(ItemTypes.BOX, spec, collect)
// Dustbin.jsx
import ItemTypes from './ItemTypes'
@DropTarget(ItemTypes.BOX, spec, collect)
複製代碼
spec定義特定方法的對象,如 source組件
的spec 能夠定義 拖動 相關的事件,target組件
的spec 能夠定義 放置 相關的事件,具體列表:
beginDrag(props, monitor, component)
: 拖動開始時觸發的事件,必須。返回跟props相關的對象。
endDrag(props, monitor, component)
: 拖動結束時觸發的事件,可選。
canDrag(props, monitor)
: 當前是否能夠拖拽的事件,可選。
isDragging(props, monitor)
: 拖拽時觸發的事件,可選。
翻譯爲代碼:
// Box.jsx
const sourceSpec = {
beginDrag(props, monitor, component){
// 返回須要注入的屬性
return {
id: props.id
}
},
endDrag(props, monitor, component){
// ..
},
canDrag(props, monitor){
// ..
},
isDragging(props, monitor){
// ..
}
}
@DragSource(ItemTypes.BOX, sourceSpec, collect)
複製代碼
drop(props, monitor, component)
組件放下時觸發的事件,可選。hover(props, monitor, component)
組件在DropTarget上方時響應的事件,可選。canDrop(props, monitor)
組件能夠被放置時觸發的事件,可選。翻譯爲代碼:
// Dustbin.jsx
const targetSpec = {
drop(props, monitor, component){
// ..
},
hover(props, monitor, component){
// ..
},
canDrop(props, monitor){
// ..
}
}
@DropTarget(ItemTypes.BOX, targetSpec, collect)
複製代碼
source組件
的 monitor 參數是 DragSourceMonitor 的實例target組件
的 monitor 參數是 DropTargetMonitor 的實例collect 是一個函數,默認有兩個參數:connect
和 monitor
。collect函數將返回一個對象,這個對象會注入到組件的 props 中,也就是說,咱們能夠經過 this.props
獲取collect返回的全部屬性。
source組件
collect 中 connect是 DragSourceConnector的實例,它內置了兩個方法:dragSource()
和 dragPreview()
。dragSource()
返回一個方法,將source組件
傳入這個方法,能夠將 source DOM 和 React DnD backend 鏈接起來;dragPreview()
返回一個方法,你能夠傳入節點,做爲拖拽預覽時的角色。target組件
collect 中 connect是 DropTargetConnector的實例,內置的方法 dropTarget()
對應 dragSource()
,返回能夠將 drop target 和 React DnD backend 鏈接起來的方法。翻譯爲代碼:
// Box.jsx
@DragSource(ItemTypes.BOX, sourceSpec,(connect)=>({
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
}))
export default class Box {
render() {
const { connectDragSource } = this.props
return connectDragSource(
<div> { /* ... */ } </div>,
)
}
}
// Dustbin.jsx
@DropTarget(ItemTypes.BOX, targetSpec, (connect)=>{
connectDropTarget: connect.dropTarget(),
})
export default class Dustbin {
render() {
const { connectDropTarget } = this.props
return connectDropTarget(
<div> { /* ... */ } </div>,
)
}
}
複製代碼
monitor 用於查詢當前的拖拽狀態,其對應實例內置了不少方法。
source組件
collect 中 monitor是 DragSourceMonitor的實例。target組件
collect 中 monitor是 DropTargetMonitor的實例。內置方法列表:
// DragSourceMonitor
monitor.canDrag() // 是否能被拖拽
monitor.isDragging() // 是否正在拖拽
monitor.getItemType() // 拖拽組件type
monitor.getItem() // 當前拖拽的item
monitor.getDropResult() // 查詢drop結果
monitor.didDrop() // source是否已經drop在target
monitor.getInitialClientOffset() // 拖拽組件初始拖拽時offset
monitor.getInitialSourceClientOffset()
monitor.getClientOffset() // 拖拽組件當前offset
monitor.getDifferenceFromInitialOffset() // 當前拖拽offset和初始拖拽offset的差異
monitor.getSourceClientOffset()
// DropTargetMonitor
monitor.canDrop() // 是否可被放置
monitor.isOver(options) // source是否在target上方
monitor.getItemType() // 拖拽組件type
monitor.getItem() // 當前拖拽的item
monitor.getDropResult() // 查詢drop結果
monitor.didDrop() // source是否已經drop在target
monitor.getInitialClientOffset() // 拖拽組件初始拖拽時offset
monitor.getInitialSourceClientOffset()
monitor.getClientOffset() // 拖拽組件當前offset
monitor.getDifferenceFromInitialOffset() // 當前拖拽offset和初始拖拽offset的差異
monitor.getSourceClientOffset()
複製代碼
先草草丟下官方例子和源碼: