Skip to content

Kılavuz ​

EffDND, yalnızca öznitelikler (attributes) kullanarak HTML'inize sürükle-bırak özelliği ekler. JavaScript çağrısı gerektirmez; tek bir içe aktarma (import) dışında hiçbir kurulum süreci yoktur. Bu kılavuz, EffDND ile neler yapabileceğinizi ve bunları nasıl gerçekleştireceğinizi açıklar.

Başlarken ​

sh
npm i effdnd

Uygulamanızda bir kez içe aktarın:

ts
import 'effdnd';            // the library
import 'effdnd/style.css';  // optional: default styles

İşte bu kadar. Aşağıdaki niteliklerle (attributes) işaretlenmiş her öğe anında sürüklenebilir hale gelir; sayfaya sonradan eklenen öğeler bile buna dahildir.

Framework'ler: Herhangi biriyle uyumludur. Ayrıca bir bileşen sarmalayıcıya (component wrapper) gerek duymaz.

Nasıl çalışır? ​

EffDND, tek bir temel fikir üzerine inşa edilmiştir; bu kılavuzdaki diğer her şey aslında bu fikrin bir uzantısıdır:

  • Sürükleme işlemini yalnızca bir trigger (tetikleyici) başlatır. Hiçbir öğe kendiliğinden sürüklenebilir değildir. data-dnd-trigger ile işaretlenmiş bir tutamağı yakaladığınızda sürükleme başlar; böyle bir tetikleyici yoksa hiçbir şey hareket etmez.
  • Hareket eden asıl öğe itemdır. trigger genellikle itemın içinde yer alır; böylece öğenin tamamı imlecinizi takip eder. Ancak trigger ile itemın aynı düğüm (node) olması zorunlu değildir.
  • scope (kapsam), çalışma alanını (sandbox) temsil eder. Bir item, yalnızca kendi scopeu içinde hareket edebilir ve bırakılabilir. Bu kapsamın dışındaki bırakma alanları veya kapsayıcılar tamamen göz ardı edilir.

İşte temel senaryo budur: bir scope içinde yer alan bir item üzerinde bulunan bir trigger.

html
<div data-dnd-scope="board">              <!-- scope: the sandbox -->
  <div data-dnd-item="a">                 <!-- item: what moves -->
    <span data-dnd-trigger>⠿</span>     <!-- trigger: what you grab -->
      Grab me
  </div>
</div>

Bunu takip eden her bir özellik — yeniden sıralama, aktarma, kaydırma veya aşağıdaki tetikleyici parametreleri — yalnızca bu temel davranışı geliştirir ya da genişletir.

Sürükleme sırasında stillendirme. Hareket ettiğini gördüğünüz öğe, item (öğe) öğesinin bir kopyasıdır (klonudur) ve öğenin kendi üst öğesinin (parent) içine yerleştirilir. Bu, basamaklı (cascaded) ve kalıtım yoluyla aktarılan stillerin; ayrıca üst öğe seçicilerine (ul > li, .zone .card vb.) dayalı kuralların, hareket eden klon üzerinde de geçerli olmaya devam edeceği anlamına gelir; dolayısıyla her bir renk değerini satır içi (inline) stil olarak tanımlamanıza gerek kalmaz. Orijinal öğe listedeki yerinde kalır ve passive (pasif) durumu aracılığıyla görünümü soluklaştırılır (aşağıdaki Stillendirme bölümüne bakın).

Dikkat edilmesi gereken nokta: Dönüştürülmüş (transformed) üst öğeler. Klon, position:fixed özelliğine sahiptir; yani düzenten (layout) bağımsızdır. Ancak öğenin herhangi bir üst öğesinde transform, filter, perspective (veya will-change:transform) özellikleri bulunuyorsa, tarayıcı fixed değerini absolute gibi ele alır. Bu durumda klon, söz konusu üst öğeye göre konumlandırılır ve kaymış görünebilir (ayrıca, dönüştürülmüş ve kaydırılabilir bir kapsayıcı varsa, klon da onunla birlikte kayar). Sürüklenen öğelerin üst öğelerinde dönüştürme (transform) işlemlerinden kaçının ya da data-dnd-state özniteliğini ve öğeye uyguladığınız satır içi (inline) stilleri kullanarak bu fixed kaynaklı görsel durumu geçersiz kılın (override edin).

Özniteliklere kısa bir bakış ​

