zoukankan      html  css  js  c++  java
  • react-dnd使用介绍

    核心API

    想要灵活使用,就先知道几个核心API

    • DragSource 用于包装你需要拖动的组件,使组件能够被拖拽(make it draggable)
    • DropTarget 用于包装接收拖拽元素的组件,使组件能够放置(dropped on it)
    • DragDropContex 用于包装拖拽根组件,DragSource 和 DropTarget 都需要包裹在DragDropContex内
    • DragDropContextProvider 与 DragDropContex 类似,用 DragDropContextProvider 元素包裹拖拽根组件。

    大致理解这几个API的概念后,垃圾(Box.jsx)扔进垃圾桶(Dustbin.jsx)的代码将会是:

    // 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>
        );
      }
    }
    

    API参数介绍

    上面的代码

    @DragSource(type, spec, collect)
    @DropTarget(types, spec, collect)
    

    可以看到 DragSource, DropTarget 分别有三个参数:

    • type: 拖拽类型,必填
    • spec: 拖拽事件的方法对象,必填。
    • collect: 把拖拽过程中需要信息注入组件的 props,接收两个参数 connect and monitor,必填。

    下面约定 source组件为DragSource包装的组件(本示例为Box.jsx),target组件为DropTarget包装的组件(本示例为Dustbin.jsx)。

    type

    当 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

    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)
    
    • props: 组件当前的props
    • monitor:查询当前的拖拽状态,比如当前拖拽的item和它的type,当前拖拽的offsets,当前是否dropped。具体获取方法,参看collect 参数 monitor 部分
    • source组件 的 monitor 参数是 DragSourceMonitor 的实例
    • target组件 的 monitor 参数是 DropTargetMonitor 的实例
    • component:当前组件实例

    collect

    collect 是一个函数,默认有两个参数:connect 和 monitor。collect函数将返回一个对象,这个对象会注入到组件的 props 中,也就是说,我们可以通过 this.props 获取collect返回的所有属性。

    connect

    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

    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()
    

    实例

    1、定义被拖拽组件DragableBody.js

    import React, { Component } from 'react';
    import { DragSource, DropTarget } from 'react-dnd';
    
    const sourceSpec = {
        beginDrag(props) {
            return {
                id: props.id,
                index: props.index
            }
        },
    }
    
    const targetSpec = {
        // 组件下放时响应的事件
        drop(props, monitor) {
            const dragIndex = monitor.getItem().index;
            const hoverIndex = props.index;
        
            if (dragIndex === hoverIndex) {
              return;
            }
    
            props.moveFN(dragIndex, hoverIndex);
        
            monitor.getItem().index = hoverIndex;
        },
    
        // hover(props, monitor, component){}   // 组件在DropTarget上方时响应的事件   
    }
    
    
    
    class BodyRow extends Component {
        render() {
            const {
                connectDragSource,
                connectDropTarget,
                id,
            } = this.props;
            const style = {cursor: 'move' };
            // 实际展示出来的东西
            return connectDragSource(
                connectDropTarget(
                  <p style={style}>{id}</p>
                )
            );
        }
    }
    
    // DragSource 用于包装你需要拖动的组件,使组件能够被拖拽(make it draggable)
    // DropTarget 用于包装接收拖拽元素的组件,使组件能够放置(dropped on it)
    // 当 source组件的type 和 target组件的type 一致时,target组件可以接受source组件。
    
    const DragableBody = DropTarget(
        'box',      // 拖拽类型
        targetSpec,     // 拖拽事件的方法对象
        (connect, monitor) => ({
          connectDropTarget: connect.dropTarget(),
          isOver: monitor.isOver(),
        }), // 把拖拽过程中需要信息注入组件的 props,接收两个参数 connect and monitor,必填。
      )(
        DragSource(
          'box',
          sourceSpec,
          (connect) => ({
            connectDragSource: connect.dragSource(),
          }),
        )(PBodyRow),
      );
    
    export default DragableBody;
    

    2、使用拖拽的相关逻辑组建

    import React, { Component } from 'react';
    import { DragDropContextProvider,DragDropContext } from 'react-dnd';
    import HTML5Backend from 'react-dnd-html5-backend';
    import update from 'immutability-helper';
    import DragableBody from './DragableBody';
    
    class Dnd extends Component {
        state = {
          cardList: ['red', 'green', 'yellow', 'blue']
        }
    
        moveFN =(dragIndex, hoverIndex)=> {
          const { cardList } = this.state;
          const dragRow = cardList[dragIndex];
          this.setState(
            update(this.state, {
              cardList: {
                $splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]],
              },
            }),
          );
        }
    
        render() {
            let { cardList } = this.state;
            return (
              // <DragDropContextProvider backend={HTML5Backend}>   // DragDropContextProvider易用性不高;推荐DragDropContext。
              <div className="App">     
                {cardList.map((item, index) => 
                  <PBodyRow
                    id={item}
                    index={index}
                    moveFN={this.moveFN}
                    key={item} 
                  />
                )}
              </div>
              // </DragDropContextProvider>
            );
        }
    }
    
    export default DragDropContext(HTML5Backend)(Dnd);     // 这样页面中可以同时使用多个
    
  • 相关阅读:
    ServletConfig对象
    乱码问题
    response request
    mysql
    数据库三范式 简单理解
    会话 cookie
    ServletContext对象
    读取工程中的配置文件
    Servlet与缓存
    C#捕获异常崩溃时
  • 原文地址:https://www.cnblogs.com/adoctors/p/10795897.html
Copyright © 2011-2022 走看看