React-dnd: Comment obtenir les coordonnées de mon élément déposé par rapport au conteneur cible de dépôt ?

Créé le 13 mai 2015  ·  15Commentaires  ·  Source: react-dnd/react-dnd

Je travaille avec 1.0.0-rc.

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

À l'heure actuelle, il semble que je doive obtenir le décalage à partir de la page de l'élément d'origine, puis je peux trouver le décalage à partir de la page où j'ai déposé, puis je dois trouver le décalage du conteneur de dépôt à partir de la page, puis faire ce calcul et j'ai la position relative dans mon conteneur de cible de dépôt.

Cela semble être beaucoup de travail pour quelque chose d'assez commun...

enhancement

Commentaire le plus utile

Ouais, je suppose qu'on pourrait avoir ça pour la symétrie. Pour l'instant, vous pouvez simplement utiliser findDOMNode(component).getBoundingClientRect() , mais cela ne me dérangerait pas de l'ajouter si davantage de personnes prennent en charge la voix. Gardons cela ouvert et voyons ce que les autres disent.

Tous les 15 commentaires

On dirait que getClientOffset me renvoie la position par rapport à la fenêtre. Alors tout ce que j'ai à faire est de trouver mon décalage dans ma cible de chute. Pensez-vous qu'il vaut toujours la peine d'avoir une méthode pratique par rapport à la cible de dépôt ?

Ouais, je suppose qu'on pourrait avoir ça pour la symétrie. Pour l'instant, vous pouvez simplement utiliser findDOMNode(component).getBoundingClientRect() , mais cela ne me dérangerait pas de l'ajouter si davantage de personnes prennent en charge la voix. Gardons cela ouvert et voyons ce que les autres disent.

Je voudrais quelque chose comme ça aussi. J'ai besoin d'obtenir le rectangle/les coordonnées englobantes de la cible de dépôt, donc quand je survole quelque chose dessus, je peux calculer si c'est à gauche, à droite, en haut ou en bas à l'intérieur de la cible de dépôt.

Les coordonnées relatives peuvent être utiles pour d'autres cas d'utilisation. Pour une application de type Trello, lorsque vous faites glisser une carte sur une liste, la liste défile vers le bas lorsque vous survolez près du bas de la zone de dépôt et défile vers le haut lorsque vous survolez près du haut.

Trivial à mettre en œuvre sur l'espace utilisateur tho.

De plus, je me souviens vaguement d'avoir lu que l'accès au rectangle englobant déclenche une refusion dans les navigateurs et un peu coûteux. Pas sûr que ce soit toujours le cas.

Je ne pense pas qu'il existe un moyen de le faire sans accéder réellement à getBoundingClientRect parce que vous ne savez jamais si l'élément a bougé.

Pour une application de type Trello, lorsque vous faites glisser une carte sur une liste, la liste défile vers le bas lorsque vous survolez près du bas de la zone de dépôt et défile vers le haut lorsque vous survolez près du haut.

C'est un excellent cas d'utilisation.

La pénalité de perf est en effet importante et sera gaspillée si elle est ajoutée à React DnD mais que votre application ne l'utilise pas. Par conséquent, je ne veux pas ajouter cela à React DnD.

Il est facile à implémenter dans l'espace utilisateur, et vous pourrez faire des choses comme étrangler les appels getBoundingClientRect , ou mettre le code de défilement associé dans un cadre d'animation.

Je suis ouvert à l'ajout de "faire défiler en survolant en bas" _comme exemple_ au test de résistance triable . Cela impliquerait l'ajout d'une autre cible de dépôt au niveau du conteneur qui n'écoute que hover et défile à l'intérieur d'un cadre d'animation.

Cependant, je n'ajouterai pas les méthodes de coordonnées DOM à React DnD pour les raisons décrites ci-dessus.

@gaearon Je suis intéressé par une solution généralisée. Comment pouvons-nous utiliser react-dnd-html5-backend au lieu de getBoundingClientRect directement ?

J'ai résolu ce problème en passant les fonctions DropTargetMonitor getInitialSourceClientOffset et getSourceClientOffset à une fonction de rappel dans mon événement onDrop . De cette façon, ma fonction de rappel peut calculer les coordonnées correctes liées au port de vue.

// 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 ne fonctionne pas avec le composant fonctionnel et useDrop#drop ne transmet aucun component . Maintenant, si je veux obtenir le ref de mon composant, j'ai pour le stocker séparément et appeler manuellement le connecteur de dérivation pour le transmettre. Y a-t-il une façon plus concise de faire cela?

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 avez-vous des exemples de code complets que vous voudriez partager, s'il vous plaît ?

@dendrochronologie

Un exemple artificiel : https://codesandbox.io/s/elastic-liskov-00ldf

L'API est plus agréable lorsque nous n'avons pas à stocker nous-mêmes les ref ( useGlobalDrop vs useLocalDrop ). Maintenant, si seulement le ref , que je suppose que react-dnd obtient déjà, est attaché ~à l'objet monitor ~ quelque part (accessible dans drop , je n'ai pas opinion où), cela résoudrait ce problème.

cette solution n'est pas fiable, surtout lorsque vous zoomez dans le navigateur ou que la résolution de l'appareil change. une idée?

j'ai la même question @sepehr09

Je passe juste après quelques recherches sur google... Une mise à jour sur la question d'origine ? (obtention du x/y d'un élément déposé par rapport à la cible de dépôt)

Je suppose que je vais rejoindre la liste de ceux qui en ont besoin. Une aide s'il vous plait ?

Je pense que cette fonctionnalité est très nécessaire, doit être ajoutée dans la bibliothèque. En ce moment, quelqu'un a travaillé avec, aidez-nous s'il vous plaît !

Cette page vous a été utile?
0 / 5 - 0 notes