React-dnd: Como obtenho as coordenadas do meu item largado em relação ao recipiente de destino de descarte?

Criado em 13 mai. 2015  ·  15Comentários  ·  Fonte: react-dnd/react-dnd

Estou trabalhando com 1.0.0-rc.

Em 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);
  }
};

No momento, parece que preciso obter o deslocamento da página do item original, então posso encontrar o deslocamento da página de onde larguei, então preciso encontrar o deslocamento do contêiner de soltar da página e, em seguida, esse cálculo e eu tenho a posição relativa em meu recipiente de destino de gota.

Isso parece muito trabalho para algo muito comum ...

enhancement

Comentários muito úteis

Sim, acho que poderíamos ter isso para simetria. Por enquanto, você pode apenas usar findDOMNode(component).getBoundingClientRect() , mas eu não me importaria de adicionar isso se mais pessoas derem suporte por voz. Vamos manter isso em aberto e ver o que os outros dizem.

Todos 15 comentários

Parece que getClientOffset retorna a posição em relação à janela de visualização. Então, tudo que tenho a fazer é encontrar meu deslocamento no meu alvo de queda. Você acha que ainda vale a pena ter um método de conveniência em relação ao alvo de descarte?

Sim, acho que poderíamos ter isso para simetria. Por enquanto, você pode apenas usar findDOMNode(component).getBoundingClientRect() , mas eu não me importaria de adicionar isso se mais pessoas derem suporte por voz. Vamos manter isso em aberto e ver o que os outros dizem.

Eu também gostaria de algo assim. Preciso obter o retângulo / coordenadas delimitadoras do alvo de queda, então, quando eu passar o mouse sobre ele, posso calcular se está no lado esquerdo, direito, superior ou inferior dentro do alvo de queda.

As coordenadas relativas podem ser úteis para outros casos de uso. Para um aplicativo semelhante ao Trello, quando você arrasta um cartão sobre uma lista, a lista rola para a parte inferior ao pairar próximo à parte inferior da área para soltar e rola para cima ao pairar próximo ao topo.

Trivial para implementar no espaço do usuário tho.

Além disso, lembro-me vagamente de ter lido que acessar o retângulo delimitador dispara refluxo nos navegadores e é um tanto caro. Não tenho certeza se este ainda é o caso.

Não acho que haja uma maneira de fazer isso sem realmente acessar getBoundingClientRect porque você nunca sabe se o item foi movido.

Para um aplicativo semelhante ao Trello, quando você arrasta um cartão sobre uma lista, a lista rola para a parte inferior ao pairar próximo à parte inferior da área para soltar e rola para cima ao pairar próximo ao topo.

Esse é um ótimo caso de uso.

A penalidade de desempenho é realmente significativa e será desperdiçada se for adicionada ao React DnD, mas seu aplicativo não a usar. Portanto, não quero adicionar isso ao React DnD.

É fácil de implementar no domínio do usuário e você poderá fazer coisas como acelerar getBoundingClientRect chamadas ou colocar o código de rolagem relacionado em um quadro de animação.

Estou aberto para adicionar “rolar ao pairar na parte inferior” _como um exemplo_ para o teste de estresse classificável . Isso envolveria adicionar outro destino de soltar no nível do contêiner que apenas escuta hover e rola dentro de um quadro de animação.

No entanto, não adicionarei os métodos de coordenadas DOM ao React DnD pelos motivos descritos acima.

@gaearon Estou interessado em soluções generalizadas. Como podemos usar react-dnd-html5-backend vez de getBoundingClientRect diretamente?

Resolvi isso passando as funções DropTargetMonitor getInitialSourceClientOffset e getSourceClientOffset para uma função de retorno de chamada dentro do meu evento onDrop . Dessa forma, minha função de retorno de chamada pode calcular as coordenadas corretas relacionadas à porta de visualização.

// 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 não funciona com o componente funcional e useDrop#drop não passa nenhum component . Agora, se eu quiser obter ref do meu componente, eu tenho para armazená-lo separadamente e chamar manualmente o conector de gota para passá-lo. Existe alguma maneira mais concisa de fazer isso?

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 , você tem algum exemplo de código completo que gostaria de compartilhar, por favor?

@dendrochronology

Um exemplo inventado: https://codesandbox.io/s/elastic-liskov-00ldf

A API é melhor quando não temos que armazenar ref nós mesmos ( useGlobalDrop vs useLocalDrop ). Agora, se apenas o ref , que presumo que react-dnd já obtém, está anexado ~ ao objeto monitor ~ em algum lugar (acessível em drop , não tenho opinião onde), isso resolveria.

esta solução não é confiável, especialmente quando você aumenta o zoom no navegador ou altera a resolução do dispositivo. qualquer ideia?

eu tenho a mesma pergunta @ sepehr09

Só de passagem depois de algumas pesquisas no google ... Alguma atualização sobre a pergunta original? (obtendo o x / y de um item solto em relação ao alvo de soltar)

Acho que vou entrar na lista de quem precisa disso. Alguma ajuda por favor?

Acho esse recurso muito necessário, precisa ser adicionado na biblioteca. No momento, Alguém já trabalhou com isso, por favor nos ajude!

Esta página foi útil?
0 / 5 - 0 avaliações