Signatur
Beschreibung
DragEvent ist die Ereignisklasse der HTML-Drag-and-Drop-API. Sie erbt von MouseEvent und damit auch von UIEvent und Event. Deshalb stehen neben der zusätzlichen Eigenschaft dataTransfer auch Koordinaten wie clientX/clientY, Zusatztasten wie shiftKey oder altKey sowie target zur Verfügung.
Der Browser löst beim Ziehen die folgenden Ereignisse aus:
- am gezogenen Element:
dragstart,dragunddragend, - am Ablageziel:
dragenter,dragover,dragleaveunddrop.
Über das DataTransfer-Objekt tauscht man die Daten zwischen Quelle und Ziel aus: Mit setData() legt man sie in dragstart ab, mit getData() liest man sie in drop aus. Dateien aus dem Betriebssystem erreicht man über dataTransfer.files. Damit ein Element überhaupt als Ablageziel gilt, muss man in dragover (und am besten auch in dragenter) event.preventDefault() aufrufen.
Man verwendet DragEvent zum Beispiel für sortierbare Listen, Kanban-Boards, Bereiche zum Hochladen von Dateien oder zum Verschieben von Inhalten zwischen Fenstern und Anwendungen. Ein Element wird ziehbar, wenn es das Attribut draggable="true" hat. Links, Bilder und markierter Text lassen sich schon standardmäßig ziehen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Nur für den Konstruktor new DragEvent(type, options): Name des Ereignisses, z. B. "dragstart" oder "drop". |
|
| $options | DragEventInit | {} | Optionales Objekt mit allen Feldern von MouseEventInit (z. B. bubbles, cancelable, clientX) sowie dataTransfer (DataTransfer | null, Standard null). |
Rückgabewert
DragEvent-Instanz. Die wichtigste zusätzliche Eigenschaft ist dataTransfer (DataTransfer | null, nur lesbar).Beispiele
Einfaches Drag-and-Drop zwischen zwei Elementen
// HTML: <div id="karte" draggable="true">Aufgabe 1</div>
// <div id="spalte">Erledigt</div>
const karte = document.getElementById('karte');
const spalte = document.getElementById('spalte');
karte.addEventListener('dragstart', (event) => {
console.log(event instanceof DragEvent); // true
event.dataTransfer.setData('text/plain', event.target.id);
event.dataTransfer.effectAllowed = 'move';
});
// Ohne preventDefault() ist kein Drop möglich
spalte.addEventListener('dragover', (event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
});
spalte.addEventListener('drop', (event) => {
event.preventDefault();
const id = event.dataTransfer.getData('text/plain');
spalte.appendChild(document.getElementById(id));
console.log(`Verschoben: ${id}`);
});
Dateien per Drag-and-Drop hochladen
const zone = document.querySelector('#upload-zone');
const hervorheben = (an) => zone.classList.toggle('aktiv', an);
zone.addEventListener('dragenter', (e) => { e.preventDefault(); hervorheben(true); });
zone.addEventListener('dragover', (e) => e.preventDefault());
zone.addEventListener('dragleave', (e) => {
// Nur reagieren, wenn die Zone wirklich verlassen wird
if (!zone.contains(e.relatedTarget)) hervorheben(false);
});
zone.addEventListener('drop', async (e) => {
e.preventDefault();
hervorheben(false);
const dateien = [...e.dataTransfer.files];
const formData = new FormData();
dateien.forEach((datei) => formData.append('dateien', datei));
const antwort = await fetch('/api/upload', { method: 'POST', body: formData });
console.log(`${dateien.length} Datei(en) hochgeladen, Status ${antwort.status}`);
});
DragEvent per Konstruktor erzeugen (z. B. für Tests)
const ziel = document.createElement('div');
ziel.addEventListener('drop', (e) => {
console.log(e.type, e.dataTransfer.getData('text/plain'), e.clientX);
});
const dt = new DataTransfer();
dt.setData('text/plain', 'Hallo');
const event = new DragEvent('drop', {
bubbles: true,
cancelable: true,
clientX: 120,
dataTransfer: dt
});
ziel.dispatchEvent(event);
Eigenes Vorschaubild beim Ziehen setzen
const element = document.querySelector('[draggable="true"]');
const vorschau = new Image();
vorschau.src = '/img/drag-icon.png';
element.ondragstart = (event) => {
event.dataTransfer.setDragImage(vorschau, 16, 16);
event.dataTransfer.setData('text/uri-list', location.href);
};
element.ondragend = (event) => {
console.log('Ergebnis:', event.dataTransfer.dropEffect); // 'none' bei Abbruch
};
// Wichtig · Fallstricke
- Ohne
preventDefault()kein Drop: WirdpreventDefault()indragovernicht aufgerufen, löst der Browserdropnie aus. Beim Ablegen von Dateien öffnet er sie dann einfach als neue Seite. - Geschützte Daten:
getData()liefert nur indrop(und indragstart) echte Werte. Indragenter/dragoverbefindet sich der Datenspeicher im geschützten Modus. Dort kann man nurdataTransfer.typesprüfen. dragleaveflackert: Das Ereignis feuert auch beim Wechsel auf Kindelemente. Abhilfe schaffen die Prüfung vonrelatedTarget, ein Zähler oderpointer-events: noneauf den Kindern.- Mobile Geräte: Auf Touch-Geräten wird die HTML-Drag-and-Drop-API erst seit iOS Safari 15 bzw. in neueren Android-Browsern unterstützt und ist dort teils eingeschränkt. Für Touch-Bedienung sind Pointer Events oft die zuverlässigere Wahl.
- Synthetische Ereignisse: Ein per
new DragEvent()erzeugtes Ereignis startet keinen echten Ziehvorgang des Browsers. Es eignet sich nur, um Handler auszulösen, etwa in Tests. - Sicherheit: Abgelegte Inhalte wie
text/htmloder Dateinamen stammen aus fremden Quellen. Man sollte sie nie ungeprüft perinnerHTMLeinfügen, sonst droht XSS. Besser isttextContentoder vorheriges Bereinigen, z. B. mit DOMPurify. - Performance:
dragunddragoverfeuern alle paar Millisekunden. Aufwendige Logik in diesen Handlern sollte man drosseln.