React-dnd: Wie erhalte ich die Koordinaten meines abgelegten Artikels relativ zum Drop-Zielcontainer?

Erstellt am 13. Mai 2015  ·  15Kommentare  ·  Quelle: react-dnd/react-dnd

Ich arbeite mit 1.0.0-rc.

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

Im Moment sieht es so aus, als müsste ich den Offset von der Seite des Originalelements abrufen, dann kann ich den Offset von der Seite finden, auf der ich abgelegt habe, dann muss ich den Offset des Drop-Containers von der Seite finden, dann mach diese Berechnung und ich habe die relative Position in meinem Drop-Ziel-Container.

Das scheint eine Menge Arbeit für etwas ziemlich Alltägliches zu sein...

enhancement

Hilfreichster Kommentar

Ja, ich denke, wir könnten das aus Symmetriegründen haben. Im Moment können Sie einfach findDOMNode(component).getBoundingClientRect() , aber ich hätte nichts dagegen, dies hinzuzufügen, wenn mehr Leute Unterstützung sagen würden. Lassen Sie uns das offen halten und sehen, was andere sagen.

Alle 15 Kommentare

Scheint, als würde mir getClientOffset die Position relativ zum Ansichtsfenster zurückgeben. Dann muss ich nur noch meinen Offset in meinem Drop-Target finden. Glauben Sie, dass es sich immer noch lohnt, eine praktische Methode in Bezug auf das Drop-Target zu haben?

Ja, ich denke, wir könnten das aus Symmetriegründen haben. Im Moment können Sie einfach findDOMNode(component).getBoundingClientRect() , aber ich hätte nichts dagegen, dies hinzuzufügen, wenn mehr Leute Unterstützung sagen würden. Lassen Sie uns das offen halten und sehen, was andere sagen.

So etwas hätte ich auch gerne. Ich muss die Begrenzungsrechte / Koordinaten des Drop-Ziels abrufen, damit ich, wenn ich mit etwas darüber fahre, berechnen kann, ob es sich links, rechts, oben oder unten innerhalb des Drop-Ziels befindet.

Die relativen Koordinaten können für andere Anwendungsfälle nützlich sein. Wenn Sie bei einer Trello-ähnlichen App eine Karte über eine Liste ziehen, scrollt die Liste nach unten, wenn der Mauszeiger nahe dem unteren Rand des Drop-Bereichs bewegt wird, und scrollt nach oben, wenn der Mauszeiger nahe dem oberen Rand bewegt wird.

Trivial zu implementieren im Benutzerbereich tho.

Außerdem erinnere ich mich vage daran, gelesen zu haben, dass der Zugriff auf das Begrenzungsrechteck in Browsern einen Reflow auslöst und etwas kostspielig ist. Nicht sicher, ob dies immer noch der Fall ist.

Ich glaube nicht, dass es eine Möglichkeit gibt, dies zu tun, ohne tatsächlich auf getBoundingClientRect zuzugreifen, da Sie nie wissen, ob das Element verschoben wurde.

Wenn Sie bei einer Trello-ähnlichen App eine Karte über eine Liste ziehen, scrollt die Liste nach unten, wenn der Mauszeiger nahe dem unteren Rand des Drop-Bereichs bewegt wird, und scrollt nach oben, wenn der Mauszeiger nahe dem oberen Rand bewegt wird.

Das ist ein großartiger Anwendungsfall.

Der Perf-Abzug ist in der Tat erheblich und wird verschwendet, wenn er zu React DnD hinzugefügt wird, Ihre App ihn jedoch nicht verwendet. Daher möchte ich dies nicht zu React DnD hinzufügen.

Es ist einfach im Userland zu implementieren und Sie können Dinge wie getBoundingClientRect Aufrufe drosseln oder den zugehörigen Scroll-Code in einen Animationsrahmen einfügen.

Ich bin offen dafür, dem sortierbaren Stresstest _als Beispiel_ "scroll on hover at the bottom" hinzuzufügen. Dies würde das Hinzufügen eines weiteren Ablageziels auf Containerebene erfordern, das nur auf hover lauscht und innerhalb eines Animationsframes scrollt.

Ich werde die DOM-Koordinatenmethoden jedoch aus den oben beschriebenen Gründen nicht zu React DnD hinzufügen.

@gaearon Ich interessiere mich für eine verallgemeinerte Lösung. Wie können wir react-dnd-html5-backend anstelle von getBoundingClientRect direkt verwenden?

Ich habe dies gelöst, indem ich die DropTargetMonitor Funktionen getInitialSourceClientOffset und getSourceClientOffset an eine Callback-Funktion innerhalb meines onDrop Ereignisses übergeben habe. Auf diese Weise kann meine Callback-Funktion die korrekten Koordinaten in Bezug auf den Viewport berechnen.

// 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 funktioniert nicht mit funktionalen Komponenten, und useDrop#drop übergibt keine component . Wenn ich jetzt die ref meiner Komponente erhalten möchte, die ich habe um es separat zu speichern und den Drop-Connector manuell aufzurufen, um es zu übergeben. Gibt es eine kürzere Möglichkeit, dies zu tun?

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 haben Sie bitte vollständige Codebeispiele, die Sie gerne teilen würden?

@dendrochronologie

Ein erfundenes Beispiel: https://codesandbox.io/s/elastic-liskov-00ldf

Die API ist schöner, wenn wir die ref selbst speichern müssen ( useGlobalDrop vs useLocalDrop ). Wenn nun nur das ref , von dem ich annehme, dass react-dnd bereits vorhanden ist, ~an das monitor Objekt~ angehängt ist (zugänglich in drop , habe ich keine Meinung wo), es würde dies lösen.

Diese Lösung ist nicht zuverlässig, insbesondere wenn Sie den Browser vergrößern oder die Geräteauflösung ändern. irgendeine Idee?

Ich habe die gleiche Frage @sepehr09

Nach ein paar Google-Suchen einfach vorbeikommen ... Irgendein Update zur ursprünglichen Frage? (Ermitteln des x/y eines abgelegten Gegenstands relativ zum Ablageziel)

Ich denke, ich werde mich der Liste derer anschließen, die das brauchen. Irgendwelche Hilfe bitte?

Ich denke, diese Funktion ist sehr notwendig, muss in der Bibliothek hinzugefügt werden. Im Moment hat jemand damit gearbeitet, bitte helft uns!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen