In diesem Beitrag werden die Grundlagen des Drag-and-drop-Verfahrens erläutert.
Ziehbare Inhalte erstellen
In den meisten Browsern können Textauszüge, Bilder und Links standardmäßig verschoben werden. Wenn Sie beispielsweise einen Link auf einer Webseite ziehen, wird ein kleines Feld mit einem Titel und einer URL angezeigt, das Sie auf die Adressleiste oder den Desktop ziehen können, um einen Verknüpfung zu erstellen oder den Link aufzurufen. Wenn Sie andere Arten von Inhalten per Drag-and-drop verschieben möchten, müssen Sie die HTML5-Drag-and-drop-APIs verwenden.
Wenn Sie ein Objekt ziehbar machen möchten, setzen Sie für dieses Element draggable=true
. Fast alles kann per Drag-and-drop verschoben werden, einschließlich Bildern, Dateien, Links oder Markups auf Ihrer Seite.
Im folgenden Beispiel wird eine Benutzeroberfläche erstellt, mit der Spalten neu angeordnet werden können, die mit CSS-Grid angeordnet wurden. Das grundlegende Markup für die Spalten sieht so aus. Dabei ist das draggable
-Attribut für jede Spalte auf true
festgelegt:
<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 das CSS für die Container- und Box-Elemente. Die einzige CSS-Property, die sich auf die Drag-Funktion bezieht, ist cursor: move
. Der Rest des Codes steuert das Layout und die Formatierung 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;
}
Sie können die Elemente zwar verschieben, aber es passiert sonst nichts. Wenn Sie ein Verhalten hinzufügen möchten, müssen Sie die JavaScript API verwenden.
Auf Drag-Ereignisse warten
Sie können eines der folgenden Ereignisse beobachten, um den Ziehvorgang zu überwachen:
Für die Drag-and-drop-Funktion benötigen Sie ein Quellelement (wo das Ziehen beginnt), die Datennutzlast (das Objekt, das gezogen wird) und ein Ziel (einen Bereich, in den das Objekt abgelegt werden soll). Das Quellelement kann fast jede Art von Element sein. Das Ziel ist die Dropzone oder Gruppe von Dropzones, in die der Nutzer die Daten ablegen möchte. Nicht alle Elemente können als Ziele festgelegt werden. Ihr Ziel kann beispielsweise kein Bild sein.
Drag-and-drop-Sequenz starten und beenden
Nachdem Sie draggable="true"
-Attribute für Ihren Inhalt definiert haben, fügen Sie einen dragstart
-Ereignishandler hinzu, um die Drag-and-drop-Sequenz für jede Spalte zu starten.
Mit diesem Code wird die Deckkraft der Spalte auf 40% gesetzt, wenn der Nutzer sie zu ziehen beginnt, und dann wieder auf 100 %, wenn das Ziehen beendet wird.
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 ist in der folgenden Glitch-Demo zu sehen. Wenn Sie ein Element ziehen, ändert sich seine Deckkraft. Da das Quellelement das Ereignis dragstart
hat, erhält der Nutzer durch die Einstellung von this.style.opacity
auf 40% visuelles Feedback, dass dieses Element die aktuelle Auswahl ist, die verschoben wird. Wenn Sie das Element ablegen, wird die Deckkraft des Quellelements wieder auf 100% zurückgesetzt, auch wenn Sie das Drop-Verhalten noch nicht definiert haben.
Zusätzliche visuelle Hinweise hinzufügen
Verwenden Sie die Event-Handler dragenter
, dragover
und dragleave
, um Nutzern zu verdeutlichen, wie sie mit Ihrer Benutzeroberfläche interagieren können. In diesem Beispiel sind die Spalten nicht nur verschiebbar, sondern auch Drop-Ziele. Erläutern Sie dies den Nutzern, indem Sie den Rahmen gepunktet darstellen, wenn sie ein gezogenes Element über eine Spalte halten. Sie können beispielsweise in Ihrem CSS eine over
-Klasse für Elemente erstellen, die Drop-Ziele sind:
.box.over {
border: 3px dotted #666;
}
Richten Sie dann in Ihrem JavaScript die Ereignishandler ein, fügen Sie die Klasse over
hinzu, wenn die Spalte verschoben wird, und entfernen Sie sie, wenn das verschobene Element die Spalte verlässt. Im dragend
-Handler entfernen wir außerdem die Klassen am Ende des Ziehens.
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);
});
});
Bei diesem Code gibt es einige Punkte, die es zu beachten gilt:
Die Standardaktion für das Ereignis
dragover
besteht darin, die EigenschaftdataTransfer.dropEffect
auf"none"
festzulegen. Die PropertydropEffect
wird weiter unten auf dieser Seite behandelt. Fürs Erste sei nur gesagt, dass dadurch das Ereignisdrop
verhindert wird. Wenn Sie dieses Verhalten überschreiben möchten, rufen Siee.preventDefault()
auf. Es ist auch empfehlenswert,false
in diesem Handler zurückzugeben.Mit dem Ereignis-Handler
dragenter
wird die Klasseover
an- und ausgeschaltet, nichtdragover
. Wenn Siedragover
verwenden, wird das Ereignis wiederholt ausgelöst, während der Nutzer das gezogene Element über eine Spalte hält, wodurch die CSS-Klasse wiederholt aktiviert und deaktiviert wird. Dadurch muss der Browser viel unnötige Rendering-Arbeit leisten, was sich auf die Nutzerfreundlichkeit auswirken kann. Wir empfehlen dringend, Neuzeichnungen zu minimieren. Wenn Siedragover
verwenden müssen, sollten Sie den Ereignis-Listener drosseln oder entprellen.
Drop abschließen
Fügen Sie zum Verarbeiten des Drop-downs einen Event-Listener für das Ereignis drop
hinzu. Im drop
-Handler musst du das Standardverhalten des Browsers für Drop-Vorgänge verhindern, was in der Regel eine Art nervige Weiterleitung ist. Rufen Sie dazu e.stopPropagation()
auf.
function handleDrop(e) {
e.stopPropagation(); // stops the browser from redirecting.
return false;
}
Registrieren Sie den neuen Handler zusammen mit den anderen Handlern:
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 jetzt ausführen, wird der Artikel nicht an der neuen Position abgelegt. Verwenden Sie dazu das DataTransfer
-Objekt.
Die Property dataTransfer
enthält die Daten, die bei einer Drag-Aktion gesendet wurden. dataTransfer
wird im Ereignis dragstart
festgelegt und im Drop-Ereignis gelesen oder verarbeitet. Wenn Sie e.dataTransfer.setData(mimeType, dataPayload)
aufrufen, können Sie den MIME-Typ und die Datennutzlast des Objekts festlegen.
In diesem Beispiel können Nutzer die Spalten neu anordnen. Dazu müssen Sie zuerst die HTML-Datei 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 Ereignis drop
verarbeiten Sie das Ziehen der Spalte, indem Sie das HTML der Quellspalte auf das HTML der Zielspalte festlegen, in die Sie die Daten abgelegt haben. Außerdem muss geprüft werden, ob der Nutzer die Elemente nicht wieder in die Spalte ablegt, aus der er sie 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 sehen Sie in der folgenden Demo. Dazu benötigen Sie einen Desktop-Browser. Die Drag-and-drop-API wird auf Mobilgeräten nicht unterstützt. Ziehen Sie die Spalte A auf die Spalte B und lassen Sie die Maustaste los. Die Spalten wechseln die Position:
Weitere Eigenschaften für das Ziehen
Das dataTransfer
-Objekt stellt Eigenschaften bereit, um dem Nutzer während des Ziehens visuelles Feedback zu geben und zu steuern, wie jedes Drop-Ziel auf einen bestimmten Datentyp reagiert.
dataTransfer.effectAllowed
Schränkt ein, welche Art von Drag-and-drop-Vorgang der Nutzer auf das Element ausführen kann. Sie wird im Drag-and-drop-Verarbeitungsmodell verwendet, um diedropEffect
während derdragenter
- unddragover
-Ereignisse zu initialisieren. Die Eigenschaft kann die folgenden Werte haben:none
,copy
,copyLink
,copyMove
,link
,linkMove
,move
,all
unduninitialized
.- Mit
dataTransfer.dropEffect
wird das Feedback gesteuert, das der Nutzer während der Ereignissedragenter
unddragover
erhält. Wenn der Nutzer den Mauszeiger auf ein Zielelement bewegt, gibt der Cursor des Browsers an, welche Art von Vorgang ausgeführt wird, z. B. Kopieren oder Verschieben. Der Effekt kann einen der folgenden Werte haben: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 Quell- als auch als Zielelement verwendet. Das kann bei einer Benutzeroberfläche passieren, auf der der Nutzer aufgefordert wird, Elemente neu anzuordnen. In einigen Fällen können das Ziel und die Quelle des Ziehens unterschiedliche Elementtypen sein, z. B. in einer Benutzeroberfläche, in der der Nutzer ein Bild als Hauptbild für ein Produkt auswählen muss, indem er es auf ein Ziel zieht.
Drag-and-drop wird häufig verwendet, um Nutzern das Ziehen von Elementen von ihrem Desktop in eine Anwendung zu ermöglichen. Der Hauptunterschied besteht im drop
-Handler. Anstatt über dataTransfer.getData()
auf die Dateien zuzugreifen, sind die Daten in der Property dataTransfer.files
enthalten:
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 finden Sie unter Benutzerdefiniertes Drag-and-drop.