React-dnd: Unterstützen Sie das Ziehen mehrerer Elemente

Erstellt am 25. Okt. 2014  ·  30Kommentare  ·  Quelle: react-dnd/react-dnd

Es gibt ein allgemeines Muster, das mit nativem Drag & Drop schwer zu implementieren ist: das Ziehen mehrerer Elemente. Die Auswahlmechanismen können zwar von App zu App unterschiedlich sein (cmd+Klicken, Kontrollkästchen, vordefinierte Gruppen), aber es wäre schön, es zumindest _möglich_ zu machen, dieses Szenario zu unterstützen.

screen shot 2014-10-26 at 1 07 07

Da mehrere gezogene Elemente in DOM möglicherweise keine Geschwister sind und setDragImage(element, x, y) ziemlich verrückt ist und nicht besser geworden ist, werden wir uns nicht damit belasten, mehrere Elemente gleichzeitig in der Drag-Vorschau zu rendern.

Wie können wir bei der Umsetzung dieses Szenarios helfen, wenn wir keine "mehrere" Drag-Vorschau anzeigen können?

In gewisser Weise ist dieses Szenario bereits möglich: Verbraucher können ausgewählte Elemente manuell nachverfolgen, dragPreview auf eine Art generischen Platzhalter Image und entsprechend auf das Weglassen von (sofern Geschäft Logik betrifft) mehrere Elemente.

Derzeit gibt es jedoch keine unterstützte Möglichkeit für ein Element, zu erkennen, dass es Teil einer gezogenen Gruppe ist. Aus der Sicht von React-dnd erhält diese Komponente getDragState(type).isDragging = true , wenn wir etwas ziehen, andere Komponenten jedoch nicht. Wenn Sie die Mehrfachauswahl aus Sicht Ihrer App unterstützen, möchten Sie, dass alle logisch "ausgewählten" Elemente wissen, dass sie gezogen werden, auch wenn nur eines von ihnen tatsächlich "DOM-gezogen" wird.

Was wir brauchen, ist eine Möglichkeit, damit die Komponenten reagieren-dnd sagen können: „Hey, obwohl onDragStart von einer anderen Komponente empfangen wurde, möchte ich so tun, als würde ich auch gezogen und habe meine getDragState(type) hat getDragState(type) Komponente endDrag(didDrop) aufgerufen, damit ich meine Sachen erledigen kann“.

Wie würden sich Komponenten dafür entscheiden?

design decisions

Hilfreichster Kommentar

Wenn es jemanden interessiert, habe ich eine Mehrfach-Drag / Grid-Ansicht implementiert: https://codesandbox.io/s/9j897k0mwy.
Sie können Cmd/Strg und Umschalttaste verwenden, um mehrere Elemente auszuwählen, sie dann um das Raster zu ziehen und an einer beliebigen Stelle einzufügen.

Dies ist immer noch eine Demo, aber ich könnte den Code etwas mehr abstrahieren und ihn später in eine Komponente packen.

Alle 30 Kommentare

