📚معرفی و شروع سریع

Sortable.js یک کتابخانه مستقل برای ایجاد لیست‌های قابل مرتب‌سازی با Drag & Drop است. بدون jQuery، با پشتیبانی از Touch موبایل و سازگار با همه فریم‌ورک‌ها.

<!-- فایل محلی -->
<script src="Sortable.min.js"></script>

// ساده‌ترین استفاده
var el = document.getElementById('myList');
Sortable.create(el, {
  animation:   150,          // انیمیشن ms
  ghostClass:  'ghost-cls', // کلاس placeholder
  chosenClass: 'chosen-cls' // کلاس هنگام کشیدن
});

// یا با new
var sortable = new Sortable(el, { animation: 150 });
⇅ دمو: لیست ساده — آیتم‌ها را بکشید
  • آیتم اول — HTML/CSS
  • آیتم دوم — JavaScript
  • آیتم سوم — React
  • آیتم چهارم — Vue.js
  • آیتم پنجم — Node.js
💡 نکته: متد Sortable.create(el, opts) و new Sortable(el, opts) معادل هم هستند. هر دو یک نمونه Sortable برمی‌گردانند که می‌توانید آن را برای کنترل بعدی ذخیره کنید.

تنظیمات پایه

گزینهپیش‌فرضتوضیح
animation0ms انیمیشن جابجایی (توصیه: ۱۵۰)
handleCSS selector دستگیره drag
ghostClassکلاس placeholder هنگام drag
chosenClassکلاس آیتم انتخاب‌شده
dragClassکلاس عنصر در حال کشیدن
delay0تأخیر ms برای شروع drag
disabledfalseغیرفعال کردن کامل
draggableselector — فقط این آیتم‌ها قابل drag
filterselector — این آیتم‌ها قابل drag نیستند
sorttruefalse = فقط drag بین لیست‌ها، بدون مرتب‌سازی داخلی
forceFallbackfalsetrue = انیمیشن یکنواخت‌تر
swapThreshold1آستانه تعویض (0–1)
var sortable = Sortable.create(listEl, {
  animation:   200,
  handle:      '.handle',    // فقط از دستگیره
  ghostClass:  'ghost-cls',
  chosenClass: 'chosen-cls',
  dragClass:   'drag-cls',
  delay:       100,          // ۱۰۰ms تأخیر (مفید برای موبایل)
  forceFallback: true
});
≡ دمو: با Handle — فقط آیکون ≡ را بکشید
  • مدیریت پروژه
  • طراحی رابط کاربری
  • توسعه فرانت‌اند
  • توسعه بک‌اند
  • تست و کیفیت

🔗گروه‌بندی (group)

با گزینه group می‌توانید چند لیست را به هم متصل کنید تا آیتم‌ها بین آن‌ها جابجا شوند.

// نام گروه مشترک
Sortable.create(document.getElementById('list-a'), {
  group: 'shared', animation: 150
});
Sortable.create(document.getElementById('list-b'), {
  group: 'shared', animation: 150
});

// تنظیمات پیشرفته گروه
Sortable.create(listEl, {
  group: {
    name: 'myGroup',
    pull: true,          // true | false | 'clone'
    put:  true           // true | false | ['groupName']
  }
});
🔗 دمو: drag بین دو لیست

💻 Frontend

  • React.js
  • Vue.js
  • Angular
  • Svelte

⚙️ Backend

  • Node.js
  • Express.js
  • Fastify

📋حالت Clone

با pull: 'clone' آیتم‌ها کپی می‌شوند و نسخه اصلی در لیست منبع باقی می‌ماند.

Sortable.create(sourceList, {
  group: { name: 'clone-g', pull: 'clone', put: false },
  sort: false,     // منبع مرتب نمی‌شود
  animation: 150
});
Sortable.create(targetList, {
  group: { name: 'clone-g', pull: true, put: true },
  animation: 150
});

