前提
它这个官方文档贼难进去,而且第一次看的时候也不太好理解,这篇文章就把一些常用的内容记下,希望能帮助到大家。本篇文章参考的是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 | spec 中collect 函数返回的属性 |
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 |