HTML5 Sürükle ve Bırak API'sı

Bu yayın, sürükle ve bırak özelliğiyle ilgili temel bilgileri açıklar.

Taşınabilir içerikler oluşturma

Çoğu tarayıcıda metin seçimleri, görseller ve bağlantılar varsayılan olarak sürüklenebilir. Örneğin, bir web sayfasında bir bağlantıyı sürüklerseniz başlığı ve URL'si olan küçük bir kutu görürsünüz. Bu kutuyu kısayol oluşturmak ya da bağlantıya gitmek için adres çubuğuna veya masaüstüne bırakabilirsiniz. Diğer içerik türlerini sürüklenebilir hale getirmek için HTML5 Sürükle ve Bırak API'lerini kullanmanız gerekir.

Bir nesneyi sürüklenebilir hâle getirmek için ilgili öğede draggable=true özelliğini ayarlayın. Resimler, dosyalar, bağlantılar, dosyalar veya sayfanızdaki işaretlemeler dahil neredeyse her şey sürüklenebilir.

Aşağıdaki örnekte, CSS Grid ile yerleştirilmiş sütunları yeniden düzenlemek için bir arayüz oluşturulmaktadır. Her sütunun draggable özelliği true değerine ayarlandığında, sütunlara ilişkin temel işaretleme aşağıdaki gibi görünür:

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

Kapsayıcı ve kutu öğeleri için CSS'yi burada görebilirsiniz. Sürükleme özelliğiyle ilgili tek CSS cursor: move özelliğidir. Kodun geri kalanı, kapsayıcı ve kutu öğelerinin düzenini ve stilini kontrol eder.

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

Bu noktada öğeleri sürükleyebilirsiniz ancak başka hiçbir şey olmaz. Davranış eklemek için JavaScript API'yi kullanmanız gerekir.

Etkinlikleri sürüklemeyi dinleyin

Süreci izlemek için aşağıdaki etkinliklerden herhangi birini dinleyebilirsiniz:

Sürükleme akışını yönetmek için bir tür kaynak öğeye (sürüklemenin başladığı yer), veri yüküne (sürüklenen öğe) ve bir hedefe (düşüşü yakalamak için alan) ihtiyacınız vardır. Kaynak öğe neredeyse her tür öğe olabilir. Hedef, kullanıcının bırakmaya çalıştığı verileri kabul eden bırakma bölgesi veya bırakma bölgesi grubudur. Tüm öğeler hedef olamaz. Örneğin, hedefiniz bir resim olamaz.

Sürükleme sırasını başlatma ve sonlandırma

İçeriğinizde draggable="true" özelliklerini tanımladıktan sonra her sütun için sürükleme sırasını başlatmak üzere bir dragstart etkinlik işleyici ekleyin.

Bu kod, kullanıcı sütunu sürüklemeye başladığında sütunun opaklığını %40'a ayarlar ve sürükleme etkinliği sona erdiğinde opaklığı %100'e döndürür.

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

Sonuç, aşağıdaki Glitch demosunda görülebilir. Bir öğeyi sürüklediğinizde opaklığı değişir. Kaynak öğede dragstart etkinliği bulunduğundan, this.style.opacity değerinin% 40 olarak ayarlanması kullanıcıya bu öğenin taşınmakta olan geçerli seçim olduğuna dair görsel geri bildirim verir. Öğeyi bıraktığınızda, bırakma davranışını henüz tanımlamamış olsanız bile kaynak öğe% 100 opaklığa geri döner.

Ek görsel ipuçları ekleme

Kullanıcının arayüzünüzle nasıl etkileşimde bulunacağını anlamasına yardımcı olmak için dragenter, dragover ve dragleave etkinlik işleyicilerini kullanın. Bu örnekte sütunlar, sürüklenebilmenin yanı sıra bırakma hedefleridir. Sürüklenen bir öğeyi bir sütun üzerinde tutarken kenarlığı kesik çizgi şeklinde göstererek kullanıcının bunu anlamasına yardımcı olun. Örneğin, CSS'nizde bırakma hedefi olan öğeler için bir over sınıfı oluşturabilirsiniz:

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

Ardından JavaScript'inizde etkinlik işleyicileri ayarlayın, sütun sürüklendiğinde over sınıfını ekleyin ve sürüklenen öğe ayrıldığında sınıfı kaldırın. dragend işleyicide, sürüklemenin sonundaki sınıfları da kaldırdığımızdan emin oluruz.

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

