核心API

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

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

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

  1. // Box.jsx
  2. import { DragSource } from 'react-dnd';
  3. @DragSource(type, spec, collect)
  4. export default class Box {
  5. /* ... */
  6. }
  7. // Dustbin.jsx
  8. import { DropTarget } from 'react-dnd';
  9. @DropTarget(types, spec, collect)
  10. export default class Contaier {
  11. /* ... */
  12. }
  13. // Contaier.jsx (DragDropContex)
  14. import { DragDropContext } from 'react-dnd'
  15. import HTML5Backend from 'react-dnd-html5-backend'
  16. import Box from './Box';
  17. import Dustbin from './Dustbin';
  18. @DragDropContext(HTML5Backend)
  19. export default class Contaier extends Component {
  20. render() {
  21. return (
  22. <div>
  23. <Dustbin/>
  24. <Box/>
  25. </div>
  26. );
  27. }
  28. }
  29. // 也可以写成 Contaier.jsx (DragDropContextProvider)
  30. import { DragDropContextProvider } from 'react-dnd'
  31. import HTML5Backend from 'react-dnd-html5-backend'
  32. import Box from './Box';
  33. import Dustbin from './Dustbin';
  34. export default class DustbinContaier extends Component {
  35. render() {
  36. return (
  37. <DragDropContextProvider backend = { HTML5Backend }>
  38. <div>
  39. <Dustbin/>
  40. <Box/>
  41. </div>
  42. </DragDropContextProvider>
  43. );
  44. }
  45. }

API参数介绍

上面的代码

  1. @DragSource(type, spec, collect)
  2. @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。

翻译为代码:

  1. // ItemTypes.js 定义类型
  2. export default {
  3. BOX: 'box',
  4. }
  5. // Box.jsx
  6. import ItemTypes from './ItemTypes'
  7. @DragSource(ItemTypes.BOX, spec, collect)
  8. // Dustbin.jsx
  9. import ItemTypes from './ItemTypes'
  10. @DropTarget(ItemTypes.BOX, spec, collect)

spec

spec定义特定方法的对象。

  1. source组件的spec 可以定义 拖动 相关的事件;
  2. target组件的spec 可以定义 放置 相关的事件,具体列表:
  • beginDrag(props, monitor, component): 拖动开始时触发的事件,必须。返回跟props相关的对象。
  • endDrag(props, monitor, component): 拖动结束时触发的事件,可选。
  • canDrag(props, monitor): 当前是否可以拖拽的事件,可选。
  • isDragging(props, monitor): 拖拽时触发的事件,可选。

翻译为代码:

  1. // Box.jsx
  2. const sourceSpec = {
  3. beginDrag(props, monitor, component){
  4. // 返回需要注入的属性
  5. return {
  6. id: props.id
  7. }
  8. },
  9. endDrag(props, monitor, component){
  10. // ..
  11. },
  12. canDrag(props, monitor){
  13. // ..
  14. },
  15. isDragging(props, monitor){
  16. // ..
  17. }
  18. }
  19. @DragSource(ItemTypes.BOX, sourceSpec, collect)
  • drop(props, monitor, component) 组件放下时触发的事件,可选。
  • hover(props, monitor, component) 组件在DropTarget上方时响应的事件,可选。
  • canDrop(props, monitor) 组件可以被放置时触发的事件,可选。

翻译为代码:

  1. // Dustbin.jsx
  2. const targetSpec = {
  3. drop(props, monitor, component){
  4. // ..
  5. },
  6. hover(props, monitor, component){
  7. // ..
  8. },
  9. canDrop(props, monitor){
  10. // ..
  11. }
  12. }
  13. @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 连接起来的方法。

翻译为代码:

  1. // Box.jsx
  2. @DragSource(ItemTypes.BOX, sourceSpec,(connect)=>({
  3. connectDragSource: connect.dragSource(),
  4. connectDragPreview: connect.dragPreview(),
  5. }))
  6. export default class Box {
  7. render() {
  8. const { connectDragSource } = this.props
  9. return connectDragSource(
  10. <div>
  11. {
  12. /* ... */
  13. }
  14. </div>,
  15. )
  16. }
  17. }
  18. // Dustbin.jsx
  19. @DropTarget(ItemTypes.BOX, targetSpec, (connect)=>{
  20. connectDropTarget: connect.dropTarget(),
  21. })
  22. export default class Dustbin {
  23. render() {
  24. const { connectDropTarget } = this.props
  25. return connectDropTarget(
  26. <div>
  27. {
  28. /* ... */
  29. }
  30. </div>,
  31. )
  32. }
  33. }

monitor

monitor 用于查询当前的拖拽状态,其对应实例内置了很多方法。

source组件 collect 中 monitor是 DragSourceMonitor的实例。

target组件 collect 中 monitor是 DropTargetMonitor的实例。

内置方法列表:

  1. // DragSourceMonitor
  2. monitor.canDrag() // 是否能被拖拽
  3. monitor.isDragging() // 是否正在拖拽
  4. monitor.getItemType() // 拖拽组件type
  5. monitor.getItem() // 当前拖拽的item
  6. monitor.getDropResult() // 查询drop结果
  7. monitor.didDrop() // source是否已经drop在target
  8. monitor.getInitialClientOffset() // 拖拽组件初始拖拽时offset
  9. monitor.getInitialSourceClientOffset()
  10. monitor.getClientOffset() // 拖拽组件当前offset
  11. monitor.getDifferenceFromInitialOffset() // 当前拖拽offset和初始拖拽offset的差别
  12. monitor.getSourceClientOffset()
  13. // DropTargetMonitor
  14. monitor.canDrop() // 是否可被放置
  15. monitor.isOver(options) // source是否在target上方
  16. monitor.getItemType() // 拖拽组件type
  17. monitor.getItem() // 当前拖拽的item
  18. monitor.getDropResult() // 查询drop结果
  19. monitor.didDrop() // source是否已经drop在target
  20. monitor.getInitialClientOffset() // 拖拽组件初始拖拽时offset
  21. monitor.getInitialSourceClientOffset()
  22. monitor.getClientOffset() // 拖拽组件当前offset
  23. monitor.getDifferenceFromInitialOffset() // 当前拖拽offset和初始拖拽offset的差别
  24. monitor.getSourceClientOffset()

实例

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

  1. import React, { Component } from 'react';
  2. import { DragSource, DropTarget } from 'react-dnd';
  3. const sourceSpec = {
  4. beginDrag(props) {
  5. return {
  6. id: props.id,
  7. index: props.index
  8. }
  9. },
  10. }
  11. const targetSpec = {
  12. // 组件下放时响应的事件
  13. drop(props, monitor) {
  14. const dragIndex = monitor.getItem().index;
  15. const hoverIndex = props.index;
  16. if (dragIndex === hoverIndex) {
  17. return;
  18. }
  19. props.moveFN(dragIndex, hoverIndex);
  20. monitor.getItem().index = hoverIndex;
  21. },
  22. // hover(props, monitor, component){} // 组件在DropTarget上方时响应的事件
  23. }
  24. class BodyRow extends Component {
  25. render() {
  26. const {
  27. connectDragSource,
  28. connectDropTarget,
  29. id,
  30. } = this.props;
  31. const style = {cursor: 'move' };
  32. // 实际展示出来的东西
  33. return connectDragSource(
  34. connectDropTarget(
  35. <p style={style}>{id}</p>
  36. )
  37. );
  38. }
  39. }
  40. // DragSource 用于包装你需要拖动的组件,使组件能够被拖拽(make it draggable)
  41. // DropTarget 用于包装接收拖拽元素的组件,使组件能够放置(dropped on it)
  42. // 当 source组件的type 和 target组件的type 一致时,target组件可以接受source组件。
  43. const DragableBody = DropTarget(
  44. 'box', // 拖拽类型
  45. targetSpec, // 拖拽事件的方法对象
  46. (connect, monitor) => ({
  47. connectDropTarget: connect.dropTarget(),
  48. isOver: monitor.isOver(),
  49. }), // 把拖拽过程中需要信息注入组件的 props,接收两个参数 connect and monitor,必填。
  50. )(
  51. DragSource(
  52. 'box',
  53. sourceSpec,
  54. (connect) => ({
  55. connectDragSource: connect.dragSource(),
  56. }),
  57. )(PBodyRow),
  58. );
  59. export default DragableBody;

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

  1. import React, { Component } from 'react';
  2. import { DragDropContextProvider,DragDropContext } from 'react-dnd';
  3. import HTML5Backend from 'react-dnd-html5-backend';
  4. import update from 'immutability-helper';
  5. import DragableBody from './DragableBody';
  6. class Dnd extends Component {
  7. state = {
  8. cardList: ['red', 'green', 'yellow', 'blue']
  9. }
  10. moveFN =(dragIndex, hoverIndex)=> {
  11. const { cardList } = this.state;
  12. const dragRow = cardList[dragIndex];
  13. this.setState(
  14. update(this.state, {
  15. cardList: {
  16. $splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]],
  17. },
  18. }),
  19. );
  20. }
  21. render() {
  22. let { cardList } = this.state;
  23. return (
  24. // <DragDropContextProvider backend={HTML5Backend}> // DragDropContextProvider易用性不高;推荐DragDropContext。
  25. <div className="App">
  26. {cardList.map((item, index) =>
  27. <PBodyRow
  28. id={item}
  29. index={index}
  30. moveFN={this.moveFN}
  31. key={item}
  32. />
  33. )}
  34. </div>
  35. // </DragDropContextProvider>
  36. );
  37. }
  38. }
  39. export default DragDropContext(HTML5Backend)(Dnd); // 这样页面中可以同时使用多个