// سفارشی‌سازی کلون
Sortable.create(sourceList, {
  group: { name: 'g', pull: 'clone' },
  onClone: function(evt) {
    evt.clone.textContent += ' (کپی)';
    evt.clone.style.color = '#e74c3c';
  }
});
📋 دمو: Clone — آیتم اصلی باقی می‌ماند

منبع — کلون می‌شود

  • HTML
  • CSS
  • JavaScript
  • TypeScript

🨀 سبد انتخاب

    🚫Filter و Disabled

    // آیتم‌های .no-drag قابل کشیدن نیستند
    Sortable.create(listEl, {
      animation: 150,
      filter: '.no-drag',
      onFilter: function(evt) {
        // شیک کردن آیتم قفل‌شده
        evt.item.style.transform = 'translateX(-6px)';
        setTimeout(function(){ evt.item.style.transform = ''; }, 150);
      }
    });
    
    // غیرفعال / فعال کردن
    sortable.option('disabled', true);   // غیرفعال
    sortable.option('disabled', false);  // فعال
    
    // draggable — عکس filter
    Sortable.create(listEl, { draggable: '.sortable-item' });
    🔒 دمو: آیتم‌های قفل‌شده قابل drag نیستند
    • وظیفه ۱ — آزاد
    • 🔒 وظیفه ۲ — قفل (filter)
    • وظیفه ۳ — آزاد
    • 🔒 وظیفه ۴ — قفل (filter)
    • وظیفه ۵ — آزاد
    • وظیفه ۶ — آزاد

    📡رویدادها (Callbacks)

    رویدادزمانپارامترهای مهم
    onStartشروع کشیدنitem, from, oldIndex
    onEndپایان کشیدنitem, from, to, oldIndex, newIndex
    onAddآیتمی از لیست دیگر اضافه شدitem, from, to, newIndex
    onRemoveآیتمی به لیست دیگر رفتitem, from, to, oldIndex
    onSortترتیب تغییر کرد (هر نوع)item, from, oldIndex, newIndex
    onUpdateترتیب در همان لیست عوض شدitem, from, oldIndex, newIndex
    onMoveدر حین کشیدن هر framedragged, related
    onCloneآیتم کلون شدitem, clone, from
    onFilterکلیک روی آیتم فیلتر‌شدهitem
    Sortable.create(listEl, {
      animation: 150,
      dataIdAttr: 'data-id',
    
      onStart: function(evt) {
        console.log('شروع — index:', evt.oldIndex);
      },
      onEnd: function(evt) {
        console.log('از', evt.oldIndex, 'به', evt.newIndex);
      },
      onSort: function() {
        var order = sortable.toArray();  // ['id1','id2',...]
        console.log('ترتیب جدید:', order);
      }
    });
    📡 دمو: لاگ زنده رویدادها
    • آیتم A — طراحی
    • آیتم B — توسعه
    • آیتم C — تست
    • آیتم D — استقرار
    • آیتم E — نگهداری
    // آیتم‌ها را جابجا کنید...

    API و متدها

    var sortable = Sortable.create(listEl, { animation: 150, dataIdAttr: 'data-id' });
    
    // toArray — آرایه data-id ها به ترتیب فعلی
    var order = sortable.toArray(); // ['id3','id1','id2']
    
    // sort — مرتب‌سازی برنامه‌نویسی
    sortable.sort(['id1', 'id2', 'id3']);
    
    // option — خواندن / تنظیم گزینه
    sortable.option('animation');          // خواندن
    sortable.option('disabled', true);     // تنظیم
    sortable.option('animation', 300);    // تنظیم
    
    // destroy — حذف کامل
    sortable.destroy();
    
    // Sortable.get — گرفتن instance از element
    var instance = Sortable.get(document.getElementById('myList'));
    ⚡ دمو: کنترل API
    • ۱ وظیفه اول
    • ۲ وظیفه دوم
    • ۳ وظیفه سوم
    • ۴ وظیفه چهارم
    • ۵ وظیفه پنجم
    نتیجه اینجا...

    📋تخته Kanban

    ترکیب group و چند لیست Sortable برای ساختن یک تخته Kanban واقعی مثل Trello:

    // هر ستون = یک Sortable با group مشترک
    ['todo', 'doing', 'done'].forEach(function(col) {
      Sortable.create(document.getElementById('col-' + col), {
        group:       'kanban',
        animation:   200,
        ghostClass:  'ghost-class',
        chosenClass: 'chosen-class',
        onAdd: function(evt) {
          updateColumnCounts(); // آپدیت شمارنده ستون
        }
      });
    });
    📋 دمو: تخته Kanban — کارت‌ها را بین ستون‌ها بکشید
    📆 انجام نشده3
    • 📄 طراحی ماکاپUI
    • 🔧 راه‌اندازی پروژهDEV
    • 📋 مستندنویسی APIDOC
    ▶ در حال انجام2
    • 💻 پیاده‌سازی لاگینDEV
    • 🌐 اتصال به APIDEV
    ✓ انجام شده2
    • 🔍 تحلیل نیازمندی‌هاDONE
    • 🌐 تنظیم سرورDONE

    🔗یکپارچه‌سازی

    React — با useRef و useEffect

    // React
    import { useEffect, useRef } from 'react';
    import Sortable from 'sortablejs';
    
    function SortableList({ items, onReorder }) {
      const listRef = useRef(null);
    
      useEffect(() => {
        const sortable = Sortable.create(listRef.current, {
          animation: 150,
          onEnd: (evt) => {
            onReorder(evt.oldIndex, evt.newIndex);
          }
        });
        return () => sortable.destroy(); // cleanup
      }, []);
    
      return <ul ref={listRef}>
        {items.map(item => <li key={item.id} data-id={item.id}>{item.text}</li>)}
      </ul>;
    }

    Vue 3 — با onMounted

    import { onMounted, onUnmounted, ref } from 'vue';
    import Sortable from 'sortablejs';
    
    setup() {
      const listEl = ref(null);
      let sortable;
    
      onMounted(() => {
        sortable = Sortable.create(listEl.value, { animation: 150 });
      });
      onUnmounted(() => sortable.destroy());
      return { listEl };
    }

    ذخیره ترتیب در سرور

    Sortable.create(listEl, {
      animation: 150,
      dataIdAttr: 'data-id',
      onSort: function() {
        var order = sortable.toArray();
        fetch('/api/save-order', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ order })
        });
      }
    });

    🔥بهترین شیوه‌ها

    موضوعتوصیهدلیل
    انیمیشن animation: 150تجربه بصری بهتر — بالاتر از 300ms سنگین
    data-id روی هر آیتمبرای toArray() و ذخیره ترتیب
    destroy هنگام unmountجلوگیری از memory leak
    handle برای محتوای کلیک‌پذیراز تداخل drag با کلیک جلوگیری می‌کند
    forceFallback برای انیمیشن یکنواختاز CSS transform بهره می‌برد
    ذخیره بی‌درنگ در onMoveاز onEnd یا onSort استفاده کنید
    sort: false برای منبع Cloneآیتم‌های منبع جابجا نمی‌شوند
    delay موبایل delay: 150جلوگیری از تداخل با scroll موبایل
    💡 خلاصه Sortable.js:
    • Sortable.create(el, {animation:150}) — راه‌اندازی
    • group: 'name' — drag بین لیست‌ها
    • pull: 'clone' — کپی به جای جابجایی
    • filter: '.no-drag' — آیتم‌های محروم
    • handle: '.handle' — دستگیره اختصاصی
    • onEnd / onSort — رویداد تغییر
    • sortable.toArray() — ترتیب فعلی
    • sortable.destroy() — پاک‌سازی

    🚀زمین بازی کد (Playground)

    با Sortable.js لیست‌ها را Drag & Drop کن. مرتب‌سازی، جابجایی بین دو لیست و رویدادها را امتحان کن. نسخهٔ ۱.۱۵.۲ آفلاین بارگذاری می‌شود.