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...
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!
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.