【问题标题】:Using a handle with React DND使用带有 React DND 的句柄
【发布时间】:2021-10-04 02:00:14
【问题描述】:

我正在使用 React-dnd,并尝试创建一个包含可排序行的表格,该表格只能从右侧的一个小跨度的句柄中拖动。

他们在这里给出的例子 https://react-dnd.github.io/react-dnd/examples/customize/handles-and-previews

不显示任何排序。我可以使用不同的预览使 Handle 工作,问题是如果我使用它们提供的代码,用于对表格进行排序的 dropzone 仅当我将它直接悬停在跨度上时才有效,而不是像应该的那样悬停在行上。

我的代码:

 const dragRef  = useRef<any>(null)


const [{ isDragging }, drag, preview] = useDrag({
    type: DragTypeEnum.ENTRY,
    item: () => {
        return { id: props.id, index: props.sequence }
    },
    collect: (monitor: any) => ({
        isDragging: monitor.isDragging(),
    }),
});


const [{ handlerId }, drop] = useDrop({
    accept: DragTypeEnum.ENTRY,
    collect(monitor) {
        return {
            handlerId: monitor.getHandlerId(),
        }
    },
    hover(item: DragItem, monitor: DropTargetMonitor) {
        if (!dragRef.current) {
            return
        }
        const dragId = item.id
        const hoverId = props.id;

        // Don't replace items with themselves
        if (dragId === hoverId) {
            return
        }

        // Determine rectangle on screen
        const hoverBoundingRect = dragRef.current?.getBoundingClientRect()

        // Get vertical middle
        const hoverMiddleY =
            (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2

        // Determine mouse position
        const clientOffset = monitor.getClientOffset()

        // Get pixels to the top
        const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top

        // Only perform the move when the mouse has crossed half of the items height
        // When dragging downwards, only move when the cursor is below 50%
        // When dragging upwards, only move when the cursor is above 50%

        // Dragging downwards
        if (dragId < hoverId && hoverClientY < hoverMiddleY) {
            console.log("downwards");
            return
        }

        // Dragging upwards
        if (dragId > hoverId && hoverClientY > hoverMiddleY) {
            console.log("upwards");
            return
        }

        // Time to actually perform the action
        props.moveEntry(dragId, hoverId)      //ONLY FIRING WHEN I GO OVER THE HANDLE :(

        // Note: we're mutating the monitor item here!
        // Generally it's better to avoid mutations,
        // but it's good here for the sake of performance
        // to avoid expensive index searches.
        item.id = hoverId
    },
});


const opacity = isDragging ? 0 : 1;
drag(drop(dragRef))

而表 tsx 是:

    <tr
        style={{ opacity }}
        data-handler-id={handlerId}
        ref={preview}   //THIS SHOULD BE THE PREVIEW HTML AND ALSO WHERE I CAN DRAG INTO
    >
        <td>
        //emptied for demo purpose
        </td>

        <td>
        //emptied for demo purpose
        </td>



        <td>
                    <span ref={dragRef}>                 // THIS IS MY DRAG HANDLE
                        <FontAwesomeIcon 
                            icon="bars"
                            className="pointer"
                        ></FontAwesomeIcon>
                    </span>
                </>
            }
        </td>

    </tr>

【问题讨论】:

    标签: react-hooks react-dnd react-tsx


    【解决方案1】:

    为处理程序和预览创建 2 个参考 比如像这样

    const dragRef = useRef<HTMLDivElement>(null)
    const previewRef = useRef<HTMLDivElement>(null)
    

    那么你需要用处理程序包装你的 refs

    drag(dragRef)
    drop(preview(previewRef))
    

    使用您的代码,它将如下所示:

    const dragRef = useRef<HTMLDivElement>(null)
    const previewRef = useRef<HTMLDivElement>(null)
    
    const [{ isDragging }, drag, preview] = useDrag({
        type: DragTypeEnum.ENTRY,
        item: () => {
            return { id: props.id, index: props.sequence }
        },
        collect: (monitor: any) => ({
            isDragging: monitor.isDragging(),
        }),
    });
    
    const [{ handlerId }, drop] = useDrop({
        accept: DragTypeEnum.ENTRY,
        collect(monitor) {
            return {
                handlerId: monitor.getHandlerId(),
            }
        },
        hover(item: DragItem, monitor: DropTargetMonitor) {
            if (!previewRef.current) {
                return
            }
            const dragId = item.id
            const hoverId = props.id;
    
            // Don't replace items with themselves
            if (dragId === hoverId) {
                return
            }
    
            // Determine rectangle on screen
            const hoverBoundingRect = previewRef.current?.getBoundingClientRect()
    
            // Get vertical middle
            const hoverMiddleY =
                (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
    
            // Determine mouse position
            const clientOffset = monitor.getClientOffset()
    
            // Get pixels to the top
            const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
    
            // Only perform the move when the mouse has crossed half of the items height
            // When dragging downwards, only move when the cursor is below 50%
            // When dragging upwards, only move when the cursor is above 50%
    
            // Dragging downwards
            if (dragId < hoverId && hoverClientY < hoverMiddleY) {
                console.log("downwards");
                return
            }
    
            // Dragging upwards
            if (dragId > hoverId && hoverClientY > hoverMiddleY) {
                console.log("upwards");
                return
            }
    
            // Time to actually perform the action
            props.moveEntry(dragId, hoverId)      //ONLY FIRING WHEN I GO OVER THE HANDLE :(
    
            // Note: we're mutating the monitor item here!
            // Generally it's better to avoid mutations,
            // but it's good here for the sake of performance
            // to avoid expensive index searches.
            item.id = hoverId
        },
    });
    
    
    const opacity = isDragging ? 0 : 1;
    
    drag(dragRef)
    drop(preview(previewRef))
    

    表格

    <tr
            style={{ opacity }}
            data-handler-id={handlerId}
            ref={previewRef}   //THIS SHOULD BE THE PREVIEW HTML AND ALSO WHERE I CAN DRAG INTO
        >
            <td>
            //emptied for demo purpose
            </td>
    
            <td>
            //emptied for demo purpose
            </td>
    
    
    
            <td>
                        <span ref={dragRef}>                 // THIS IS MY DRAG HANDLE
                            <FontAwesomeIcon 
                                icon="bars"
                                className="pointer"
                            ></FontAwesomeIcon>
                        </span>
                    </>
                }
            </td>
    
        </tr>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-06
      • 2022-11-26
      • 2012-06-29
      • 2018-09-26
      • 1970-01-01
      • 2014-11-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多