React-dnd: 如何获取我的掉落物品相对于放置目标容器的坐标?

创建于 2015-05-13  ·  15评论  ·  资料来源: react-dnd/react-dnd

我正在使用 1.0.0-rc。

drag-around-naive

const boxTarget = {
  drop(props, monitor, component) {
    const item = monitor.getItem();
    const delta = monitor.getDifferenceFromInitialOffset();
    const left = Math.round(item.left + delta.x);
    const top = Math.round(item.top + delta.y);

    component.moveBox(item.id, left, top);
  }
};

目前看起来我需要从原始项目的页面获取偏移量,然后我可以找到我放置的页面的偏移量,然后我需要从页面中找到放置容器的偏移量,然后做该计算和我在放置目标容器中的相对位置。

对于非常常见的事情来说,这似乎需要做很多工作......

enhancement

最有用的评论

是的,我想我们可以用这个来对称。 目前,您可以只使用findDOMNode(component).getBoundingClientRect() ,但如果有更多人支持语音,我不介意添加此功能。 让我们保持开放,看看其他人怎么说。

所有15条评论

似乎getClientOffset返回了相对于视口的位置。 那么我所要做的就是在我的放置目标中找到我的偏移量。 你认为它仍然值得拥有一个相对于放置目标的便捷方法吗?

是的,我想我们可以用这个来对称。 目前,您可以只使用findDOMNode(component).getBoundingClientRect() ,但如果有更多人支持语音,我不介意添加此功能。 让我们保持开放,看看其他人怎么说。

我也想要这样的东西。 我需要获取放置目标的边界矩形/坐标,因此当我将某物悬停在其上时,我可以计算它是否位于放置目标内的左侧、右侧、顶部或底部。

相对坐标可用于其他用例。 对于类似 Trello 的应用程序,当您将卡片拖到列表上时,当悬停在放置区域底部附近时列表会滚动到底部,而在悬停在顶部附近时会向上滚动。

在用户空间上实现很简单。

此外,我依稀记得读到访问边界矩形会触发浏览器中的回流并且有些昂贵。 不确定是否仍然如此。

我不认为有一种方法可以在不实际访问getBoundingClientRect情况下执行此操作,因为您永远不知道该项目是否移动。

对于类似 Trello 的应用程序,当您将卡片拖到列表上时,当悬停在放置区域底部附近时列表会滚动到底部,而在悬停在顶部附近时会向上滚动。

这是一个很好的用例。

性能损失确实很重要,如果将其添加到 React DnD 但您的应用程序不使用它,则会被浪费掉。 因此,我不想将此添加到 React DnD。

在用户空间中很容易实现,您将能够执行诸如限制getBoundingClientRect调用之类的操作,或者将相关的滚动代码放入动画帧中。

我愿意将“在底部悬停时滚动”_作为示例_添加到可排序压力测试中。 这将涉及在容器级别添加另一个放置目标,该目标仅侦听hover并在动画帧内滚动。

但是,由于上述原因,我不会将 DOM 坐标方法添加到 React DnD。

@gaearon我对通用解决方案感兴趣。 我们如何直接使用react-dnd-html5-backend而不是getBoundingClientRect

我通过将DropTargetMonitor函数getInitialSourceClientOffsetgetSourceClientOffset传递给我的onDrop事件中的回调函数来解决这个问题。 这样,我的回调函数就可以计算出与视口相关的正确坐标。

// some code before...

const [, dropRef] = useDrop({
    accept: 'STICKY',
    drop(item, monitor) {
      move(
        item.id,
        monitor.getInitialSourceClientOffset(),
        monitor.getSourceClientOffset()
      );
    },
  });

// I'm updating my state with npm immer (immutable helper) throuthg the produce function...

const move = (id, initialPosition, finalPosition) => {
    setList(
      produce(list, draft => {
        list.map(item => {
          if (item.id === id) {
            item.position = getCorrectDroppedOffsetValue(
              initialPosition,
              finalPosition
            );
          }
          return item;
        });
      })
    );
  };

// and finally, my getCorrectDroppedOffsetValue function
const getCorrectDroppedOffsetValue = (initialPosition, finalPosition) => {
    // get the container (view port) position by react ref...
    const dropTargetPosition = ref.current.getBoundingClientRect();

    const { y: finalY, x: finalX } = finalPosition;
    const { y: initialY, x: initialX } = initialPosition;

    // calculate the correct position removing the viewport position.
   // finalY > initialY, I'm dragging down, otherwise, dragging up
    const newYposition =
      finalY > initialY
        ? initialY + (finalY - initialY) - dropTargetPosition.top
        : initialY - (initialY - finalY) - dropTargetPosition.top;

    const newXposition =
      finalX > initialX
        ? initialX + (finalX - initialX) - dropTargetPosition.left
        : initialX - (initialX - finalX) - dropTargetPosition.left;

    return {
      x: newXposition,
      y: newYposition,
    };
  };

findDOMNode不适用于功能组件,并且useDrop#drop不会传入任何component 。现在如果我想获得我的组件的ref将其单独存储并手动调用drop连接器以传递它。 有没有更简洁的方法来做到这一点?

function useCustomDrop(onDrop: (info: unknown, xy: Point) => void) {

    const ref = useRef<Element>();

    const [, dropTarget] = useDrop<any, void, unknown>({
        accept: 'item-type',
        drop(item, monitor) {
            const offset = monitor.getSourceClientOffset();
            if (offset && ref.current) {
                const dropTargetXy = ref.current.getBoundingClientRect();
                onDrop(item.data, {
                    x: offset.x - dropTargetXy.left,
                    y: offset.y - dropTargetXy.top,
                });
            }
        }
    });

    return (elem) => {
        ref.current = elem;
        dropTarget(ref);
    };
}

@quanganhtran请问您有愿意分享的完整代码示例吗?

@dendrochronology

一个人为的例子: https :

当我们不必自己存储ref时,API 会更好( useGlobalDrop vs useLocalDrop )。 现在,如果只有ref ,我假设react-dnd已经获得,附加到monitor对象〜某处(可在drop ,我没有意见在哪里),它会解决这个问题。

此解决方案不可靠,尤其是当您放大浏览器或更改设备分辨率时。 任何的想法?

我有同样的问题@sepehr09

只是经过几次谷歌搜索后路过......原始问题的任何更新? (获取相对于放置目标的放置项目的 x/y)

我想我会加入那些需要这个的名单。 请问有什么帮助吗?

我觉得这个功能很有必要,需要在库中添加。 现在,任何人使用它,请帮助我们!

此页面是否有帮助?
0 / 5 - 0 等级