0Pricing
HTML Academy · درس

قائمة عملية لإعادة الترتيب بالسحب

إنشاء قائمة قابلة لإعادة الترتيب باستخدام Drag and Drop API

قائمة عملية لإعادة الترتيب بالسحب درس مجاني في HTML Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في HTML Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة HTML Academy 4 دروس في المجموع.

نظرة عامة على النمط

لبناء قائمة تدعم إعادة الترتيب بالسحب، اجعل كل عنصر قابلًا للسحب، وخزّن معرّف العنصر المسحوب في dataTransfer عند dragstart، وعند الإسقاط أدرج العنصر المسحوب قبل الهدف أو بعده. يظل DOM والنموذج متزامنين إذا أعدت بناء الترتيب من DOM بعد كل عملية إسقاط.

الترميز

اعرض قائمة مسطّحة يحمل كل عنصر li فيها draggable="true" وdata-id. يضمن إبقاء المعرّفات على العناصر ألّا تحتاج معالجات السحب إلى الاستعلام عن مخزن حالة منفصل لتحديد العناصر — فالعنصر نفسه هو مصدر الحقيقة.

<ul id="list">
  <li draggable="true" data-id="1">Item 1</li>
  <li draggable="true" data-id="2">Item 2</li>
  <li draggable="true" data-id="3">Item 3</li>
</ul>

dragstart يسجّل المصدر

عند dragstart، خزّن معرّف العنصر المسحوب في dataTransfer وأضف الصنف "dragging" لإظهار تغذية راجعة مرئية. يوضّح effectAllowed="move" للمتصفح أن العملية إعادة ترتيب وليست نسخًا، لذلك يعكس المؤشر وdropEffect عملية نقل.

list.addEventListener("dragstart", (e) => {
  const li = e.target.closest("li");
  if (!li) return;
  e.dataTransfer.setData("text/plain", li.dataset.id);
  e.dataTransfer.effectAllowed = "move";
  li.classList.add("dragging");
});

dragover يتيح الإسقاط

استمع إلى القائمة باستخدام تفويض الأحداث، واستدعِ preventDefault، واضبط dropEffect على "move". استخدم e.target.closest("li") للعثور على الصف الذي يحوم فوقه المؤشر، وبذلك يعمل المعالج نفسه مع القائمة بأكملها.

حساب موضع الإدراج

لتحديد ما إذا كان ينبغي أن يستقر العنصر المسحوب فوق الصف الذي يحوم فوقه المؤشر أو تحته، قارن إحداثي Y للمؤشر بالمنتصف الرأسي للصف: const before = (e.clientY - rect.top) < rect.height / 2. تعني before=true الإدراج باستخدام insertBefore، بينما تعني false الإدراج باستخدام insertAfter.

function getInsertBefore(target, clientY) {
  const rect = target.getBoundingClientRect();
  return clientY < rect.top + rect.height / 2;
}

drop يعيد ترتيب DOM

في معالج drop، ابحث عن العنصر المسحوب حسب المعرّف، وعن الصف المستهدف الموجود تحت المؤشر. استدعِ list.insertBefore(dragged, target) أو list.insertBefore(dragged, target.nextSibling) بحسب النصف من الهدف الذي كان المؤشر يحوم فوقه.

dragend ينظّف الأنماط

سواء نجحت عملية الإسقاط أو ضغط المستخدم على Escape، يُطلَق dragend دائمًا على المصدر. استخدمه لإزالة الصنف "dragging" وأي تمييز لأهداف الإسقاط، حتى تعود القائمة إلى حالة السكون.

list.addEventListener("dragend", () => {
  list.querySelectorAll(".dragging, .over").forEach((el) => {
    el.classList.remove("dragging", "over");
  });
});

مؤشر الإسقاط المرئي

اعرض خطًا رفيعًا في الموضع الذي سيستقر فيه العنصر، باستخدام pseudo-element في CSS على الصف الذي يحوم فوقه المؤشر، مع تفعيله بواسطة الصنف "over-top" أو "over-bottom" الذي يضبطه معالج dragover استنادًا إلى موضع المؤشر. يرى المستخدم نقطة الإدراج قبل الإفلات.

مزامنة النموذج

بعد الإسقاط، استنتج الترتيب الجديد من DOM: const order = Array.from(list.children).map((li) => li.dataset.id). أرسل هذه المصفوفة إلى الخادم أو خزّنها في الحالة — ولا تحاول مطلقًا الحفاظ على فهرس موازٍ إلى جانب DOM، إذ ينحرف عن الترتيب الصحيح أثناء عمليات السحب السريعة.

البديل باستخدام لوحة المفاتيح

أضف معالجات Up/Down تنقل العنصر المركّز باستخدام insertBefore. أعلن عن النقل عبر منطقة aria-live ("نُقل العنصر إلى الموضع 2"). يحصل مستخدمو لوحة المفاتيح على الإمكانية نفسها من دون استخدام السحب المرئي، وهذا ضروري لإتاحة الوصول.

بديل ملائم لشاشات اللمس

في الأجهزة المحمولة، استبدل السحب الأصلي بـ Pointer Events: عند pointerdown التقط الصف، وعند pointermove حرّكه باستخدام CSS transform، وعند pointerup حدّد الصف الموجود أسفله وأعد الترتيب. تغلّف مكتبات مثل SortableJS هذا النمط عبر أنواع الإدخال المختلفة.

اختبار المعرفة

لماذا نحسب موضع الإدراج انطلاقًا من موضع المؤشر بالنسبة إلى المنتصف الرأسي للصف الذي يحوم فوقه؟

الخلاصة

تجمع قائمة إعادة الترتيب المتينة بين draggable="true" وdragstart (تسجيل المعرّف وeffectAllowed=move) وdragover (preventDefault وتحديد موضع المؤشر) وdrop (استخدام insertBefore في الموضع المحسوب من المنتصف) وdragend (التنظيف). استنتج الترتيب الجديد دائمًا من DOM بعد الإسقاط، ووفّر بديلًا باستخدام لوحة المفاتيح لضمان إتاحة الوصول.

الأسئلة الشائعة

هل درس «قائمة عملية لإعادة الترتيب بالسحب» مجاني؟

نعم — نص درس «قائمة عملية لإعادة الترتيب بالسحب» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة HTML Academy، انتقل إلى CoddyKit PRO. تتضمن دورة HTML Academy 4 دروس في المجموع.

ماذا ستتعلم في «قائمة عملية لإعادة الترتيب بالسحب»؟

إنشاء قائمة قابلة لإعادة الترتيب باستخدام Drag and Drop API تتمرن على HTML Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ HTML Academy؟

لا تُشترط خبرة سابقة. HTML Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «قائمة عملية لإعادة الترتيب بالسحب»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس HTML Academy هذا؟

نعم. كل درس في HTML Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. السمة draggable وحدث dragstart
  2. حدثا dragover وdrop
  3. الكائن dataTransfer
  4. قائمة عملية لإعادة الترتيب بالسحب
← العودة إلى HTML Academy