Öznitelikİşlevi
data-dnd-triggerKullanıcının sürükleme işlemini başlatmak için tuttuğu "tutamacı" (handle) belirtir
data-dnd-itemSürüklenecek öğeyi işaretler
data-dnd-scopeSürükleme ve bırakma hedeflerini tek bir kapsayıcıyla sınırlar
data-dnd-reorderBir kapsayıcıyı sıralanabilir bir listeye (x veya y ekseninde) dönüştürür
data-dnd-targetBir bırakma alanını (drop zone) işaretler
data-dnd-transferBir bırakma alanına append (sonuna ekle), prepend (başına ekle) veya remove (kaldır) gibi bir eylem tanımlar
data-dnd-scrollSürükleme sırasında kapsayıcının otomatik olarak kaydırılmasını sağlar
data-dnd-transitionHareket animasyonunu yumuşatır
data-dnd-disabledBir tetikleyiciyi (trigger) devre dışı bırakır
data-dnd-stateSürükleme sırasında belirlenen çalışma zamanı durumu (active/passive) — stil belirlemek için kullanılır

En temel senaryo için bunlardan yalnızca üçü gereklidir: bir kapsayıcı (scope) içindeki bir öğede (item) bulunan bir tutamaç (trigger). Diğer tüm öğeler isteğe bağlıdır ve işlevsellik ekler.

Tetikleyici (trigger) parametreleri ​

trigger giriş noktası olduğu için, en sık ayarladığınız öznitelik budur. Noktalı virgülle ayrılmış bir parametre listesi kabul eder:

html
<span data-dnd-trigger="dist:12;axis:y;scope:board;item:task-1">⠿</span>

Bir sürükleme mesafesi (dist) gerektirir ​

Tıklama sırasında kazara sürükleme yapılmasını önler; sürükleme işlemi yalnızca işaretçi belirtilen sayıda piksel hareket ettikten sonra başlar:

html
<span data-dnd-trigger="dist:12">⠿</span>   <!-- only drags after the pointer moves 12px -->

Tek bir eksene (axis) kilitle ​

html
<span data-dnd-trigger="axis:x">⠿</span>   <!-- horizontal only -->
<span data-dnd-trigger="axis:y">⠿</span>   <!-- vertical only -->

Belirli bir kapsayıcıyı (scope) hedefleyin ​

EffDND, varsayılan olarak DOM üzerinde arama yaparak en yakın scope öğesini bulur. Belirli bir kapsayıcıya ihtiyaç duyduğunuzda ise ona bir isim verin:

html
<span data-dnd-trigger="scope:board">⠿</span>

Belirli bir öğeyi (item) hedefleyin ​

Tetikleyici, üzerinde bulunan öğelerden hangisinin taşınacağını belirtebilir:

html
<span data-dnd-trigger="scope:board;item:task-1">⠿</span>

Bırakma hedeflerini (target) kısıtlayın ​

Yalnızca data-dnd-target değeri belirtilen isimle başlayan bölgelere bırakma işlemine izin verin:

html
<span data-dnd-trigger="scope:board;target:drop">⠿</span>

Sayfanın tamamında özgürce hareket edin (scope:*) ​

Özel scope:* değeri, her türlü scope sınırını bütünüyle yok sayar:

html
<span data-dnd-trigger="scope:*">⠿</span>

Öğe daha sonra sayfa üzerinde herhangi bir yere sürüklenebilir.

Bir tetikleyiciyi devre dışı bırakma ​

html
<span data-dnd-trigger data-dnd-disabled>⠿</span>

Yeniden etkinleştirmek için özelliği kaldırın.

Tipik senaryolar ​

Bunlar, parçaların gerçek arayüzlerde bir araya gelmesinin yaygın yollarıdır.

Yeniden sıralama: sıralanabilir bir liste ​

Öğelerinizi data-dnd-reorder = "y" ile bir listeye sarın, her öğeyi işaretleyin ve bir tanıtıcı ekleyin.

html
<ul data-dnd-scope="todo" data-dnd-reorder="y">
  <li data-dnd-item="1"><span data-dnd-trigger>⠿</span>Buy milk</li>
  <li data-dnd-item="2"><span data-dnd-trigger>⠿</span>Read a book</li>
</ul>
  • y dikey olarak, x ise yatay olarak sıralar.
  • Yalnızca listenin doğrudan alt öğeleri olan öğeler yeniden düzenlenir.

Aktarım: öğeleri kapsayıcılar arasında taşıma ​

Bir kapsayıcıyı bırakma alanı (drop zone) olarak işaretleyin ve ona bir aktarım eylemi tanımlayın.

