React DnD 是一組 React 高階組件,能夠用來幫你構建複雜的拖拽接口,同時解耦你的組件。React DnD 很是適合像 Trello 和 Storify 這樣的應用,在不一樣地方經過拖拽轉移數據,而組件會改變它們的外觀和應用的狀態來響應拖拽事件。html
把應用的根組件包裝在 DragDropContext
中html5
把能夠拖拽的組件包裝在 DragSource
中react
設置 typegit
設置 spec,讓組件能夠響應拖拽事件github
設置 collect,把拖拽過程當中須要信息注入組件的 props瀏覽器
把能夠接受拖拽的組件包裝在 DropTarget
中app
設置 type函數
設置 spec,讓組件能夠響應拖拽事件性能
設置 collect,把拖拽過程當中須要信息注入組件的 propsthis
完
翻譯成代碼就是:
// 1 import HTML5Backend from 'react-dnd-html5-backend'; import { DragDropContext } from 'react-dnd'; class App { ... } export default DragDropContext(HTML5Backend)(App); /*---------------------------*/ // 2 import { DragSource } from 'react-dnd'; class MyComponent { ... } export default DragSource(type, spec, collect)(MyComponent); /*---------------------------*/ // 3 import { DropTarget } from 'react-dnd'; class MyComponent2 { ... } export default DropTarget(types, spec, collect)(MyComponent2);
這樣,MyComponent 就變得能夠拖拽,而 MyComponent2 就變得能夠接受拖拽了,但這並不表明 MyComponent 能夠放到 MyComponent2 中!
React DnD 中有一些特殊的概念,理解這些概念以後才能活用這個庫!
Backend
實現 DnD 的方式,默認是用 HTML5 DnD API,它不能在觸屏環境下工做,並且在 IE 下可定製性比其餘瀏覽器弱。你也能夠用本身實現,具體請看官方文檔。
Items
拖拽數據的表現形式,用 Object 來表示。譬如,要拖拽一張卡片,那這張卡片的數據的表現形式多是 { id: xxx, content: yyy }
。
Types
表示拖/放組件的兼容性,DragSource
和 DropTarget
必須指定 type
。只有在 type
相同的狀況下,DragSource
才能放到 DropTarget
中。
Monitors
用來響應拖拽事件,能夠用來更新組件的的狀態。
Connectors
底層接觸 DOM 的東西,用來封裝你的組件,讓你的組件有拖拽的特性。通常在 collect 方法中指定,而後注入到組件的 props 中,最後 render 方法中包裝你本身的組件。
DragSource && DropTarget
把上面的概念都綁在一塊兒的東西,也是真正跟你的組件打交道的東西。
這些主要 API 都是經過包裝你的組件,而後返回一個新的組件。
backend
實現 DnD 的方式,通常是 HTML5Backend
export default DragDropContext(HTML5Backend)(App);
type
必須。type 是自定義的,能夠是 string,symbol,也能夠是用一個函數來返回該組件的其餘 props。該組件只能放到相同 type 的 DropTarget 中。
spec
必須。一個帶有特定方法的純 Object,裏面是一些響應拖拽事件的方法。
collect
必須。一個函數返回一個 Object,這個 Object 會注入到組件的 props 中。
options
可選。除非有性能問題,不然不須要關心這個參數。
const type = 'xxx'; const spec = { ... }; function collect(connect, monitor) { ... } export default DragSource(type, spec, collect)(MyComponent); export default DropTarget(type, spec, collect)(MyComponent2);
讓你的組件響應 dnd 相關事件,支持如下方法:
beginDrag(props, monitor, component)
必須
endDrag(props, monitor, component)
可選
canDrag(props, monitor)
可選
isDragging(props, monitor)
可選
參數含義以下:
props
組件當前的 props
monitor
是一個 DragSourceMonitor
實例,用來查詢當前 drag state 的信息。
component
表示當前組件,能夠省略。
const spec = { beginDrag(props) { return { id: props.id, content: props.content } } //... }
讓你的組件響應 dnd 相關事件,支持如下方法:
drop(props, monitor, component)
可選,響應 drop 事件
hover(props, monitor, component)
可選
canDrop(props, monitor)
可選
參數含義以下:
props
組件當前的 props
monitor
是一個 DropTargetMonitor
實例,用來查詢當前 drag state 的信息。
component
表示當前組件,能夠省略。
const spec = { drop(props, monitor, component) { // 獲取正在拖放的數據 const item = monitor.getItem(); // 更新組件狀態 component.setState({ item }) } }
返回一個 object,這個 object 能夠會注入到組件的 props 中。
connect
一個 DragSourceConnector
/DropTargetConnector
實例,能夠用 connect.dragSource()
/connect.dropTarget()
來封裝咱們的組件。
monitor
一個 DragSourceMonitor
/DropTargetMonitor
實例,用來查詢當前拖拽的信息。
function collect(connect, monitor) { return { isDragging: monitor.isDragging(), connectDragSource: connect.dragSource() } } class MyComponent extends Component { render() { // 能夠訪問 collect 中返回的 object const { isDragging, connectDragSource } = this.props; // 須要用 connect.dragSource()/connect.dropTarget() 封裝本身的組件 return connectDragSource( <div>123</div> ) } }