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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React DnD 是一个 React 的拖放库,可以帮助我们快速实现拖放功能。下面是一个基本的示例: 首先,安装 `react-dnd` 和 `react-dnd-html5-backend`: ``` npm install react-dnd react-dnd-html5-backend ``` 然后,创建一个拖放组件: ```jsx import React from 'react'; import { useDrag } from 'react-dnd'; const Box = ({ name }) => { const [{ isDragging }, drag] = useDrag({ item: { name, type: 'box' }, collect: (monitor) => ({ isDragging: !!monitor.isDragging(), }), }); return ( <div ref={drag} style={{ opacity: isDragging ? 0.5 : 1, fontSize: 20, fontWeight: 'bold', cursor: 'move', }} > {name} </div> ); }; export default Box; ``` 在上面的代码中,我们使用 `useDrag` 钩子来创建一个拖动源。`item` 属性指定了拖动源的参数,`collect` 函数用于收集拖动源的状态。 接下来,创建一个拖放目标组件: ```jsx import React from 'react'; import { useDrop } from 'react-dnd'; const Target = ({ onDrop }) => { const [{ isOver }, drop] = useDrop({ accept: 'box', drop: (item, monitor) => { onDrop(item); }, collect: (monitor) => ({ isOver: !!monitor.isOver(), }), }); return ( <div ref={drop} style={{ width: 200, height: 200, backgroundColor: isOver ? 'yellow' : 'white', }} /> ); }; export default Target; ``` 在上面的代码中,我们使用 `useDrop` 钩子来创建一个拖放目标。`accept` 属性指定了接受的拖动源类型,`drop` 函数用于处理拖放事件,`collect` 函数用于收集拖放目标的状态。 最后,在父组件中使用这两个组件: ```jsx import React, { useState } from 'react'; import Box from './Box'; import Target from './Target'; const App = () => { const [droppedBox, setDroppedBox] = useState(null); const handleDrop = (item) => { setDroppedBox(item.name); }; return ( <div> <Box name="Box 1" /> <Box name="Box 2" /> <Box name="Box 3" /> <Target onDrop={handleDrop} /> {droppedBox && <p>Dropped box: {droppedBox}</p>} </div> ); }; export default App; ``` 在上面的代码中,我们使用 `useState` 钩子来保存拖放目标接受的拖动源名称。`handleDrop` 函数用于处理拖放事件,并更新状态。最后,我们在页面上显示拖放的结果。 这就是一个简单的 React DnD 示例。如果想要了解更多内容,可以查看官方文档:https://react-dnd.github.io/react-dnd/docs/overview。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值