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 menyeret sebuah tautan ke laman web, Anda akan melihat kotak kecil dengan dan URL yang dapat Anda letakkan di kolom URL atau desktop untuk membuat atau membuka tautan tersebut. Untuk membuat jenis konten lain dapat ditarik, Anda menggunakan API Seret dan Lepas HTML5.

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

Contoh berikut membuat antarmuka untuk mengatur ulang kolom yang telah ditata dengan CSS Grid. Markup dasar untuk kolom 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 cursor: move saat ini. Kode lainnya mengontrol tata letak dan gaya visual 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 ini, 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 (dengan elemen dimulai), {i>payload<i} data (hal yang sedang ditarik), dan target (area yang akan menangkap drop-nya). Elemen sumber dapat berupa hampir semua jenis elemen. Tujuan target adalah zona lepas atau kumpulan zona lepas yang menerima data pengguna mencoba menjatuhkannya. Tidak semua elemen dapat menjadi target. Misalnya, target Anda tidak bisa menjadi gambar.

Memulai dan mengakhiri urutan tarik

Setelah menentukan atribut draggable="true" di konten Anda, lampirkan Pengendali peristiwa dragstart untuk memulai urutan tarik bagi setiap kolom.

Kode ini menyetel opasitas kolom menjadi 40% saat pengguna mulai menariknya, lalu mengembalikannya ke 100% saat peristiwa penyeretan 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. Seret item, dan perubahan opasitas. Karena elemen sumber memiliki peristiwa dragstart, setelan this.style.opacity hingga 40% memberikan masukan visual kepada pengguna bahwa elemen tersebut pilihan saat ini sedang dipindahkan. Saat Anda melepaskan item, elemen sumber akan kembali ke opasitas 100%, meskipun Anda belum menentukan perilaku penurunan.

Menambahkan isyarat visual tambahan

Untuk membantu pengguna memahami cara berinteraksi dengan antarmuka Anda, gunakan Pengendali peristiwa dragenter, dragover, dan dragleave. Dalam contoh ini, adalah target lepas, selain dapat ditarik. Membantu pengguna memahami hal ini dengan membuat garis batas putus-putus saat mereka menahan item yang ditarik di atas . 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 menghapusnya ketika elemen yang ditarik keluar. Di beberapa pengendali dragend, pastikan untuk menghapus class di akhir tarik.

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 menggantinya perilakunya, panggil e.preventDefault(). Praktik baik lainnya adalah mengembalikan false di 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 di atas kolom, yang menyebabkan class CSS beralih berulang kali. Hal ini membuat {i>browser<i} melakukan banyak pekerjaan {i>rendering<i} yang tidak perlu, yang dapat mempengaruhi pengalaman pengguna. Kami sangat menyarankan untuk mengurangi menggambar ulang, dan jika Anda perlu menggunakan dragover, sebaiknya melakukan throttling atau debue pemroses peristiwa.

Selesaikan pelepasan

Untuk memproses pelepasan, tambahkan pemroses peristiwa untuk peristiwa drop. Di drop Anda harus mencegah perilaku {i>default<i} browser untuk 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 diturunkan ke lokasi baru. Kepada untuk melakukannya, gunakan DataTransfer .

Properti dataTransfer menyimpan data yang dikirim dalam tindakan tarik. dataTransfer ditetapkan dalam peristiwa dragstart dan dibaca atau ditangani dalam peristiwa lepas. Menelepon e.dataTransfer.setData(mimeType, dataPayload) memungkinkan Anda menyetel MIME objek jenis dan {i>payload<i} data.

Dalam contoh ini, kita akan mengizinkan pengguna mengatur ulang urutan kolom. Untuk melakukannya, pertama-tama Anda harus menyimpan HTML elemen sumber saat metode tarik dimulai:

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

  dragSrcEl = this;

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

Di peristiwa drop, Anda akan memproses penghapusan kolom dengan menetapkan nilai HTML ke HTML kolom target tempat Anda meletakkan data. Ini termasuk memeriksa apakah pengguna tidak kembali ke kolom yang sama dengan 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 berfungsi, Anda memerlukan browser desktop. API Tarik lalu Lepas tidak didukung di perangkat seluler. Seret dan lepaskan kolom A di atas kolom B dan perhatikan bagaimana kolom tersebut mengubah tempat:

Properti tarik lainnya

Objek dataTransfer mengekspos properti untuk memberikan masukan visual ke selama proses {i>drag<i} dan mengendalikan bagaimana setiap target {i>drop <i}merespons terhadap tipe data tertentu.

  • dataTransfer.effectAllowed membatasi 'jenis tarik' dapat dilakukan pengguna pada elemen itu. Sudah 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 didapatkan pengguna selama dragenter dan dragover peristiwa. Saat pengguna mengarahkan kursor ke elemen target, elemen kursor menunjukkan jenis operasi apa yang akan terjadi, seperti penyalinan atau pindah. Efeknya dapat menggunakan salah satu nilai berikut: none, copy, link, move.
  • e.dataTransfer.setDragImage(imgElement, x, y) berarti bahwa alih-alih menggunakan 'gambar hantu' default browser, masukan, Anda dapat mengatur ikon {i>drag<i}.

Upload file

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

{i>Drag and <i}sering digunakan untuk memungkinkan pengguna menarik item dari {i>desktop<i} mereka ke aplikasi. Perbedaan utamanya adalah pada pengendali drop Anda. Daripada menggunakan dataTransfer.getData() untuk mengakses file, datanya dimuat 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 lebih lanjut tentang hal ini di Tarik lalu lepas kustom.

Referensi lainnya