Keine Priorität. Wir können es nach der Einführung von Drag-Quellschlüsseln erneut besuchen (https://github.com/gaearon/react-dnd/issues/38#issuecomment-73409935).

Ich werde mich später dafür interessieren, obwohl ich denke, dass Sie möglicherweise einfach einen Abschnitt Ihres Komponentenbaums mit einer Komponente umschließen können, die eine dragSource hat ...
Wenn Sie beispielsweise die Umschalttaste gedrückt halten und klicken, werden die Abschnitte des Arrays erweitert, die in das DragItem kopiert werden oder so?

Irgendwie.

Zuerst lernen wir, null component (benötigt für #38) und eine andere Komponente mit demselben key (benötigt für #53) zu übergeben.

Dann fügen wir groupKey was optional ist. Wie key wird es in der Drag-Quelle angegeben und ist ein String. Wenn Sie anfangen, etwas mit einem groupKey , rufen wir beginDrag nicht nur beim Aufrufer, sondern bei jeder gemounteten Drag-Quelle mit demselben groupKey und sammeln ihre Gegenstände in eine Anordnung. Wir werden diese Elemente anstelle von item , um Zielmethoden zu löschen. Wenn das Ziehen beendet ist, rufen wir acceptDrop auf dem Drop-Ziel mit einem Elementarray auf und rufen dann die endDrag jeder Ziehquelle mit ihrem Element auf.

Was Spaß macht, ist, dass wir DragLayer mit einer benutzerdefinierten „zusammengesetzten“ Miniaturansichtskomponente und einem Zähler zeichnen können, wie ich oben einen Screenshot gemacht habe, weil wir die Anzahl von items.length .

Das ist eine viel weniger hässliche Idee, als ich sie im Sinn hatte

:+1: für diese Funktion :-)

Schließen, da ich derzeit keinen Anwendungsfall dafür habe, und es ist ein erheblicher Implementierungsaufwand.

@gaearon

Ich habe früher Java/Swing DnD verwendet, und sie hatten wahrscheinlich eine Armee von Entwicklern, die sich mit diesem Problem auseinandergesetzt und ein ziemlich raffiniertes, extrem generisches und flexibles Framework entwickelt haben. Ich würde empfehlen, alte Desktop-Frameworks zu recherchieren, da sie wahrscheinlich alle schwierigen Herausforderungen bei der Erstellung eines guten DnD-Frameworks wie diesem gelöst haben.

Der Weg dazu in Java/Swing (obwohl es keine integrierte Unterstützung für Drag-Images hatte) bestand darin, _die Baumansicht selbst zur Drag-Quelle zu machen_ und es _in der Lage zu machen, zu entscheiden, ob ein Drag basierend auf seiner Funktion initiiert werden soll oder nicht aktueller Status und die Drag-Startposition_. Ist monitor.getInitialSourceClientOffset() verfügbar, wenn canDrag und beginDrag aufgerufen werden? Die Leute werden auf jeden Fall wollen, dass es verfügbar ist. Sie möchten wahrscheinlich auch, dass Modifikatortasten (Strg, Alt, Umschalt) verfügbar sind und Drag-Quellen angeben können, ob sie verschoben oder kopiert werden sollen, und Drop-Ziele angeben können, um anzugeben, ob sie Verschieben und/oder Kopieren unterstützen, basierend auf einem von diese Faktoren, denn das ist in Java/Swing möglich und ich vermute andere Frameworks. Swing hatte auch das Konzept von _Drag-Gesten-Erkennern_, die ausgetauscht werden konnten.

Ich würde vorhersagen, dass es schwierig sein wird, alle Elemente in der Liste als einzelne Draggables zu behandeln, verglichen damit, dass die Listenkomponente die einzige Drag-Quelle ist, die herausfindet, welche Art von Drop-Nutzlast / Vorschaubild basierend auf der Auswahl darin erstellt werden soll.

Bedenken Sie auch, dass ein Entwickler _die Reihenfolge der gezogenen Elemente ändern möchte, je nachdem, auf welches Element der Benutzer geklickt und aus dem gezogen wurde._ Ich glaube, Windows Explorer verhält sich auf diese Weise.

Hat jemand das Ziehen mehrerer Elemente mit React-dnd in seinen Anwendungen implementiert? Was ist Ihre aktuelle Lösung dafür?

Meinten Sie mehrere Drop-Ziele für eine einzelne Drag-Quelle?

+1 @danii1 : Hat jemand das Ziehen mehrerer Elemente implementiert?

Ich habe es implementiert, die Lösung ist im Wesentlichen das, was im ersten Beitrag beschrieben ist:

  1. Behalten Sie den Überblick über Ihre ausgewählten Artikel
  2. Implementieren Sie CustomDragLayer (siehe https://gaearon.github.io/react-dnd/docs-drag-layer.html) und rendern Sie Ihre ausgewählten Elemente selbst
  3. Behandeln Sie das Ablegen, wenn das abgelegte Element Teil der Auswahl ist

Ich habe es implementiert durch:

  1. Behalte den Überblick über ausgewählte Gegenstände in einem Set
  2. Übergeben Sie dies als Eigenschaft an die dnd-Quelle
  3. Rufen Sie in beginDrag das Set von den Requisiten ab und geben Sie es als Drag-Element zurück
  4. Erstellen Sie eine benutzerdefinierte Ziehvorschau
  5. Verschieben Sie bei EndDrag alle Elemente des Sets in das dnd-Ziel

Ich habe einen etwas anderen Anwendungsfall dafür, denke ich, ich möchte Knoten zeichnen, die ziehbar sind, mit Kanten, die nicht ziehbar sind, sich aber bewegen, wenn Knoten zum Verschieben angebracht sind. Meine aktuelle Implementierung ist ein CustomDragLayer , das die Kanten zeichnet, wenn es erkennt, dass sich ein DraggableNode bewegt (ebenfalls auf dem CustomDragLayer gezeichnet, aber ich denke, es könnte besser sein, es als Mehrfach-Drag-Situation, indem alle Kanten als DragSources implementiert werden, wobei isDragging() implementiert ist, um zu erkennen, ob sich ein Knoten, mit dem sie verbunden sind, bewegt, damit sie sich selbst zeichnen können, anstatt die Koordinaten von CustomDragLayer als Requisiten einzufügen .

@danii1
Können Sie bitte die von Ihnen implementierte als Referenz mitteilen?

Ich werde einen Beitrag schreiben und ein Repo über mehrere und verschachtelte Drag-and-Drop mit React-dnd + Redux hinzufügen.

@nayemmajhar , das wäre toll

@nayemmajhar ein Update zu einem Beispiel damit?

Ich habe diese Anwendung vor langer Zeit mit React DnD mit reduxJS entwickelt https://www.joomshaper.com/page-builder Ich schreibe ein Tutorial, brauche aber Zeit zum Veröffentlichen

@serle Könnten Sie ein Codebeispiel teilen, wie Sie dies gemacht haben?

Ich versuche, Multi-Drag in einem Beispiel ähnlich dem sortierbaren Beispiel hier zu implementieren: https://react-dnd.github.io/react-dnd/examples-sortable-simple.html. Ich möchte in der Lage sein, beliebige Objekte auszuwählen und sie dann als Einheit in der Liste nach oben und unten zu verschieben. Ich habe Probleme, meinen Kopf darüber zu wickeln, wie ich die oben geteilten Beispiele / Informationen dazu verwenden kann. Irgendwelche Gedanken/Ideen/Feedback, wie das funktionieren könnte?

Wenn es jemanden interessiert, habe ich eine Mehrfach-Drag / Grid-Ansicht implementiert: https://codesandbox.io/s/9j897k0mwy.
Sie können Cmd/Strg und Umschalttaste verwenden, um mehrere Elemente auszuwählen, sie dann um das Raster zu ziehen und an einer beliebigen Stelle einzufügen.

Dies ist immer noch eine Demo, aber ich könnte den Code etwas mehr abstrahieren und ihn später in eine Komponente packen.

@melvynhills Haben Sie eine Lösung untersucht, bei der nicht alle ausgewählten Karten an jede

@jmcrthrs Nein, es scheint mir mit der

@melvynhills @jmcrthrs Andere Desktop-dnd-Frameworks, die ich verwendet habe, basieren darauf , Listen und Tabellen zu den Drag-Quellen / Drop-Zielen zu machen, anstatt jede einzelne Zeile, Zelle, jedes Element usw. zu einer eigenen Drag-Quelle und / oder einem eigenen Drop-Ziel zu machen. Die Implementierung zum Ziehen mehrerer Elemente sowie zum Abrufen der spezifischen Ablageposition innerhalb der Liste oder Tabelle ist auf diese Weise viel sauberer. Wenn eine Liste ein Drag-Start-Ereignis empfängt, kann sie sich einfach die aktuell ausgewählten Elemente ansehen.

@jedwards1211 denkst du, dass es mit dieser Bibliothek machbar ist? Insbesondere der Anwendungsfall, ein Element zu ziehen, das vor dem Ziehen nicht ausgewählt war. Ich bin mir nicht sicher, ob das die Art und Weise ist, wie React-dnd funktionieren soll.

Hat jemand einen Fall gelöst, in dem es mehrere Drop-Targets gibt?
Nehmen wir an, man zieht mehrere Elemente (mit einer der obigen Lösungen) und ein Element landet auf einem Typ von Ablageziel und das andere auf einem anderen. drop wird nur für die Ziehquelle ausgelöst, die das Ziehen initiiert hat, aber nicht für die andere. Irgendwelche Ideen, wie Sie das Ablegen für jedes Element, das verschoben wird, einzeln auslösen können.
Beispiel:
Is development slow, Online Whiteboard for Visual Collaboration 2019-11-27 10-45-33

BEARBEITEN: Separate Ausgabe für diese erstellt https://github.com/react-dnd/react-dnd/issues/1650

@melvynhills wahrscheinlich, wenn ein mousedown Handler die Elementauswahl auslöst (was Sie tun sollten, alle Software mit DnD, die ich verwendet habe, funktioniert auf diese Weise), wird es mit React DnD gut funktionieren, damit die Containerkomponente der Drag ist source, da die Ziehereignisse nach mousedown .

Haben Sie eine Lösung untersucht, bei der nicht alle ausgewählten Karten an jede Kartenkomponente weitergegeben werden müssen?

Dies ist ein Beispiel dafür, warum ich empfehlen würde, die Containerkomponente anstelle der einzelnen Elemente zur Ziehquelle zu machen. Ich musste Multiselect nicht mit React DnD implementieren, aber vielleicht kann ich irgendwann eine Sandbox erstellen, um die Leute davon zu überzeugen, dass es der wartungsfreundlichere Ansatz ist

Hat jemand das Ziehen mehrerer Elemente mit React-beautiful-dnd in seine Anwendungen implementiert? Was ist Ihre aktuelle Lösung dafür?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen