React-DnD的简要使用方法与API文档

发布时间 2023-04-14 14:33:40作者: sanhuamao

前提

它这个官方文档贼难进去,而且第一次看的时候也不太好理解,这篇文章就把一些常用的内容记下,希望能帮助到大家。本篇文章参考的是16.0.1版本

npm i react-dnd

1 简单示例

先不说具体API,来看下常用示例~

1.1 useDrag:让DOM允许拖拽

import React from 'react'
import { useDrag } from 'react-dnd'

export default function Player() {
  // 第一个返回值是一个对象,主要放一些拖拽物的状态。后面会介绍,先不管
  // 第二个返回值:顾名思义就是一个Ref,只要将它注入到DOM中,该DOM就会变成一个可拖拽的DOM
  const [_, dragRef] = useDrag({
      type: 'Player', // 给拖拽物命名,后面用于分辨该拖拽物是谁,支持string和symbol
      item: { id:1  }, // 拖拽物所携带的数据,让后面一些事件可以拿到数据,已达到交互的目的
    },[])

  // 由上面示例可知, useDrag所接收的参数一个是对象/函数 和一个依赖数组(可选)

  // 注入Ref,现在这个DOM就可以拖拽了
  return (
    <div ref={dragRef}></div>
  )
}

1.2 useDrop:让DOM作为拖放区域

import { useDrop } from 'react-dnd'

export const Dustbin = () => {
  const [_, dropRef] = useDrop({
    accept: ['Player'],  // 指明该区域允许接收的拖放物。可以是单个,也可以是数组
    // 里面的值就是useDrag所定义的type
    
    // 当拖拽物在这个拖放区域放下时触发,这个item就是拖拽物的item(拖拽物携带的数据)
    drop: (item) => {},
  })

  // 将ref注入进去,这个DOM就可以处理拖拽物了
  return (
    <div ref={dropRef} ></div>
  )
}

1.3. 组合:让DOM作为拖拽物和拖放区域

import React, { useRef } from 'react';
import { useDrag, useDrop } from 'react-dnd';

const Player=({onChangePosition,id})=>{
	const ref = useRef(null);

	// 1. 让DOM作为拖拽物,允许拖放
	const [_, drag] = useDrag(() => ({
	  type: 'PLAYER', 
	  item: { id:1 }  
	}));

	// 2. 让DOM作为可拖放的区域
	const [, drop] = useDrop(() => ({
	  accept: ['PLAYER'],  
	  drop(item) {
		 if (onChangePosition) {
			onChangePosition(item.id,id);
		 }
	  }
	}));

	// 3. 让目标DOM即能作为拖拽物,也能作为拖放区域
	drag(drop(ref));

	// 4. 下面就是施展魔法,把ref注入DOM中
	return <div ref={ref}></div>
}

下面就是枯燥的API搬运了,为了方便理解,以下内容中,由useDrag注册的DOM将称为拖拽物,有useDrop注册的DOM将称为拖放区域

2. useDrag

先放一个官网比较完整的示例:

import { useDrag } from 'react-dnd'

function DraggableComponent(props) {
  // 返回三个值:
  // collected:是一个对象,下面的collect函数返回什么,就有什么,常用于判断拖拽物的状态
  // drag:拖拽物Ref
  // dragPreview: 当DOM处于拖拽状态时,所显示的DOM的ref
   const [{ isDragging }, drag, preview] = useDrag({
      type: 'BOX',
      item: { id:1  },
      // 这个monitor会提供拖拽物状态的信息,我会在下面罗列所有monitor支持的方法
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),  // 是否处于拖拽状态
      }),
    },[],
  )

  return collected.isDragging ? (
    <div ref={preview} />
  ) : (
    <div ref={drag} style={{color:isDragging?'red':'green'}}>
      ...
    </div>
  )
}

2.1 返回值与参数对象

const [collected,dragRef,dragPreviewRef]=useDrag({
	type:'Player',
	item:{id:1},
	previewOptions:{},
	end(item, monitor){...}, // 拖拽停止时调用,item是拖拽物在上方定义的数据
	canDrag(monitor){...},
	isDragging(monitor){...},
	collect(monitor ,props)=>({...})
},[])

  • 返回值