html
<div data-dnd-scope="sprint">
  <div class="zone" data-dnd-target="backlog" data-dnd-transfer="append">Backlog</div>
  <div class="zone" data-dnd-target="done" data-dnd-transfer="prepend">Done</div>
</div>
  • append — öğe, alanın sonuna eklenir.
  • prepend — öğe, alanın başına eklenir.
  • remove — öğe silinir (çöp kutusu için idealdir).

Bırakma alanlarının (drop zones) aynı scope (kapsam) içinde yer alması gerekir (veya yukarıda belirtildiği gibi scope:* kullanılabilir).

Birleştirme: çöp kutusu içeren, sıralanabilir bir liste ​

html
<div data-dnd-scope="mailbox">
  <ul data-dnd-reorder="y">
    <li data-dnd-item="1"><span data-dnd-trigger>⠿</span>Invoice</li>
    <li data-dnd-item="2"><span data-dnd-trigger>⠿</span>Newsletter</li>
  </ul>
  <button data-dnd-target="trash" data-dnd-transfer="remove">Delete</button>
</div>

Burada liste kendi kendini sıralar; ayrıca satırlar, düğmenin üzerine bırakılarak kaldırılabilir.

Kanban: sütunlar ve kartlar ​

Sütunları sıralamak için panoya data-dnd-reorder="x" niteliğini ekleyin; her bir sütunun kart alanını ise hem dikey yeniden sıralama bölgesi hem de öğe kabul eden bir alan (transfer alıcısı) haline getirin.

html
<div data-dnd-scope="kanban" data-dnd-reorder="x">          <!-- sorts columns -->
  <div class="col" data-dnd-item="col-1">
    <div class="col-head"><span data-dnd-trigger>⠿</span>Backlog</div>
    <div class="cards" data-dnd-reorder="y"
         data-dnd-target="col-1" data-dnd-transfer="append"> <!-- sorts & accepts cards -->
      <div class="card" data-dnd-item="task-1"><span data-dnd-trigger>⠿</span>Write spec</div>
    </div>
  </div>
  <!-- more columns ... -->
</div>

Sütunların sırasını değiştirmek için bir sütun başlığını sürükleyin; bir kartı sütunlar arasında taşımak için onu sürükleyin.

Yaygın davranışların ayarlanması ​

Uzun bir kapsayıcıyı otomatik kaydırma ​

Kaydırılabilir öğeye data-dnd-scroll niteliğini ekleyin:

html
<div data-dnd-scroll="threshold:50;speed:12">
  • threshold (varsayılan 30) — kaydırmanın başlaması için kenara ne kadar yakın olunması gerektiğini belirtir (piksel cinsinden).
  • speed (varsayılan 10) — kaydırma hızını belirtir (her kare başına düşen piksel cinsinden).

Artık bir kenara yakınken sürükleme işlemi yapıldığında kapsayıcı kaydırılır; kenara yaklaştıkça kaydırma hızı artar.

Animasyonu yumuşatın ​

html
<div data-dnd-transition="150ms ease">…</div>

Varsayılan değer 100ms linear şeklindedir.

JavaScript ile sürükleme işlemlerine tepki verme ​

Bunu hâlâ yapabilirsiniz; EffDND yalnızca bunu isteğe bağlı hâle getirir. Aşağıdaki işlevlerin her biri, aboneliği sonlandıran (unsubscribe) bir işlev döndürür:

ts
import { onDrag, onDrop, onReorder, onTransfer, onDragStart, onDragEnd } from 'effdnd';

onReorder((event) => {
  console.log('Item was reordered:', event.detail.keys.item);
});

Mevcut olaylar: effdragstart, effdrag, effdragend, effdragenter, effdragleave, effdrop, effreorder, efftransfer.

Her olay, üzerinde işlem yapabileceğiniz bir detail nesnesi sunar:

ts
event.detail.keys.item;          // which item
event.detail.keys.scope;         // in which scope
event.detail.keys.target;        // on which target
event.detail.item;

İşinize yarayabilecek yardımcılar ​

ts
import { getItem, getScope, getTargets, getReorderContainer, reset } from 'effdnd';

getItem(trigger);           // the item an element belongs to
getScope(trigger);          // the scope an element belongs to
getTargets(trigger);        // the drop zones available for a trigger
reset(item);                // snap an item back to its original position

data-dnd-state ile Stil Oluşturma ​

Sürükleme işlemi sırasında EffDND, ilgili öğeleri çalışma zamanında bir data-dnd-state özniteliğiyle işaretler. Bu, satır içi (inline) JavaScript koduna ihtiyaç duymadan, aktif sürükleme işlemini biçimlendirmeniz için temiz bir kanca (hook) sağlar. Herhangi bir sürükleme işlemi gerçekleşmediğinde data-dnd-state özniteliği mevcut değildir.

