Drag’n’Drop ist eine großartige Schnittstellenlösung. Etwas zu nehmen und es per Drag & Drop zu verschieben, ist eine klare und einfache Möglichkeit, viele Dinge zu tun, vom Kopieren und Verschieben von Dokumenten (wie in Dateimanagern) bis zum Bestellen (Ablegen von Artikeln in einen Warenkorb).
Im modernen HTML Standardmäßig gibt es einen Abschnitt über Drag & Drop mit speziellen Ereignissen wie dragstart
, dragend
usw.
Diese Ereignisse ermöglichen es uns, spezielle Arten von Drag’n’Drop zu unterstützen, z. B. das Ziehen einer Datei aus dem Dateimanager des Betriebssystems und das Ablegen im Browserfenster. Dann kann JavaScript auf den Inhalt solcher Dateien zugreifen.
Native Drag-Ereignisse haben jedoch auch Einschränkungen. Beispielsweise können wir das Ziehen aus einem bestimmten Bereich nicht verhindern. Außerdem können wir das Ziehen nicht nur „horizontal“ oder „vertikal“ machen. Und es gibt viele andere Drag & Drop-Aufgaben, die mit ihnen nicht ausgeführt werden können. Die Unterstützung mobiler Geräte für solche Ereignisse ist ebenfalls sehr schwach.
Hier sehen wir also, wie Drag’n’Drop mithilfe von Mausereignissen implementiert wird.
Drag’n’Drop-Algorithmus
Der grundlegende Drag’n’Drop-Algorithmus sieht folgendermaßen aus:
- On
mousedown
– Bereiten Sie das Element für das Verschieben vor, wenn benötigt (erstellen Sie möglicherweise einen Klon davon, fügen Sie eine Klasse hinzu oder was auch immer). - Verschieben Sie ihn dann auf
mousemove
, indem Sie mitposition:absolute
. - Bei
mouseup
– führen Sie alle Aktionen aus, die mit dem Beenden des Drag’n zusammenhängen ‚drop.
Dies sind die Grundlagen. Später werden wir sehen, wie andere Funktionen ausgeführt werden, z. B. das Hervorheben der aktuellen zugrunde liegenden Elemente, während wir darüber ziehen.
Hier ist die Implementierung des Ziehens eines Balls:
Wenn wir den Code ausführen, wir können etwas Seltsames bemerken. Zu Beginn des Drag’n’Drops „gabelt“ sich der Ball: Wir beginnen mit dem Ziehen seines „Klons“.
Hier ist ein Beispiel in Aktion:
Wenn Sie versuchen, mit der Maus zu ziehen, wird ein solches Verhalten angezeigt.
Dies liegt daran, dass der Browser eine eigene Drag & Drop-Unterstützung für Bilder und Bilder hat einige andere Elemente. Es wird automatisch ausgeführt und steht in Konflikt mit unserem.
So deaktivieren Sie es:
Jetzt ist alles in Ordnung.
In Aktion:
Ein weiterer wichtiger Aspekt – Wir verfolgen mousemove
auf document
, nicht auf ball
. Auf den ersten Blick scheint die Maus immer über dem Ball zu sein, und wir können mousemove
darauf setzen.
Aber wie wir uns erinnern, mousemove
wird häufig ausgelöst, jedoch nicht für jedes Pixel. Nach einer schnellen Bewegung kann der Zeiger also irgendwo in der Mitte des Dokuments (oder sogar außerhalb des Fensters) vom Ball springen.
Wir sollten also document
abhören
Richtige Positionierung
In den obigen Beispielen wird der Ball immer so bewegt, dass sich seine Mitte unter dem Zeiger befindet:
Nicht schlecht, aber es gibt einen Nebeneffekt. Um den Drag & Drop zu starten, können wir mousedown
überall auf dem Ball platzieren. Wenn Sie es jedoch von seiner Kante „nehmen“, „springt“ der Ball plötzlich, um unter dem Mauszeiger zentriert zu werden.
Es wäre besser, wenn wir die anfängliche Verschiebung des Elements relativ zum Zeiger beibehalten.
Wenn wir beispielsweise an der Kante des Balls ziehen, sollte der Zeiger beim Ziehen über der Kante bleiben.
Aktualisieren wir unseren Algorithmus:
Der endgültige Code mit besserer Positionierung:
In Aktion (innerhalb von <iframe>
) :
Der Unterschied macht sich besonders bemerkbar, wenn wir den Ball an der rechten unteren Ecke ziehen. Im vorherigen Beispiel „springt“ der Ball unter den Zeiger. Jetzt folgt er fließend dem Zeiger von der aktuellen Position.
Potenzielle Drop-Ziele (Droppables)
In den vorherigen Beispielen konnte der Ball einfach „überall“ fallen gelassen werden, um zu bleiben. Im wirklichen Leben nehmen wir normalerweise ein Element und lassen es auf ein anderes fallen. Zum Beispiel eine „Datei“ in einen „Ordner“ oder etwas anderes.
Wenn wir abstrakt sprechen, nehmen wir ein „ziehbares“ Element und legen es auf einem „ablegbaren“ Element ab.
Wir müssen wissen:
- wo das Element am Ende von Drag’n’Drop abgelegt wurde – um die entsprechende Aktion auszuführen,
- und vorzugsweise kennen wir das ablegbare Wir Ziehen Sie es herüber, um es hervorzuheben.
Die Lösung ist irgendwie interessant und nur ein bisschen knifflig. Lassen Sie es uns hier behandeln.
Was kann das sein? die erste idee? Wahrscheinlich, um mouseover/mouseup
-Handler auf potenzielle Droppables zu setzen?
Aber das funktioniert nicht.
Das Problem ist, dass wir es sind Beim Ziehen befindet sich das ziehbare Element immer über anderen Elementen.Mausereignisse treten nur auf dem obersten Element auf, nicht auf den darunter liegenden.
Im Folgenden finden Sie beispielsweise zwei <div>
-Elemente, ein rotes über dem blauen eine (vollständig abdeckt). Es gibt keine Möglichkeit, ein Ereignis auf dem blauen abzufangen, da das rote oben ist:
Dasselbe gilt für ein ziehbares Element. Der Ball ist immer oben auf anderen Elementen, so dass Ereignisse darauf stattfinden. Unabhängig davon, welche Handler wir auf niedrigere Elemente setzen, funktionieren sie nicht.
Aus diesem Grund funktioniert die ursprüngliche Idee, Handler auf potenzielle Droppables zu setzen, in der Praxis nicht. Sie werden nicht ausgeführt.
Also, was ist zu tun?
Es gibt eine Methode namens document.elementFromPoint(clientX, clientY)
. Es gibt das am meisten verschachtelte Element für bestimmte fensterbezogene Koordinaten zurück (oder null
, wenn bestimmte Koordinaten außerhalb des Fensters liegen).
Wir können es in jedem von verwenden Unsere Maus-Ereignishandler, um das potenzielle Abfallen unter dem Zeiger wie folgt zu erkennen:
Bitte beachten Sie: Wir müssen den Ball vor dem Aufruf (*)
verstecken. Andernfalls haben wir normalerweise einen Ball auf diesen Koordinaten, da dies das oberste Element unter dem Zeiger ist: elemBelow=ball
. Also verstecken wir es und zeigen es sofort wieder an.
Mit diesem Code können wir jederzeit überprüfen, über welches Element wir „fliegen“. Und den Drop behandeln, wenn es passiert.
Ein erweiterter Code von onMouseMove
zum Auffinden von „abnehmbaren“ Elementen:
Im folgenden Beispiel wird das Tor hervorgehoben, wenn der Ball über das Fußballtor gezogen wird.
Jetzt haben wir das aktuelle „Drop-Ziel“, über das wir fliegen, in der Variablen currentDroppable
während des gesamten Prozesses und können es zum Hervorheben von oder verwenden andere Dinge.
Zusammenfassung
Wir haben einen grundlegenden Drag’n’Drop-Algorithmus in Betracht gezogen.
Die Schlüsselkomponenten:
- Ereignisfluss:
ball.mousedown
→document.mousemove
→ball.mouseup
(vergessen Sie nicht, native abzubrechenondragstart
). - Denken Sie beim Ziehen an die anfängliche Verschiebung des Zeigers relativ zum Element:
shiftX/shiftY
und behalten Sie es während des Ziehens bei. - Erkennen Sie fallende Elemente und Er den Zeiger mit
document.elementFromPoint
.
Wir können viel auf diese Grundlage legen.
- Auf
mouseup
Wir können den Drop intellektuell abschließen: Daten ändern, Elemente verschieben. - Wir können die Elemente hervorheben, über die wir fliegen.
- Wir kann das Ziehen um einen bestimmten Bereich oder eine bestimmte Richtung begrenzen.
- Wir können die Ereignisdelegierung für
mousedown/up
verwenden. Ein großflächiger Ereignishandler, derevent.target
überprüft, kann Drag’n’Drop für Hunderte von Elementen verwalten. - usw.
Es gibt Frameworks, die eine Architektur darüber erstellen: DragZone
, Droppable
, Draggable
und andere Klassen. Die meisten von ihnen machen ähnliche Dinge wie oben beschrieben, daher sollte es jetzt leicht sein, sie zu verstehen. Oder rollen Sie Ihre eigenen, da Sie sehen, dass dies einfach genug ist, manchmal einfacher als das Anpassen einer Lösung eines Drittanbieters.