名称 描述
Collected Props speccollect函数返回的属性
DragSource Ref 拖拽物的引用
DragPreview Ref 处于拖拽状态的拖拽物的引用
  • 参数
名称 描述
spec 一个对象或者创建一个返回对象的函数。该对象是一个特定对象
deps 依赖数组

其中spec的对象属性如下:

属性 描述
type 必填。string或symbol类型。拖放区域所接受的拖拽物将从这里挑选
item 必填。函数或对象。拖拽物携带的数据。如果传对象,不建议使用多层嵌套或复杂的对象
previewOptions 用于描述 dragPreviewRef的对象
end(item, monitor) 拖拽停止时调用。可在函数内调用monitor.didDrop() 来判断该拖拽物是否被放在所定义的拖放区域中。如果拖放区域定义了drop(),那么可以通过monitor.getDropResult() 去获取drop返回的类型
canDrag(monitor) 返回布尔值。指明该拖拽物是否允许拖拽。如果想一直允许拖拽,则可以忽略这个属性。(无法再内部调用monitor.canDrag()
isDragging(monitor) 返回布尔值。指明拖拽物是否处于拖拽状态。默认情况下,当拖拽物正拖拽时则被认为是处于拖拽状态。(无法再内部调用monitor.isDragging()
collect(monitor ,props) 返回对象的函数。可以从useDrag返回的第一个值获取

2.2 monitor 属性

记录了拖拽物状态信息,支持的属性如下:

属性 描述
canDrag() 如果没有拖拽操作正在进行,返回true;
isDragging() 如果有拖拽操作正在进行,返回true;
getItemType() 返回拖拽物的定义的type
getItem() 返回拖拽物的定义的item
getDropResult() 当拖放结束,返回拖放区域定义的drop()所返回的对象
didDrop() 如果拖放区域执行了drop(),返回true,即便drop()没有返回对象,也返回true
getInitialClientOffset() 返回拖拽开始时,拖拽物的起点位置
getInitialSourceClientOffset() 返回拖拽开始时,拖拽物的根节点的位置
getClientOffset() 当拖拽正在进行时,返回拖拽物再次过程中最后的位置
getDifferenceFromInitialOffset() 返回最后记录的位置与起点位置的差值
getSourceClientOffset() 返回拖拽物当前在根组件位置与拖拽物最初在根组件位置的差值

3. useDrop

const [collected,dropRef]=useDrop({
	accept:'Player',
	drop(item, monitor){...}, // 拖拽物拖拽进来是调用,item为拖拽物携带的数据
	hover(item, monitor){...}  // 拖拽物悬浮在拖放区域时,item为拖拽物携带的数据
	canDrop(item, monitor){...}
	collect(monitor ,props)=>({...})
},[])

3.1 参数对象

属性 描述
accept 必填。指定拖放区域所接受的拖拽物。string或symbol类型,或者是数组。
drop(item, monitor) 当拖拽物被拖拽进来是调用。而如果函数返回对象,那么对应拖拽物end方法则可以通过monitor.getDropResult() 来获取这个对象
hover(item, monitor) 当拖拽物悬浮在拖放区域时调用。 可以通过monitor.isOver({ shallow: true })来指定是否只悬浮在单个拖放区域上,而不悬浮在嵌套的拖放区域上
canDrop(item, monitor) 返回布尔值。指明该拖放区域是否可用。如果是一直可用,忽略即可。
collect(monitor ,props) 返回对象的函数。可以从useDrop返回的第一个值获取

3.2 monitor 属性

记录了拖放区域拖拽物状态信息,支持的属性如下:

属性 描述
canDrop() 如果有拖拽操作正在进行,返回true;
isOver(options) 如果有拖拽操作正在进行并悬浮在拖放区域上,返回true;可传入{ shallow: true }来指定是否只悬浮在该区域上,而不是悬浮在嵌套的拖放区域上
getItemType() 返回当前拖进来的拖拽物定义的type
getItem() 返回当前拖进来的拖拽物定义的item
getDropResult() 返回当前拖放区域定义的drop()返回的对象
didDrop() 如果拖放区域执行drop()操作,返回true