React-DnD 的使用

介紹

React DnD 是一組 React 高階組件,能夠用來幫你構建複雜的拖拽接口,同時解耦你的組件。React DnD 很是適合像 Trello 和 Storify 這樣的應用,在不一樣地方經過拖拽轉移數據,而組件會改變它們的外觀和應用的狀態來響應拖拽事件。html

基本用法

  1. 把應用的根組件包裝在 DragDropContexthtml5

  2. 把能夠拖拽的組件包裝在 DragSourcereact

    1. 設置 typegit

    2. 設置 spec,讓組件能夠響應拖拽事件github

    3. 設置 collect,把拖拽過程當中須要信息注入組件的 props瀏覽器

  3. 把能夠接受拖拽的組件包裝在 DropTargetapp

    1. 設置 type函數

    2. 設置 spec,讓組件能夠響應拖拽事件性能

    3. 設置 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 表示拖/放組件的兼容性,DragSourceDropTarget 必須指定 type。只有在 type 相同的狀況下,DragSource 才能放到 DropTarget 中。

  • Monitors 用來響應拖拽事件,能夠用來更新組件的的狀態。

  • Connectors 底層接觸 DOM 的東西,用來封裝你的組件,讓你的組件有拖拽的特性。通常在 collect 方法中指定,而後注入到組件的 props 中,最後 render 方法中包裝你本身的組件。

  • DragSource && DropTarget 把上面的概念都綁在一塊兒的東西,也是真正跟你的組件打交道的東西。

主要 API 介紹

這些主要 API 都是經過包裝你的組件,而後返回一個新的組件。

DragDropContext(backend)

  • backend 實現 DnD 的方式,通常是 HTML5Backend

export default DragDropContext(HTML5Backend)(App);

DragSource(type, spec, collect)

DropTarget(type, spec, collect)

  • 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);

DragSource#spec

讓你的組件響應 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
        }
    }
    //...
}

DropTarget#spec

讓你的組件響應 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
        })
        
    }
}

DragSource#collect(connect, monitor)

DropTarget#collect(connect, monitor)

返回一個 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>
        )
    }
}

具體例子

出處

參考資料

相關文章
相關標籤/搜索