博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React DnD
阅读量:4083 次
发布时间:2019-05-25

本文共 7157 字,大约阅读时间需要 23 分钟。

简介

最近在研究用 React 绘制拓扑图的时候涉及到了 HTML5 拖放 API,了解到了 React DnD 这个拖放神器。React DnD 帮我们封装了一系列的拖放 API,大大简化了拖放 API 的使用方式,今天就结合下面这个示例给大家介绍下 React DnD 的用法。

重要概念

React Dnd 提供了几个重要的 API 供我们使用:

  • DragSource
  • DropTarget
  • DragDropContext && DragDropContextProvider

DragSource

DragSource 是一个高阶组件,使用 DragSource 高阶组件包裹的组件可以进行拖拽操作。

基本用法:

import { DragSource } from 'react-dnd'class MyComponent {  /* ... */}export default DragSource(type, spec, collect)(MyComponent)

参数:

  • type:指定拖拽元素的类型,值的类型可以是 string、 symbol 或者 func ,只有具有相同type类型的元素才能被 drop target 所响应。
  • spec: 一个js对象,上面定义了一些方法,用来描述 drag source 如何对拖动事件进行响应。

    • beginDrag(props, monitor, component): 必填项。当拖拽开始的时候,这个方法就会被调用,这个方法必须要返回一个js 对象来描述被拖拽的元素,比如返回一个 { id: props.id },通过monitor.getItem() 方法可以获取到返回结果。
    • endDrag(props, monitor, component): 非必填项。当拖拽停止的时候,这个方法会被调用,通过 monitor.didDrop() 可以判断 drag source 是否已经被 drop target 处理完毕。如果在 drop target 的 drop 方法中返回了一个对象,在这里可以通过 monitor.getDropResult() 获取到返回结果。
    • canDrag(props, monitor): 可选参数。可以指定当前的拖拽操作是否被允许。
    • isDragging(props, monitor): 可选参数。拖拽时触发的事件,注意,在这个方法里面不能再调用 monitor.isDragging()
方法中的参数解释:- props:当前组件的 `props` 参数。- monitor:一个 `DragSourceMonitor` 实例。通过它可以获取当前的拖拽信息,比如可以获取当前被拖拽的项目及其类型,当前和初始坐标和偏移,以及它是否已被删除。- component:是组件的实例。使用它可以访问DOM元素来进行位置或大小测量,或调用组件里面定义的方法,或者进行 `setState` 操作。有时候在 isDragging、 canDrag 方法里可能获取不到 `component` 这个参数,因为它们被调用时实例可能不可用。
  • collect: 必填项,把拖拽过程中需要的信息注入组件的 props,接收两个参数 connect 和 monitor

    • connect: DragSourceConnector 的实例,包括 dragPreview() 和 dragSource() 两个方法,常用的是 dragSource() 这个方法。

      • dragSource: 返回一个函数,传递给组件用来将 source DOM 和 React DnD Backend 连接起来。
      • dragPreview: 返回一个函数,传递给组件用来将拖动时预览的 DOM 节点 和 React DnD Backend 连接起来。
    • monitor: DragSourceMonitor 的实例,包含的具体方法可以参考。

DropTarget

DropTarget 是一个高阶组件,被 DropTarget 包裹的组件能够放置拖拽组件,能够对 hover 或者 dropped 事件作出响应。

基本用法:

import { DropTarget } from 'react-dnd'class MyComponent {  /* ... */}export default DropTarget(types, spec, collect)(MyComponent)

参数:

  • types: 指定拖拽元素的类型,值的类型可以是 string、 symbol 或者 array ,drop target 只接受具有相同 type 类型的 drag source
  • spec: 一个js对象,上面定义了一些方法,描述了拖放目标对拖放事件的反应。

    • drop(props, monitor, component): 可选参数。当item被放置到目标元素上时会被调用。如果这个方法返回的是一个js对象,在 drag source 的 endDrag 方法里面,调用 monitor.getDropResult() 可以获得返回结果。
    • hover(props, monitor, component): 可选参数。当item经过 drop target 的时候被调用。可以通过 monitor.isOver({ shallow: true }) 方法来检查悬停是仅发生在当前目标上还是嵌套上。
    • canDrop(props, monitor): 可选参数。这个方法可以用来检测 drop target 是否接受 item。
