HTML Drag & Drop
HTML5 drag-and-drop memungkinkan pengguna menyeret elemen di dalam UI aplikasi Anda — misalnya, mengurutkan ulang daftar atau memindahkan item antar kolom. Ini adalah fungsionalitas web standar yang bekerja di Wails tanpa setup khusus.
Membuat Elemen Draggable
Section titled “Membuat Elemen Draggable”Secara default, sebagian besar elemen tidak dapat diseret. Untuk membuat elemen draggable, tambahkan draggable="true":
<div class="item" draggable="true">Drag me</div>Elemen sekarang akan menampilkan preview drag saat pengguna mengklik dan menyeretnya.
Tentukan Zona Drop
Section titled “Tentukan Zona Drop”Elemen tidak menerima drop secara default. Agar elemen menerima drop, Anda perlu membatalkan perilaku default pada dragover:
<div class="drop-zone" id="target">Drop here</div>
<script>const target = document.getElementById('target');
target.addEventListener('dragover', (e) => { e.preventDefault(); // Allow the drop});
target.addEventListener('drop', (e) => { e.preventDefault(); // Handle the drop});</script>Memanggil preventDefault() pada dragover diperlukan — ini menandakan elemen menerima drop. Tanpanya, event drop tidak akan terpicu.
Gaya Hover Drag
Section titled “Gaya Hover Drag”To show users where they can drop, add visual feedback when dragging over a drop zone. The dragenter event fires when something enters the zone, and dragleave fires when it leaves:
.drop-zone { border: 2px dashed #ccc; padding: 40px; transition: all 0.2s ease;}
.drop-zone.drag-over { border-color: #007bff; background-color: rgba(0, 123, 255, 0.1);}const target = document.getElementById('target');
target.addEventListener('dragenter', () => { target.classList.add('drag-over');});
target.addEventListener('dragleave', () => { target.classList.remove('drag-over');});
target.addEventListener('drop', (e) => { e.preventDefault(); target.classList.remove('drag-over'); // Handle the drop});Note: dragleave also fires when entering a child element, which can cause flickering. The complete example below shows how to handle this.
Contoh Lengkap
Section titled “Contoh Lengkap”A task list where items can be dragged between priority columns. This tracks the dragged element in a variable, which is the simplest approach when everything is on the same page:
<div class="tasks"> <div class="item" draggable="true">Fix login bug</div> <div class="item" draggable="true">Update docs</div> <div class="item" draggable="true">Add dark mode</div></div>
<div class="columns"> <div class="drop-zone" data-priority="high"> <h3>High Priority</h3> <ul></ul> </div> <div class="drop-zone" data-priority="low"> <h3>Low Priority</h3> <ul></ul> </div></div>
<script>let draggedItem = null;
// Track which item is being draggeddocument.querySelectorAll('.item').forEach(item => { item.addEventListener('dragstart', () => { draggedItem = item; item.classList.add('dragging'); });
item.addEventListener('dragend', () => { item.classList.remove('dragging'); });});
// Handle drops on each zonedocument.querySelectorAll('.drop-zone').forEach(zone => { zone.addEventListener('dragover', (e) => { e.preventDefault(); });
zone.addEventListener('dragenter', () => { zone.classList.add('drag-over'); });
zone.addEventListener('dragleave', (e) => { // Only remove the class if we're leaving the zone entirely, // not just entering a child element if (!zone.contains(e.relatedTarget)) { zone.classList.remove('drag-over'); } });
zone.addEventListener('drop', (e) => { e.preventDefault(); zone.classList.remove('drag-over');
if (draggedItem) { const li = document.createElement('li'); li.textContent = draggedItem.textContent; zone.querySelector('ul').appendChild(li); draggedItem.remove(); } });});</script>
<style>.item { padding: 12px 16px; background: #f0f0f0; margin: 8px 0; border-radius: 8px; cursor: grab;}
.item.dragging { opacity: 0.5;}
.drop-zone { min-height: 150px; border: 2px dashed #ccc; border-radius: 8px; padding: 15px; transition: all 0.2s ease;}
.drop-zone.drag-over { border-color: #007bff; background: rgba(0, 123, 255, 0.1);}</style>Menggabungkan dengan Drop File
Section titled “Menggabungkan dengan Drop File”If your app uses both HTML drag-and-drop and File Drop, your HTML drop zones will also receive events when users drag files from the operating system. To prevent confusion, filter out file drags in your handlers:
zone.addEventListener('dragenter', (e) => { // Ignore external file drags if (e.dataTransfer?.types.includes('Files')) return;
zone.classList.add('drag-over');});
zone.addEventListener('dragover', (e) => { // Ignore external file drags if (e.dataTransfer?.types.includes('Files')) return;
e.preventDefault();});
zone.addEventListener('drop', (e) => { // Ignore external file drags if (e.dataTransfer?.types.includes('Files')) return;
e.preventDefault(); zone.classList.remove('drag-over'); // Handle the internal drop});The dataTransfer.types array contains 'Files' when the user is dragging files from the OS, but contains types like 'text/plain' for internal HTML drags. This lets you distinguish between the two.
Meneruskan Data dengan dataTransfer
Section titled “Meneruskan Data dengan dataTransfer”The example above tracks the dragged element in a JavaScript variable. This works well when everything is on the same page. But if you need to drag between iframes or pass data that isn’t tied to a DOM element, use the dataTransfer API:
// When drag starts, store dataitem.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', item.id);});
// When dropped, retrieve the datatarget.addEventListener('drop', (e) => { e.preventDefault(); const itemId = e.dataTransfer.getData('text/plain'); const item = document.getElementById(itemId); // Move or copy the item});The data is stored as strings, so you’ll need to serialize objects with JSON.stringify() if needed.
Langkah Selanjutnya
Section titled “Langkah Selanjutnya”- File Drop - Accept files from the operating system
- MDN Drag and Drop API - Full browser API reference