如何实现 react-dnd useDragLayer?

Posted

技术标签:

【中文标题】如何实现 react-dnd useDragLayer?【英文标题】:How to implement react-dnd useDragLayer? 【发布时间】:2021-11-25 03:08:49 【问题描述】:

我有一个组件当前使用useDrag 挂钩连接到 react-dnd。它运行良好,除了预览。正如许多在线线程所建议的那样,我想实现 useDragLayer 来查看它是否有助于解决我的预览问题。

这是我当前的(简化的)useDrag 实现:

const [ isDragging , connectDragSource, connectPreview] = useDrag(
  item,
  collect: monitor => (
    isDragging: monitor.getItem()?.index === item.index,
  )
)

return (
  <Wrapper ref=connectPreview isDragging=isDragging>
    <DragHandle ref=connectDragSource />
  </Wrapper> 
)

如何在这种情况下使用useDragLayer,以有助于我的预览?文档示例对我来说毫无意义...

如何使用useDragLayer api 连接我渲染的组件? useDragLayer 不返回拖动源和预览连接器函数(就像 useDrag 在返回数组的索引 1 和 2 上所做的那样),并且它的 collect 函数也不提供 DragSourceConnector 实例。那么调用后的钩子/返回值该怎么办呢?

【问题讨论】:

【参考方案1】:

我刚刚解决了这个问题并想分享它以帮助其他人:)

您需要做几件事才能使其充分发挥作用。

    通过添加以下 useEffect 禁用默认预览行为
import  getEmptyImage  from "react-dnd-html5-backend";

const [ isDragging , drag, dragPreview] = useDrag(() => (
  type: "BOX",
  collect: (monitor) => (
    isDragging: monitor.isDragging(),
  ),
));

useEffect(() => 
  dragPreview(getEmptyImage(),  captureDraggingState: true );
, []);
    创建自定义默认图层

export const CustomDragLayer = (props: ) => 
  const 
    itemType,
    isDragging,
    initialCursorOffset,
    initialFileOffset,
    currentFileOffset,
   = useDragLayer((monitor) => (
    item: monitor.getItem(),
    itemType: monitor.getItemType(),
    initialCursorOffset: monitor.getInitialClientOffset(),
    initialFileOffset: monitor.getInitialSourceClientOffset(),
    currentFileOffset: monitor.getSourceClientOffset(),
    isDragging: monitor.isDragging(),
  ));

  if (!isDragging) 
    return null;
  

  return (
    <div style=layerStyles>
      <div
        style=getItemStyles(
          initialCursorOffset,
          initialFileOffset,
          currentFileOffset
        )
      >
        <div>Your custom drag preview component logic here</div>
      </div>
    </div>
  );
;

const layerStyles: CSSProperties = 
  position: "fixed",
  pointerEvents: "none",
  zIndex: 100,
  left: 0,
  top: 0,
  width: "100%",
  height: "100%",
  border: "10px solid red",
;

function getItemStyles(
  initialCursorOffset: XYCoord | null,
  initialOffset: XYCoord | null,
  currentOffset: XYCoord | null
) 
  if (!initialOffset || !currentOffset || !initialCursorOffset) 
    return 
      display: "none",
    ;
  

  const x = initialCursorOffset?.x + (currentOffset.x - initialOffset.x);
  const y = initialCursorOffset?.y + (currentOffset.y - initialOffset.y);
  const transform = `translate($xpx, $ypx)`;

  return 
    transform,
    WebkitTransform: transform,
    background: "red",
    width: "200px",
  ;


    &lt;CustomDragLayer /&gt; 添加到***组件

您需要将ref=drag 包含到要拖动的组件中,并完全删除connectPreview 引用。

希望对您有所帮助。

【讨论】:

以上是关于如何实现 react-dnd useDragLayer?的主要内容,如果未能解决你的问题,请参考以下文章

如何将项目拖放到 react-dnd 中的空白部分?

react-dnd 的 connectDragPreview() 是如何工作的?

react-dnd 中的动画

react-dnd 简单的可排序示例 ES6 而不是 ES7

使用 react-dnd 和 useDrag 和 useDrop 进行测试

react-dnd 拖拽 九宫格