方法中的参数解释:- props:当前组件的 `props` 参数。- monitor:一个 `DropTargetMonitor` 实例。通过它可以获取当前的拖拽信息,比如可以获取当前被拖拽的项目及其类型,当前和初始坐标和偏移,以及它是否已被删除。- component:是组件的实例。使用它可以访问DOM元素来进行位置或大小测量,或调用组件里面定义的方法,或者进行 `setState` 操作。有时候在 isDragging、 canDrag 方法里可能获取不到 `component` 这个参数,因为它们被调用时实例可能不可用。
  • collect: 必填项,把拖拽过程中需要的信息注入组件的 props,接收两个参数 connect 和 monitor

    • connect: DropTargetConnector 的实例,包括 dropTarget 一个方法。

      • dropTarget: 返回一个函数,传递给组件用来将 source DOM 和 React DnD Backend 连接起来。
    • monitor: DropTargetMonitor 的实例,包含的具体方法可以参考。

DragDropContext && DragDropContextProvider

使用 DragSource 和 DropTarget 包裹的组件必须放置在 DragDropContext 或者 DragDropContextProvider 组件内部。

基本用法:

import Backend from 'react-dnd-html5-backend'import { DndProvider } from 'react-dnd'export default function MyReactApp() {  return (    
/* your drag-and-drop application */
)}

参数

  • backend: 必填项。HTML5 DnD API 兼容性不怎么样,并且不适用于移动端,所以干脆把 DnD 相关具体DOM事件抽离出去,单独作为一层,即 Backend,我们可以根据 React DnD提供的约定协议定义自己的 Backend。

示例

了解了上述 API 的基本使用,现在我们就来实现下开头的demo。

本示例是基于 create-react-app 开发的,通过create-react-app的CLI工具创建我们的demo工程:

$ create-react-app react-dnd-demo

src/index.js

import React from 'react'import ReactDOM from 'react-dom'import Container from './Container'import { DndProvider } from 'react-dnd'import Backend from 'react-dnd-html5-backend'function App() {  return (    
)}const rootElement = document.getElementById('root')ReactDOM.render(
, rootElement)

src/Container.js

import React from 'react';import { DropTarget } from 'react-dnd';import DraggableBox from './DraggableBox';import Types from './types'const styles = {  width: '500px',  height: '300px',  position: 'relative',  border: '1px solid black',}@DropTarget(  Types.Box,  {    drop: (props, monitor, component) => {      if(!component) {        return;      }      const delta = monitor.getDifferenceFromInitialOffset();      const item = monitor.getItem();      const left = Math.round(delta.x + item.left);      const top = Math.round(delta.y + item.top);      component.moveBox(item.id, left, top);    },  },  (connect, monitor) => ({    connectDropTarget: connect.dropTarget(),    isOver: monitor.isOver(),    canDrop: monitor.canDrop(),  }))class Container extends React.Component {  state = {    boxes: {      a: { top: 20, left: 80, title: 'Drag me around' },      b: { top: 180, left: 20, title: 'Drag me too' },    },  }  moveBox = (id, left, top) => {    const { boxes }  = this.state;    this.setState({      boxes: {        ...boxes,        [id]: {          ...boxes[id],          left,          top        }      }    })  }  render() {    const { isOver, canDrop, connectDropTarget} = this.props;    const { boxes } = this.state;    const isActive = isOver && canDrop;    let backgroundColor = '#ccc';    // 拖拽组件此时正处于 drag target 区域时,当前组件背景色变为 darkgreen    if (isActive) {      backgroundColor = '#453467';    }    console.log('qqqq', this.state.boxes)    return connectDropTarget && connectDropTarget(      
{Object.keys(boxes).map(item =>
)}
) }}export default Container;

