API Seret dan Lepas HTML5

Postingan ini menjelaskan dasar-dasar tarik lalu lepas.

Membuat konten yang dapat ditarik

Di sebagian besar browser, pemilihan 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. Agar jenis konten lain dapat ditarik, Anda harus menggunakan API Tarik lalu Lepas HTML5.

Untuk membuat objek dapat ditarik, tetapkan draggable=true pada elemen tersebut. Segala hal apa pun dapat diaktifkan dengan tarik, termasuk gambar, file, link, file, atau markup apa pun di halaman Anda.

Contoh berikut membuat antarmuka untuk mengatur ulang kolom yang telah ditempatkan dengan Petak CSS. Markup dasar untuk kolom akan terlihat seperti ini, dengan atribut draggable untuk setiap kolom yang 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 kotak dan penampung.

.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-apa. Untuk menambahkan perilaku, Anda perlu 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 penarikan dimulai), payload data (objek yang ditarik), dan target (area untuk menangkap peristiwa lepas). Elemen sumber dapat berupa hampir semua jenis elemen. Targetnya adalah zona lepas atau kumpulan zona lepas yang menerima data yang coba dilepas 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 Anda, instal pengendali peristiwa dragstart untuk memulai urutan tarik untuk setiap kolom.

Kode ini menetapkan opasitas kolom ke 40% saat pengguna mulai menariknya, lalu mengembalikannya ke 100% saat peristiwa penarikan 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 opasitasnya 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 sedang dipindahkan. Saat Anda melepaskan item, elemen sumber akan kembali ke opasitas 100%, meskipun Anda belum menentukan perilaku operasi 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 operasi lepas, selain dapat ditarik. Bantu pengguna memahami hal ini dengan membuat batas dihapus saat mereka menahan item yang ditarik ke atas kolom. Misalnya, di CSS, Anda dapat membuat class over untuk elemen yang merupakan target operasi lepas:

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

Kemudian, di JavaScript Anda, siapkan pengendali peristiwa, tambahkan class over saat kolom ditarik, dan hapus saat elemen yang ditarik keluar. Di pengendali dragend, kami juga memastikan untuk 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 tersebut 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 menahan item yang ditarik ke atas kolom, yang menyebabkan class CSS beralih berulang kali. Hal ini membuat browser melakukan banyak pekerjaan rendering yang tidak perlu, sehingga dapat memengaruhi pengalaman pengguna. Sebaiknya minimalkan penggambaran ulang, dan jika Anda perlu menggunakan dragover, pertimbangkan throttling atau debouncing pemroses peristiwa.

Selesaikan pelepasan

Untuk memproses peristiwa lepas, tambahkan pemroses peristiwa untuk peristiwa drop. Pada pengendali drop, Anda harus mencegah perilaku default browser untuk penurunan, yang biasanya merupakan 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 turun 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 lepas. Memanggil e.dataTransfer.setData(mimeType, dataPayload) memungkinkan Anda menetapkan jenis MIME dan payload data objek.

Dalam contoh ini, kita akan mengizinkan pengguna mengatur ulang urutan kolom. Untuk melakukannya, pertama-tama Anda harus menyimpan HTML elemen sumber saat penarikan 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 penghapusan kolom dengan menetapkan HTML kolom sumber ke HTML kolom target tempat Anda melepas data. Ini termasuk memeriksa bahwa pengguna tidak kembali ke kolom yang sama dengan tempat menarik pengguna.

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 dalam demo berikut. Agar berhasil, Anda memerlukan browser desktop. API Tarik lalu Lepas tidak didukung di perangkat seluler. Tarik lalu lepaskan kolom A di bagian atas kolom B dan perhatikan bagaimana kolom tersebut mengubah tempat:

Properti tarik 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. Ini digunakan dalam model pemrosesan tarik lalu lepas untuk menginisialisasi dropEffect selama peristiwa dragenter dan dragover. Properti 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. Efek dapat menggunakan salah satu nilai berikut: none, copy, link, move.
  • e.dataTransfer.setDragImage(imgElement, x, y) berarti Anda dapat menyetel ikon tarik untuk tidak menggunakan masukan 'ghost image' 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 dapat memiliki jenis elemen yang berbeda, seperti dalam antarmuka saat pengguna harus memilih satu gambar sebagai gambar utama untuk 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. Datanya terdapat di dalam properti dataTransfer.files, bukan dataTransfer.getData() untuk mengakses file:

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