dnd 咻咻咻

# 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)
# 拖拽层

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)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值