In diesem Beitrag werden die Grundlagen von Drag-and-drop erläutert.
Ziehbare Inhalte erstellen
In den meisten Browsern sind Textauswahlen, Bilder und Links standardmäßig ziehbar. Wenn du beispielsweise einen Link auf eine Webseite ziehst, siehst du ein kleines Feld mit einem Titel und einer URL, die du in die Adressleiste oder den Desktop ziehen kannst, um eine Verknüpfung zu erstellen oder zum Link zu gehen. Wenn Sie andere Inhaltstypen ziehbar machen möchten, müssen Sie die HTML5 Drag & Drop APIs verwenden.
Wenn Sie ein Objekt ziehbar machen möchten, legen Sie für dieses Element draggable=true
fest. Die Drag-Funktion ist praktisch alles möglich, einschließlich Bilder, Dateien, Links, Dateien oder jegliches Markup auf Ihrer Seite.
Mit dem folgenden Beispiel wird eine Benutzeroberfläche zum Neuanordnen von Spalten erstellt, die mit dem CSS-Raster angeordnet wurden. Das grundlegende Markup für die Spalten sieht so aus, wobei das Attribut draggable
für jede Spalte auf true
festgelegt ist:
<div class="container">
<div draggable="true" class="box">A</div>
<div draggable="true" class="box">B</div>
<div draggable="true" class="box">C</div>
</div>
Hier ist der CSS-Code für die container- und box-Elemente. Das einzige CSS, das mit der Drag-Funktion in Verbindung steht, ist die cursor: move
-Property. Der Rest des Codes steuert das Layout und den Stil der Container- und Box-Elemente.
.container {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 10px;
}
.box {
border: 3px solid #666;
background-color: #ddd;
border-radius: .5em;
padding: 10px;
cursor: move;
}
Jetzt können Sie die Elemente ziehen, ansonsten passiert aber nichts. Wenn Sie das Verhalten hinzufügen möchten, müssen Sie die JavaScript API verwenden.
Auf Drag-Events warten
Zum Überwachen des Drag-Vorgangs können Sie auf eines der folgenden Ereignisse warten:
Für den Ziehfluss benötigen Sie ein Quellelement (wo das Ziehen beginnt), die Datennutzlast (das gezogene Element) und ein Ziel (ein Bereich zum Auffangen des Drag-Vorgangs). Das Quellelement kann fast jede Art von Element sein. Das Ziel ist die Drop-Zone oder eine Gruppe von Drop-Zonen, die die Daten aufnehmen, die der Nutzer löschen möchte. Nicht alle Elemente können Ziele sein. Ihr Ziel darf beispielsweise kein Bild sein.
Ziehsequenz starten und beenden
Nachdem Sie draggable="true"
-Attribute für Ihre Inhalte definiert haben, hängen Sie einen dragstart
-Event-Handler an, um die Ziehsequenz für jede Spalte zu starten.
Mit diesem Code wird die Deckkraft der Spalte auf 40% festgelegt, wenn der Nutzer beginnt, sie zu ziehen, und sie auf 100% zurück, wenn das Drag-Ereignis endet.
function handleDragStart(e) {
this.style.opacity = '0.4';
}
function handleDragEnd(e) {
this.style.opacity = '1';
}
let items = document.querySelectorAll('.container .box');
items.forEach(function (item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragend', handleDragEnd);
});
Das Ergebnis kannst du in der folgenden Glitch-Demo sehen. Wenn Sie ein Element ziehen, ändert sich seine Deckkraft. Da das Quellelement das Ereignis dragstart
enthält, erhält der Nutzer durch Festlegen von this.style.opacity
auf 40% ein visuelles Feedback, dass dieses Element die aktuelle Auswahl ist, die verschoben wird. Wenn Sie das Element löschen, erhält das Quellelement wieder 100% Deckkraft, obwohl Sie das Ablegenverhalten noch nicht definiert haben.
Zusätzliche visuelle Hinweise hinzufügen
Verwenden Sie die Event-Handler dragenter
, dragover
und dragleave
, damit Nutzer besser verstehen, wie sie mit Ihrer Benutzeroberfläche interagieren können. In diesem Beispiel sind die Spalten nicht nur ziehbar, sondern auch Drop-Ziele. Damit der Nutzer dies versteht, wird der Rahmen gestrichelt, wenn er ein gezogenes Element über eine Spalte hält. In Ihrem CSS könnten Sie beispielsweise eine over
-Klasse für Elemente erstellen, die Drop-Ziele sind:
.box.over {
border: 3px dotted #666;
}
Richten Sie dann in Ihrem JavaScript die Event-Handler ein, fügen Sie die Klasse over
hinzu, wenn die Spalte über die Spalte gezogen wird, und entfernen Sie sie, wenn das gezogene Element verlassen wird. Im dragend
-Handler müssen auch die Klassen am Ende des Ziehens entfernt werden.
document.addEventListener('DOMContentLoaded', (event) => {
function handleDragStart(e) {
this.style.opacity = '0.4';
}
function handleDragEnd(e) {
this.style.opacity = '1';
items.forEach(function (item) {
item.classList.remove('over');
});
}
function handleDragOver(e) {
e.preventDefault();
return false;
}
function handleDragEnter(e) {
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over');
}
let items = document.querySelectorAll('.container .box');
items.forEach(function(item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('drop', handleDrop);
});
});
In diesem Code gibt es einige Punkte, die es zu behandeln gilt:
Die Standardaktion für das Ereignis
dragover
besteht darin, das AttributdataTransfer.dropEffect
auf"none"
zu setzen. Die EigenschaftdropEffect
wird weiter unten auf dieser Seite behandelt. Beachten Sie vorerst, dass dasdrop
-Ereignis dadurch nicht ausgelöst wird. Wenn Sie dieses Verhalten überschreiben möchten, rufen Siee.preventDefault()
auf. Außerdem empfiehlt es sich,false
im selben Handler zurückzugeben.Der Event-Handler
dragenter
wird zum Umschalten derover
-Klasse anstelle vondragover
verwendet. Wenn Siedragover
verwenden, wird das Ereignis wiederholt ausgelöst, während der Nutzer das gezogene Element über eine Spalte hält. Dadurch wird die CSS-Klasse wiederholt umgeschaltet. Der Browser führt dann viele unnötige Rendering-Aufgaben aus, was sich negativ auf die Nutzererfahrung auswirken kann. Es wird dringend empfohlen, Neuzeichnungen so gering wie möglich zu halten. Wenn Siedragover
verwenden müssen, sollten Sie den Event-Listener drosseln oder aufheben.
Loslegen
Fügen Sie einen Event-Listener für das drop
-Ereignis hinzu, um das Ablegen zu verarbeiten. Im drop
-Handler musst du das Standardverhalten des Browsers für Drops verhindern, bei dem es sich in der Regel um eine lästige Weiterleitung handelt. Rufen Sie dazu e.stopPropagation()
auf.
function handleDrop(e) {
e.stopPropagation(); // stops the browser from redirecting.
return false;
}
Der neue Handler muss zusammen mit den anderen Handlern registriert werden:
let items = document.querySelectorAll('.container .box');
items.forEach(function(item) {
item.addEventListener('dragstart', handleDragStart);
item.addEventListener('dragover', handleDragOver);
item.addEventListener('dragenter', handleDragEnter);
item.addEventListener('dragleave', handleDragLeave);
item.addEventListener('dragend', handleDragEnd);
item.addEventListener('drop', handleDrop);
});
Wenn Sie den Code an dieser Stelle ausführen, wird das Element nicht am neuen Speicherort abgelegt. Dazu verwenden Sie das Objekt DataTransfer
.
Das Attribut dataTransfer
enthält die bei einer Drag-Aktion gesendeten Daten. dataTransfer
wird im dragstart
-Ereignis festgelegt und im Drop-Ereignis gelesen oder verarbeitet. Durch Aufrufen von e.dataTransfer.setData(mimeType, dataPayload)
können Sie den MIME-Typ und die Datennutzlast des Objekts festlegen.
In diesem Beispiel werden Nutzer die Reihenfolge der Spalten ändern können. Dazu müssen Sie zuerst den HTML-Code des Quellelements speichern, wenn das Ziehen beginnt:
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}
Im drop
-Ereignis verarbeiten Sie den Spalteninhalt, indem Sie den HTML-Code der Quellspalte auf den HTML-Code der Zielspalte setzen, in der Sie die Daten gelöscht haben. Dazu gehört auch, sicherzustellen, dass der Nutzer nicht auf dieselbe Spalte zurückspringt, aus der er gezogen hat.
function handleDrop(e) {
e.stopPropagation();
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}
return false;
}
Das Ergebnis können Sie sich in der folgenden Demo ansehen. Dazu benötigen Sie einen Desktop-Browser. Die Drag & Drop-API wird auf Mobilgeräten nicht unterstützt. Ziehen Sie die Spalte A über die Spalte B und lassen Sie sie los. Sie sehen, wie sich die Position ändert:
Weitere Drag-Eigenschaften
Das dataTransfer
-Objekt stellt Eigenschaften bereit, um dem Nutzer während des Drag-Vorgangs visuelles Feedback zu geben und zu steuern, wie die einzelnen Drop-Ziele auf einen bestimmten Datentyp reagieren.
- Mit
dataTransfer.effectAllowed
wird eingeschränkt, welche Art von Zieh der Nutzer für das Element ausführen kann. Sie wird im Drag-and-drop-Verarbeitungsmodell verwendet, umdropEffect
während der Ereignissedragenter
unddragover
zu initialisieren. Das Attribut kann die folgenden Werte haben:none
,copy
,copyLink
,copyMove
,link
,linkMove
,move
,all
unduninitialized
. dataTransfer.dropEffect
steuert das Feedback, das der Nutzer während der Ereignissedragenter
unddragover
erhält. Wenn der Nutzer den Mauszeiger auf ein Zielelement hält, zeigt der Cursor des Browsers an, welche Art von Vorgang stattfindet, z. B. ein Kopieren oder Verschieben. Die Auswirkung kann einen der folgenden Werte annehmen:none
,copy
,link
,move
.e.dataTransfer.setDragImage(imgElement, x, y)
bedeutet, dass Sie anstelle des standardmäßigen „Ghost Image“-Feedbacks des Browsers ein Drag-Symbol festlegen können.
Datei hochladen
In diesem einfachen Beispiel wird eine Spalte sowohl als Ziehquelle als auch als Ziehziel verwendet. Das kann in einer UI passieren, in der der Nutzer aufgefordert wird, Elemente neu anzuordnen. In einigen Situationen können das Ziehziel und die Quelle unterschiedliche Elementtypen sein, z. B. auf einer Benutzeroberfläche, auf der der Nutzer ein Bild als Hauptbild für ein Produkt auswählen muss, indem er das ausgewählte Bild auf ein Ziel zieht.
Drag-and-drop wird häufig verwendet, damit Nutzer Elemente von ihrem Desktop in eine Anwendung ziehen können. Der Hauptunterschied besteht in Ihrem drop
-Handler. Die Daten sind im Attribut dataTransfer.files
enthalten, anstatt dataTransfer.getData()
für den Zugriff auf die Dateien zu verwenden:
function handleDrop(e) {
e.stopPropagation(); // Stops some browsers from redirecting.
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; (f = files[i]); i++) {
// Read the File objects in this FileList.
}
}
Weitere Informationen hierzu finden Sie unter Benutzerdefiniertes Drag-and-drop.