Durum değerleri ​

ÖğeDurumAnlamı
data-dnd-itemactiveHareket eden kopya; şu anda imlecinizi takip eden öğe
data-dnd-itempassiveKopyanın arkasında, olduğu yerde bırakılan ve görünümü soluklaştırılmış orijinal öğe
data-dnd-scopeactiveİmleç, kapsamın (scope) sınırlarının dışında
data-dnd-scopepassiveİmleç, kapsamın (scope) içinde; sürükleme sırasında beklenen durum
data-dnd-targetactiveÜzerinde imlecin bulunduğu, bırakma hedefi (drop zone)
data-dnd-targetpassiveBırakma işlemine hazır, geçerli bir bırakma hedefi (drop zone)

Paketle birlikte gelen index.css dosyası, bu seçicileri temel alan estetik varsayılan stiller içerir; aynı seçicileri kullanarak bu stilleri dilediğiniz gibi değiştirebilirsiniz:

css
/* Defaults from index.css */
[data-dnd-item][data-dnd-state="passive"] { opacity: 0.2; }
[data-dnd-item][data-dnd-state="active"]  { opacity: 0.75; z-index: 1000; }

/* Your own theme */
[data-dnd-item][data-dnd-state="passive"] { opacity: 0.08; }
[data-dnd-item][data-dnd-state="active"]  {
    opacity: 1;
    box-shadow: 0 0 0 2px cornflowerblue;
    border-radius: 8px;
}
[data-dnd-scope][data-dnd-state="active"] { outline: 2px dashed tomato; }
[data-dnd-target][data-dnd-state="active"] { background: rgba(100, 200, 255, 0.2); }

Varsayılan ayarlar index.css dosyasında yer aldığından, bunların yüklenmesi isteğe bağlıdır: Eğer bu içe aktarma (import) işlemini yapmaz ve kendi [data-dnd-state="…"] kurallarınızı yazarsanız, EffDND tamamen bağımlılıklardan arınmış kalır ve görsel kontrol tamamen sizin elinizde olur.

İpucu. Orijinal öğe kaldırılmaz, yalnızca opacity (opaklık) değeri düşürülerek silikleştirilir; böylece liste düzeni korunur ve sürükleme sırasında diğer öğeler yer değiştirmez. Eğer orijinal öğenin tamamen kaybolmasını isterseniz, passive (pasif) durumu için opacity: 0 (veya visibility: hidden) değerini ayarlayabilirsiniz.

Kısa referans ​

Tüm özniteliklerin ve parametrelerinin özet bir listesi.

Öznitelik / parametreDeğerlerVarsayılanAmaç
data-dnd-trigger——Sürükleme işlemini başlatan tutamağı (handle) işaretler
… distsayı—Sürüklemenin başlaması için işaretçinin (pointer) belirtilen piksel kadar hareket etmesini şart koşar
… axisx / yher ikisi (both)Sürükleme hareketini tek bir eksenle sınırlar
… scopeisim / *DOM'daki en yakın öğeBelirli bir kapsayıcıyı kullanır (veya kapsamları yok sayar)
… itemisimDOM'daki en yakın öğeBelirli bir öğenin sürüklenmesini sağlar
… targetisimtümü (all)Bırakma işleminin yalnızca belirli bir isme sahip hedefler üzerinde yapılmasına izin verir
data-dnd-disabled——Bir tetikleyiciyi (trigger) devre dışı bırakır
data-dnd-itembenzersiz isim—Sürüklenecek öğeyi işaretler
data-dnd-scopebenzersiz isim—Sürükleme/bırakma işlemlerini tek bir kapsayıcıyla sınırlar
data-dnd-reorderx / y—Bir kapsayıcıyı sıralanabilir bir listeye dönüştürür
data-dnd-targetisim—Bir bırakma alanını (drop zone) işaretler
data-dnd-transferappend / prepend / remove—Bir alana bırakıldığında gerçekleştirilen eylem
data-dnd-scrolleşik;hız30;10Sürükleme sırasında kapsayıcıyı otomatik olarak kaydırır
data-dnd-transitionsüre ve geçiş türü (easing)100ms linearHareket animasyonunu yumuşatır
data-dnd-stateactive / passive—Çalışma zamanındaki sürükleme durumu; CSS ile biçimlendirilebilir (bkz. Biçimlendirme)

Apache Lisansı 2.0 altında yayınlanmıştır