Bu kodda ele alınması gereken birkaç nokta vardır:

  • dragover etkinliği için varsayılan işlem, dataTransfer.dropEffect özelliğini "none" olarak ayarlamaktır. dropEffect özelliği bu sayfanın sonraki kısımlarında ele alınmıştır. Şimdilik, drop etkinliğinin tetiklenmesini engellediğini unutmayın. Bu davranışı geçersiz kılmak için e.preventDefault() çağrısı yapın. Aynı işleyicide false döndürmek de iyi bir uygulamadır.

  • dragenter etkinlik işleyicisi, over sınıfını değiştirmek için dragover yerine kullanılır. dragover kullanırsanız kullanıcı sürüklenen öğeyi bir sütun üzerinde tutarken etkinlik tekrar tekrar tetiklenir ve CSS sınıfının sürekli olarak geçiş yapmasına neden olur. Bu, tarayıcının çok fazla gereksiz oluşturma işi yapmasına neden olur ve bu durum, kullanıcı deneyimini etkileyebilir. Yeniden çizimleri en aza indirmenizi önemle tavsiye ederiz. dragover kullanmanız gerekiyorsa etkinlik dinleyicinizi sınırlamayı veya hata ayıklama süresini azaltmayı deneyin.

Lansmanı tamamlayın

Düşüşü işlemek için drop etkinliği için bir etkinlik işleyici ekleyin. drop işleyicide, tarayıcının düşüşlerle ilgili varsayılan davranışını engellemeniz gerekir. Bu genellikle bir tür rahatsız edici yönlendirmedir. Bunun için e.stopPropagation() numaralı telefonu arayın.

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

Yeni işleyiciyi diğer işleyicilerle birlikte kaydettiğinizden emin olun:

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

Bu noktada kodu çalıştırırsanız öğe yeni konuma bırakılmaz. Bunu yapmak için DataTransfer nesnesini kullanın.

dataTransfer özelliği, sürükleme işleminde gönderilen verileri tutar. dataTransfer, dragstart etkinliğinde ayarlanır ve bırakma etkinliğinde okunur veya işlenir. e.dataTransfer.setData(mimeType, dataPayload) çağrısı, nesnenin MIME türünü ve veri yükünü ayarlamanıza olanak tanır.

Bu örnekte, kullanıcıların sütunların sırasını değiştirmesine izin vereceğiz. Bunu yapmak için öncelikle sürükleme başladığında kaynak öğenin HTML'sini depolamanız gerekir:

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

  dragSrcEl = this;

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

drop etkinliğinde, kaynak sütunun HTML'sini, verileri bıraktığınız hedef sütunun HTML'sine ayarlayarak sütun bırakma işlemini gerçekleştirirsiniz. Bu işlem, kullanıcının sürüklediği sütuna geri bırakmadığını kontrol etmeyi de içerir.

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

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

  return false;
}

Sonucu aşağıdaki demoda görebilirsiniz. Bunun işe yaraması için bir masaüstü tarayıcıya ihtiyacınız vardır. Sürükle ve bırak API'si mobil cihazlarda desteklenmez. A sütununu B sütununun üst kısmına sürükleyip bırakın ve bunların yerlerini nasıl değiştirdiğine bakın:

Diğer sürükleme özellikleri

dataTransfer nesnesi, sürükleme işlemi sırasında kullanıcıya görsel geri bildirim sağlamak ve her bırakma hedefinin belirli bir veri türüne nasıl tepki verdiğini kontrol etmek için özellikleri gösterir.

  • dataTransfer.effectAllowed, kullanıcının öğe üzerinde gerçekleştirebileceği "sürükleme türünü" kısıtlar. dragenter ve dragover etkinlikleri sırasında dropEffect öğesini başlatmak için sürükle ve bırak işleme modelinde kullanılır. Mülk şu değerlere sahip olabilir: none, copy, copyLink, copyMove, link, linkMove, move, all ve uninitialized.
  • dataTransfer.dropEffect, kullanıcının dragenter ve dragover etkinlikleri sırasında alacağı geri bildirimleri kontrol eder. Kullanıcı işaretçisini bir hedef öğenin üzerinde tuttuğunda, tarayıcı imleci kopyalama veya taşıma gibi ne tür bir işlemin yapılacağını gösterir. Efekt şu değerlerden birini alabilir: none, copy, link, move.
  • e.dataTransfer.setDragImage(imgElement, x, y), tarayıcının varsayılan "hayalet resim" geri bildirimini kullanmak yerine sürükleme simgesi ayarlayabileceğiniz anlamına gelir.

Dosya yükleme

Bu basit örnekte, bir sütunu hem sürükleme kaynağı hem de sürükleme hedefi olarak kullanılmaktadır. Bu durum, kullanıcıdan öğeleri yeniden düzenlemesini isteyen bir kullanıcı arayüzünde gerçekleşebilir. Bazı durumlarda, sürükleme hedefi ve kaynağı farklı öğe türleri olabilir. Örneğin, kullanıcının bir ürünün ana resmi olarak bir resmi seçip hedefe sürüklemesi gereken bir arayüzde.

Sürükle ve Bırak, kullanıcıların masaüstünden öğeleri bir uygulamaya sürüklemesine olanak tanımak için sıkça kullanılır. Temel fark, drop işleyicinizdedir. Dosyalara erişmek için dataTransfer.getData() yerine dataTransfer.files mülkü kullanılır ve verilerini içerir:

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

Özel sürükle ve bırak bölümünde bu konuyla ilgili daha fazla bilgi bulabilirsiniz.

Diğer kaynaklar