# 1. 钩子函数API
useDrag 拖拽
useDrop 放置
useDragLayer 拖拽层
# Drag 拖拽
import {useDrag} from 'react-dnd'
function Drag() {
const [{isDragging}, drag, dragPreview] = useDrag(() => ({
// 必须,标识可拖动组件类型
type: 'BOX',
// 可选,对象或者函数,获取拖动源信息或者拖动触发事件
item: '',
// 可选,描述拖动预览
previewOptions: '',
// 可选,放置是移动还是复制
options: 'dropEffect',
// 可选,参数(monitor/props),收集器
collect: (monitor) => ({
// 可选,拖动停止触发事件
// end(item, monitor)
// 可选,是否允许拖动
// canDrag(monitor)
// 可选,判断是否被拖拽
// isDragging(monitor),
isDragging: monitor.isDragging()
})
}))
return (
<div ref={dragPreview} style={{opacity: isDragging ? 0.5 : 1}}>
<div role="Handle" ref={drag}/>
</div>
)
}
# Drop 放置
import {useDrop} from 'react-dnd'
function Drop() {
const [{ canDrop, isOver }, drop] = useDrop(() => ({
// 必须,标识可拖动组件类型
accept: 'BOX',
// 可选,放置触发事件
// drop(item, monitor)
// 可选,当项目悬停在组件上触发事件
// hover(item, monitor)
// 可选,是否接受放置源
// canDrop(item, monitor)
// 可选,参数(monitor/props),收集器
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})
}))
return (
<div
ref={drop}
role={'Dustbin'}
style={{ backgroundColor: isOver ? 'red' : 'white' }}
>
{canDrop ? 'Release to drop' : 'Drag a box here'}
</div>
)
}
# DragLayer 拖动层
import { useDragLayer } from 'react-dnd'
function DragLayer(props) {
const collectedProps = useDragLayer(
monitor => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})
)
return <div>...</div>
}
# 2. 装饰器API
高阶函数:高阶组件是一个函数,它接受一个 React 组件类,并返回另一个 React 组件类
# source 拖动源
import React from 'react'
import { DragSource } from 'react-dnd'
const Types = {
CARD: 'card'
}
// 指定拖动源配置
const cardSource = {
// 可选,当前是否允许拖拽
canDrag(props) {
return props.isReady
},
// 可选,
isDragging(props, monitor) {
return monitor.getItem().id === props.id
},
// 必须,拖动开始触发事件
beginDrag(props, monitor, component) {
const item = { id: props.id }
return item
},
// 可选,拖动停止触发事件
endDrag(props, monitor, component) {
// 检查放置是否成功
if (!monitor.didDrop()) {
return
}
// 获取拖拽源数据
const item = monitor.getItem()
// 获取放置结果
const dropResult = monitor.getDropResult()
CardActions.moveCardToList(item.id, dropResult.listId)
}
}
// 指定要注入组件的道具
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
// 向监视器询问当前拖动状态
isDragging: monitor.isDragging()
}
}
class Card {
render() {
const { id } = this.props
const { isDragging, connectDragSource } = this.props
return connectDragSource(
<div>
I am a draggable card number {id}
{isDragging && ' (and I am being dragged now)'}
</div>
)
}
}
export default DragSource(Types.CARD, cardSource, collect)(Card)
# target 放置目标
import React from 'react'
import { findDOMNode } from 'react-dom'
import { DropTarget } from 'react-dnd'
const Types = {
CHESSPIECE: 'chesspiece'
}
const chessSquareTarget = {
// 是否可放置
canDrop(props, monitor) {
const item = monitor.getItem()
return canMakeChessMove(item.fromPosition, props.position)
},
// 可选,组件悬停事件
hover(props, monitor, component) {
const clientOffset = monitor.getClientOffset()
const componentRect = findDOMNode(component).getBoundingClientRect()
const isOnlyThisOne = monitor.isOver({ shallow: true })
const canDrop = monitor.canDrop()
},
// 可选,放置触发事件
drop(props, monitor, component) {
if (monitor.didDrop()) {
return
}
const item = monitor.getItem()
ChessActions.movePiece(item.fromPosition, props.position)
return { moved: true }
}
}
function collect(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
isOverCurrent: monitor.isOver({ shallow: true }),
canDrop: monitor.canDrop(),
itemType: monitor.getItemType()
}
}
class ChessSquare {
componentDidUpdate(prevProps) {
if (!prevProps.isOver && this.props.isOver) {}
if (prevProps.isOver && !this.props.isOver) {}
if (prevProps.isOverCurrent && !this.props.isOverCurrent) {}
}
render() {
const { position } = this.props
const { isOver, canDrop, connectDropTarget } = this.props
return connectDropTarget(
<div className="Cell">
{isOver && canDrop && <div class="green" />}
{!isOver && canDrop && <div class="yellow" />}
{isOver && !canDrop && <div class="red" />}
</div>
)
}
}
export default DropTarget(
Types.CHESSPIECE,
chessSquareTarget,
collect
)(ChessSquare)
# 拖拽层标签:isOver,dnd,return,monitor,咻咻咻,item,props,const From: https://blog.51cto.com/u_16021118/6140345
import React from 'react'
import ItemTypes from './ItemTypes'
import BoxDragPreview from './BoxDragPreview'
import snapToGrid from './snapToGrid'
import { DragLayer } from 'react-dnd'
const layerStyles = {
position: 'fixed',
pointerEvents: 'none',
zIndex: 100,
left: 0,
top: 0,
width: '100%',
height: '100%'
}
function getItemStyles(props) {
const { currentOffset } = props
if (!currentOffset) {
return {
display: 'none'
}
}
const { x, y } = currentOffset
const transform = `translate(${x}px, ${y}px)`
return {
transform: transform,
WebkitTransform: transform
}
}
function CustomDragLayer({ item, itemType, isDragging }) {
if (!isDragging) {
return null
}
function renderItem(type, item) {
switch (type) {
case ItemTypes.BOX:
return <BoxDragPreview title={item.title} />
}
}
return (
<div style={layerStyles}>
<div style={getItemStyles(props)}>{renderItem(itemType, item)}</div>
</div>
)
}
function collect(monitor) {
return {
item: monitor.getItem(),
itemType: monitor.getItemType(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging()
}
}
export default DragLayer(collect)(CustomDragLayer)