react-dnd使用介绍的更多相关文章

  1. 强大的拖拽组件:React DnD 的使用

    强大的拖拽组件:React DnD 的使用 react.js 10.6k 次阅读  ·  读完需要 25 分钟 17 文章首发我的个人blog : 原文链接 学习 React DnD 的最初原因是阅读 ...

  2. 学习笔记-React的简单介绍&工作原理

    一.React简单介绍 1.React起源于Facebook内部项目,与2013年5月 2.是一个用于构建用户界面的JavaScript库 二.React特点 1.声明式设计-React采用声明范式, ...

  3. React Native组件介绍

    1.React Native目前已有的组件 ActivityIndicatorIOS:标准的旋转进度轮; DatePickerIOS:日期选择器: Image:图片控件: ListView:列表控件: ...

  4. React Native文件介绍

    一.index.ios.js文件中的东西 index.ios.js文件,是js代码的入口文件,所有的代码编写从这开始,可以定义自己的模块和引入第三方模块. import React, { Compon ...

  5. react dnd demo2

    import React, { Component } from 'react'; import './App.css'; import Card from './Card'; import HTML ...

  6. react dnd demo

    target import React ,{ Component } from 'react'; import { DropTarget } from 'react-dnd'; import Item ...

  7. react 生命周期函数介绍

    constructor():构造函数 执行:组件加载钱最先调用一次,仅调用一次. 作用:定义状态机变量. 注意:第一个语句必须为super(), 否则会报错:'this' is not allowed ...

  8. react常用模块介绍

    react各个模块: 1.node.js自带的模块(原生模块):https://www.jianshu.com/p/abc72267abfc原生模块的api文档地址:http://nodejs.cn/ ...

  9. React 生命周期介绍

    [组件生命周期] 一.理论 组件本质上是状态机,输入确定,输出一定确定 生命周期的三个阶段,三者时间是不固定的,只是在逻辑上的分类: 二.初始化阶段: getDefaultProps:获取实例的默认属 ...

  10. React组件详细介绍及其生命周期函数

    组件的详细说明 通过Reac.createClass({...})创建组件的时候,应该有一个render()方法,也可以在其中添加生命周期函数. render方法 当调用该方法的时候,会检测this. ...

随机推荐

  1. 蓝桥杯算法训练 java算法 表达式求值

    问题描述 输入一个只包含加减乖除和括号的合法表达式,求表达式的值.其中除表示整除. 输入格式 输入一行,包含一个表达式. 输出格式 输出这个表达式的值. 样例输入 1-2+3*(4-5) 样例输出 - ...

  2. POJ 3017 DP + 单调队列 + 堆

    题意:给你一个长度为n的数列,你需要把这个数列分成几段,每段的和不超过m,问各段的最大值之和的最小值是多少? 思路:dp方程如下:设dp[i]为把前i个数分成合法的若干段最大值的最小值是多少.dp转移 ...

  3. 解决git无法clone地址为https的库

    一.问题描述 早上在学习<Spark快速大数据分析>的时候,需要下载书本的实例代码,于是用git clone一下给出的库: https://github.com/databricks/le ...

  4. java 将一个数组中的值按逆序重新存放,例如,原来顺序为:9,5,7,4,8,要求改为:8,4,7, 5,9。

    public class Test3 { public static void main(String[] args) { int[] grade = {87,88,89,98,78}; int m; ...

  5. code1039 数的划分

    来自http://blog.csdn.net/WhiStLenA/article/details/51585992 重点内容 设F(i,j)为用j个数组成i,答案为F(7,3)的话. 一个思路是,对于 ...

  6. Python爬虫实战三之实现山东大学无线网络掉线自动重连

    综述 最近山大软件园校区QLSC_STU无线网掉线掉的厉害,连上之后平均十分钟左右掉线一次,很是让人心烦,还能不能愉快地上自习了?能忍吗?反正我是不能忍了,嗯,自己动手,丰衣足食!写个程序解决掉它! ...

  7. python3--多目录之间的协作的一些必备知识

    # Auther: Aaron Fan # 动态获取执行文件的相对路径路径:print(__file__) #动态获取执行文件的绝对路径:import osfile_path = os.path.ab ...

  8. 使用shell命令操作数据库

    使用mysql的-e参数可以执行各种sql的(创建,删除,增,删,改.查)等各种操作 用法 mysql  -uxxx    –pxxx   -e  "mysql 命令" 当然还可以 ...

  9. vmware workstation 12 密钥

    VMware Workstation 12序列号:5A02H-AU243-TZJ49-GTC7K-3C61N

  10. 重定向和请求转发后面加“return;”语句

    请求转发  RequestDispatcher 重定向     Redirect 代码的执行: 无论是 request.getRequestDispatcher(path).forward(reque ...