可以看到,在 drop 方法里,通过 monitor.getDifferenceFromInitialOffset() 方法计算出每次 drop 的时候,当前元素与拖拽前元素位置的偏移量,monitor.getItem() 方法可以获得当前 哪个元素被拖拽(必须要在 drag source 的 beginDrag 方法中返回),调用 component 上的 moveBox 方法重新设置拖拽之后的最新位置,从而实现元素的移动。

collect 的 connect 方法中通过 monitor.isOver() 和 monitor.canDrop() 方法将 isOver 和 canDrop 参数传递到组件的 props 中来判断当前组件是否处于拖拽状态中,这里可以用来设置拖拽时容器的背景色。

这里有个细节需要注意的是,Container 容器的 position 属性被设置为了 relative,这样被拖拽的元素就会相对于该容器进行定位。

src/DraggableBox.js

import React from 'react';import { DragSource } from 'react-dnd';import Box from './Box';import Types from './types'@DragSource(  Types.Box,  {    beginDrag: (props) => {      const { id, title, left, top } = props      return { id, title, left, top }    }  },  (connect, monitor)=> ({    connectDragSource: connect.dragSource(),    isDragging: monitor.isDragging(),  }))class DraggableBox extends React.Component {  getStyle = () => {    const { left, top } = this.props;    const transform = `translate(${left}px, ${top}px)`    return {      position: 'absolute',      transform,    }  }  render() {    const { connectDragSource } = this.props;    return connectDragSource(      
) }}export default DraggableBox;

beginDrag 方法必须返回一个对象,以前在 drop 方法中获取到当前被拖拽组件的信息。positon 属性必须被设置为 absolute,以方便相对容器进行定位。元素的移动是通过 css 的 transform 属性进行控制的。

src/Box.js

import React from 'react';const styles = {  border: '1px dashed gray',  backgroundColor: 'white',  padding: '0.5rem 1rem',  marginRight: '1.5rem',  marginBottom: '1.5rem',  cursor: 'move',  display: 'inline-block'}class Box extends React.Component {  render() {    const { title, left, right } = this.props;    return (      
{title}
) }}export default Box;

总结

关于 React DnD 的介绍,这里只是做了一个基本介绍,更多的示例大家可以参考官网,本示例的代码大家在可以找到。

转载地址:http://ntqni.baihongyu.com/

你可能感兴趣的文章
db db2_monitorTool IBM Rational Performace Tester
查看>>
OS + Unix Aix telnet
查看>>
IBM Lotus
查看>>
Linux +Win LAMPP Tools XAMPP 1.7.3 / 5.6.3
查看>>
my read_university
查看>>
network manager
查看>>
OS + Linux Disk disk lvm / disk partition / disk mount / disk io
查看>>
RedHat + OS CPU、MEM、DISK
查看>>
net TCP/IP / TIME_WAIT / tcpip / iperf / cain
查看>>
webServer kzserver/1.0.0
查看>>
OS + Unix IBM Aix basic / topas / nmon / filemon / vmstat / iostat / sysstat/sar
查看>>
my ReadMap subway / metro / map / ditie / gaotie / traffic / jiaotong
查看>>
OS + Linux DNS Server Bind
查看>>
linux下安装django
查看>>
Android 解决TextView设置文本和富文本SpannableString自动换行留空白问题
查看>>
Android开发中Button按钮绑定监听器的方式完全解析
查看>>
Android自定义View实现商品评价星星评分控件
查看>>
postgresql监控工具pgstatspack的安装及使用
查看>>
postgresql查看表的和索引的情况,判断是否膨胀
查看>>
postgresql中根据oid和filenode去找表的物理文件的位置
查看>>