React-dnd: Как мне получить координаты моего брошенного предмета относительно целевого контейнера для перетаскивания?

Созданный на 13 мая 2015  ·  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 functions getInitialSourceClientOffset и getSourceClientOffset в функцию обратного вызова внутри моего события 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 моего компонента, у меня есть сохранить его отдельно и вручную вызвать ответвительный коннектор, чтобы передать его. Есть ли более краткий способ сделать это?

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://codesandbox.io/s/elastic-liskov-00ldf

API лучше, когда нам не нужно хранить ref сами ( useGlobalDrop vs useLocalDrop ). Теперь, если только ref , который, как я полагаю, уже получен react-dnd , прикреплен ~ к monitor объекту ~ где-то (доступному в drop , у меня нет мнение где), это решило бы это.

это решение ненадежно, особенно при увеличении масштаба браузера или изменении разрешения устройства. любая идея?

у меня такой же вопрос @ sepehr09

Просто проходя мимо после нескольких поисков в Google ... Есть ли обновления по исходному вопросу? (получение x / y выпадающего предмета относительно цели выпадения)

Думаю, я присоединюсь к списку тех, кому это нужно. Любая помощь, пожалуйста?

Я думаю, что эта функция очень нужна, ее нужно добавить в библиотеку. Прямо сейчас, кто-нибудь работал с этим, пожалуйста, помогите нам!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги