API Seret dan Lepas HTML5

Postingan ini menjelaskan dasar-dasar tarik lalu lepas.

Membuat konten yang dapat ditarik

Di sebagian besar browser, pilihan teks, gambar, dan link dapat ditarik secara default. Misalnya, jika Anda menarik link di halaman web, Anda akan melihat kotak kecil dengan judul dan URL yang dapat Anda letakkan di kolom URL atau desktop untuk membuat pintasan atau membuka link tersebut. Untuk membuat jenis konten lain dapat ditarik, Anda harus menggunakan API Tarik lalu Lepas HTML5.

Untuk membuat objek dapat ditarik, tetapkan draggable=true pada elemen tersebut. Hampir semua apa pun dapat diaktifkan untuk ditarik, termasuk gambar, file, link, file, atau markup apa pun di halaman.

Contoh berikut membuat antarmuka untuk mengatur ulang kolom yang telah ditata dengan Petak CSS. Markup dasar untuk kolom akan terlihat seperti ini, dengan atribut draggable untuk setiap kolom ditetapkan ke true:

<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>

Berikut adalah CSS untuk elemen penampung dan kotak. Satu-satunya CSS yang terkait dengan fitur tarik adalah properti cursor: move. Kode lainnya mengontrol tata letak dan gaya visual elemen penampung dan kotak.

.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;
}

Pada tahap ini Anda dapat menarik item, tetapi tidak akan terjadi apa pun. Untuk menambahkan perilaku, Anda harus menggunakan JavaScript API.

Memproses peristiwa tarik

Untuk memantau proses tarik, Anda dapat memproses salah satu peristiwa berikut:

Untuk menangani alur tarik, Anda memerlukan semacam elemen sumber (tempat tarik dimulai), payload data (objek yang ditarik), dan target (area untuk menangkap lepas). Elemen sumber dapat berupa hampir semua jenis elemen. Target adalah zona lepas atau kumpulan zona lepas yang menerima data yang coba dihapus oleh pengguna. Tidak semua elemen dapat menjadi target. Misalnya, target Anda tidak boleh berupa gambar.

Memulai dan mengakhiri urutan tarik

Setelah menentukan atribut draggable="true" pada konten, lampirkan pengendali peristiwa dragstart untuk memulai urutan tarik untuk setiap kolom.

Kode ini menetapkan opasitas kolom menjadi 40% saat pengguna mulai menariknya, lalu mengembalikannya ke 100% saat peristiwa tarik berakhir.

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);
});

Hasilnya dapat dilihat di demo Glitch berikut. Tarik item, dan opasinya akan berubah. Karena elemen sumber memiliki peristiwa dragstart, menetapkan this.style.opacity ke 40% akan memberi pengguna masukan visual bahwa elemen tersebut adalah pilihan saat ini yang dipindahkan. Saat Anda melepas item, elemen sumber akan kembali ke opasitas 100%, meskipun Anda belum menentukan perilaku lepas.

Menambahkan isyarat visual tambahan

Untuk membantu pengguna memahami cara berinteraksi dengan antarmuka Anda, gunakan pengendali peristiwa dragenter, dragover, dan dragleave. Dalam contoh ini, kolom adalah target lepas, selain dapat ditarik. Bantu pengguna untuk memahami hal ini dengan membuat batas putus-putus saat mereka menahan item yang ditarik di atas kolom. Misalnya, di CSS, Anda dapat membuat class over untuk elemen yang merupakan target drop:

.box.over {
  border: 3px dotted #666;
}

Kemudian, di JavaScript, siapkan pengendali peristiwa, tambahkan class over saat kolom ditarik, dan hapus saat elemen yang ditarik keluar. Di pengendali dragend, pastikan kita juga menghapus class di akhir penarikan.

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);
  });
});

Ada beberapa poin yang perlu dibahas dalam kode ini:

  • Tindakan default untuk peristiwa dragover adalah menetapkan properti dataTransfer.dropEffect ke "none". Properti dropEffect akan dibahas nanti di halaman ini. Untuk saat ini, perlu diketahui bahwa tindakan ini mencegah peristiwa drop diaktifkan. Untuk mengganti perilaku ini, panggil e.preventDefault(). Praktik baik lainnya adalah menampilkan false dalam pengendali yang sama.

  • Pengendali peristiwa dragenter digunakan untuk mengalihkan class over, bukan dragover. Jika Anda menggunakan dragover, peristiwa akan diaktifkan berulang kali saat pengguna memegang item yang ditarik di atas kolom, sehingga class CSS akan beralih berulang kali. Hal ini membuat browser melakukan banyak tugas rendering yang tidak perlu, yang dapat memengaruhi pengalaman pengguna. Kami sangat merekomendasikan untuk meminimalkan penggambaran ulang, dan jika Anda perlu menggunakan dragover, pertimbangkan throttling atau deboument pemroses peristiwa.

Menyelesaikan drop

Untuk memproses pelepasan, tambahkan pemroses peristiwa untuk peristiwa drop. Dalam pengendali drop, Anda harus mencegah perilaku default browser terkait penurunan, yang biasanya semacam pengalihan yang mengganggu. Untuk melakukannya, panggil e.stopPropagation().

function handleDrop(e) {
  e.stopPropagation(); // stops the browser from redirecting.
  return false;
}

Pastikan untuk mendaftarkan pengendali baru bersama pengendali lainnya:

  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);
  });

Jika Anda menjalankan kode pada tahap ini, item tidak akan dihapus ke lokasi baru. Untuk mewujudkannya, gunakan objek DataTransfer.

Properti dataTransfer menyimpan data yang dikirim dalam tindakan tarik. dataTransfer ditetapkan dalam peristiwa dragstart dan dibaca atau ditangani dalam peristiwa drop. Dengan memanggil e.dataTransfer.setData(mimeType, dataPayload), Anda dapat menetapkan jenis MIME dan payload data objek.

Dalam contoh ini, kita akan mengizinkan pengguna mengatur ulang urutan kolom. Untuk melakukannya, Anda harus menyimpan HTML elemen sumber terlebih dahulu saat proses menarik dimulai:

function handleDragStart(e) {
  this.style.opacity = '0.4';

  dragSrcEl = this;

  e.dataTransfer.effectAllowed = 'move';
  e.dataTransfer.setData('text/html', this.innerHTML);
}

Dalam peristiwa drop, Anda memproses drop kolom dengan menetapkan HTML kolom sumber ke HTML kolom target tempat Anda meletakkan data. Hal ini termasuk memeriksa apakah pengguna tidak meletakkan kembali ke kolom yang sama dengan kolom yang ditarik.

function handleDrop(e) {
  e.stopPropagation();

  if (dragSrcEl !== this) {
    dragSrcEl.innerHTML = this.innerHTML;
    this.innerHTML = e.dataTransfer.getData('text/html');
  }

  return false;
}

Anda dapat melihat hasilnya di demo berikut. Agar dapat berfungsi, Anda memerlukan browser desktop. API Tarik lalu Lepas tidak didukung di perangkat seluler. Tarik lalu lepaskan kolom A di atas kolom B dan perhatikan bagaimana posisinya berubah:

Properti menarik lainnya

Objek dataTransfer mengekspos properti untuk memberikan masukan visual kepada pengguna selama proses tarik dan mengontrol cara setiap target lepas merespons jenis data tertentu.

  • dataTransfer.effectAllowed membatasi 'jenis tarik' yang dapat dilakukan pengguna pada elemen. Fungsi ini digunakan dalam model pemrosesan tarik lalu lepas untuk melakukan inisialisasi dropEffect selama peristiwa dragenter dan dragover. Properti ini dapat memiliki nilai berikut: none, copy, copyLink, copyMove, link, linkMove, move, all, dan uninitialized.
  • dataTransfer.dropEffect mengontrol masukan yang diterima pengguna selama peristiwa dragenter dan dragover. Saat pengguna mengarahkan kursor ke elemen target, kursor browser akan menunjukkan jenis operasi yang akan terjadi, seperti penyalinan atau pemindahan. Efeknya dapat menggunakan salah satu nilai berikut: none, copy, link, move.
  • e.dataTransfer.setDragImage(imgElement, x, y) berarti bahwa Anda dapat menyetel ikon tarik, bukan menggunakan masukan 'gambar hantu' default browser.

Upload file

Contoh sederhana ini menggunakan kolom sebagai sumber tarik dan target tarik. Hal ini mungkin terjadi di UI yang meminta pengguna untuk mengatur ulang item. Dalam beberapa situasi, target dan sumber tarik mungkin memiliki jenis elemen yang berbeda, seperti pada antarmuka saat pengguna harus memilih satu gambar sebagai gambar utama untuk suatu produk dengan menarik gambar yang dipilih ke target.

Tarik lalu lepas sering digunakan untuk memungkinkan pengguna menarik item dari desktop ke aplikasi. Perbedaan utamanya ada pada pengendali drop Anda. Datanya tidak disimpan dalam properti dataTransfer.getData() untuk mengakses file, tetapi disimpan dalam properti dataTransfer.files:

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.
  }
}

Anda dapat menemukan informasi selengkapnya tentang hal ini di Tarik lalu lepas kustom.

Referensi lainnya