HTML5 Drag & Drop API

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 verwendet 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 Sie beachten sollten:

  • Die Standardaktion für das Ereignis dragover besteht darin, die Eigenschaft dataTransfer.dropEffect auf "none" festzulegen. Die Property dropEffect wird weiter unten auf dieser Seite behandelt. Fürs Erste sei nur gesagt, dass dadurch das Ereignis drop verhindert wird. Wenn Sie dieses Verhalten überschreiben möchten, rufen Sie e.preventDefault() auf. Es ist auch empfehlenswert, false in diesem Handler zurückzugeben.

  • Mit dem Ereignis-Handler dragenter wird die Klasse over an- und ausgeschaltet, nicht dragover. Wenn Sie dragover 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 Sie dragover 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 dieselbe 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 sie los. Sie sehen, dass sie die Plätze tauschen:

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. Im Drag-and-drop-Verarbeitungsmodell wird er verwendet, um die dropEffect während der dragenter- und dragover-Ereignisse zu initialisieren. Die Eigenschaft kann die folgenden Werte haben: none, copy, copyLink, copyMove, link, linkMove, move, all und uninitialized.
  • Mit dataTransfer.dropEffect wird das Feedback gesteuert, das der Nutzer während der Ereignisse dragenter und dragover 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 oder 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.

Weitere Ressourcen