jQuery والتعامل مع DOM

إزالة العناصر

12 دقيقة الدرس 16 من 30

إزالة العناصر

توفر jQuery عدة طرق لإزالة العناصر من DOM. فهم الاختلافات بين هذه الطرق أمر بالغ الأهمية لإدارة هيكل المستند بفعالية ومنع تسرب الذاكرة.

طريقة .remove()

تزيل طريقة .remove() العناصر تمامًا من DOM، بما في ذلك جميع معالجات الأحداث والبيانات:

إزالة عنصر أساسية: // إزالة جميع الفقرات $("p").remove(); // إزالة العناصر ذات الفئة المحددة $(".temporary").remove(); // إزالة مع عامل تصفية محدد $("div").remove(".obsolete"); // إزالة عناصر متعددة $(".ad, .popup, .banner").remove(); // إزالة بناءً على خاصية $("img[data-temporary='true']").remove();
إزالة مشروطة: // إزالة العناصر بناءً على المحتوى $("p").remove(":contains('spam')"); // إزالة العناصر الفارغة $("div").remove(":empty"); // إزالة بالفهرس $("li").eq(3).remove(); // إزالة العنصر الرابع // إزالة الأول والأخير $("ul li").first().remove(); $("ul li").last().remove(); // إزالة كل عنصر آخر $("tr:odd").remove();
مهم: عند استخدام .remove()، تُحذف أيضًا جميع بيانات jQuery ومعالجات الأحداث المرفقة بالعناصر المُزالة. هذا يساعد في منع تسرب الذاكرة ولكن يعني أنه لا يمكنك إعادة إرفاق العناصر بوظائفها الأصلية.

طريقة .detach()

تزيل طريقة .detach() العناصر من DOM لكنها تحافظ على بياناتها ومعالجات الأحداث:

الفصل وإعادة الإرفاق: // فصل العنصر (يحافظ على البيانات والأحداث) let detachedElement = $(".panel").detach(); // تنفيذ العمليات... // ثم إعادة إرفاقه $(".container").append(detachedElement); // فصل مع عامل تصفية let hiddenItems = $("li").detach(".hidden"); // لاحقًا، استعدها $("#list").append(hiddenItems);
حالة استخدام عملية - مربع حوار نموذجي: let modal = null; // إظهار النافذة المنبثقة function showModal() { if (!modal) { modal = $("#modal-template").clone(); } else { // إعادة إرفاق النافذة المفصولة سابقًا $("body").append(modal); } modal.fadeIn(); } // إخفاء النافذة المنبثقة (فصل بدلاً من إزالة) function hideModal() { modal.fadeOut(300, function() { modal = $(this).detach(); // يحافظ على معالجات الأحداث }); }
استخدم .detach() عندما: تخطط لإعادة إدراج العنصر لاحقًا وتريد الاحتفاظ بمعالجات الأحداث والبيانات سليمة. هذا أكثر كفاءة من إزالة العناصر وإعادة إنشائها.

طريقة .empty()

تزيل طريقة .empty() جميع العناصر الفرعية والمحتوى النصي من العناصر المحددة:

إفراغ محتويات الحاوية: // إزالة جميع أطفال الحاوية $(".container").empty(); // مسح عناصر القائمة $("#task-list").empty(); // مسح محتوى الجدول $("table tbody").empty(); // مسح وإعادة البناء $("#results").empty().append("<p>لم يتم العثور على نتائج</p>");
مثال عملي - تحديث المحتوى الديناميكي: function updateProductList(products) { let container = $("#product-list"); // مسح المنتجات الموجودة container.empty(); if (products.length === 0) { container.append("<p class='no-products'>لا توجد منتجات متاحة</p>"); return; } // إضافة منتجات جديدة products.forEach(function(product) { let productCard = $("<div>", { class: "product-card", html: "<h3>" + product.name + "</h3>" + "<p>" + product.price + " ريال</p>" + "<button class='add-to-cart'>أضف للسلة</button>" }); container.append(productCard); }); }

المقارنة: remove() مقابل detach() مقابل empty()

فهم الاختلافات: // .remove() - يزيل العنصر وجميع بياناته/أحداثه let removed = $(".item").remove(); // لا يمكن إعادة الاستخدام مع الأحداث سليمة // .detach() - يزيل العنصر لكن يحافظ على البيانات/الأحداث let detached = $(".item").detach(); // يمكن إعادة الإرفاق لاحقًا مع عمل الأحداث // .empty() - يزيل الأطفال لكن يحافظ على العنصر نفسه $(".container").empty(); // الحاوية لا تزال موجودة، فقط الأطفال تمت إزالتهم // مثال للمقارنة let box = $("#box"); box.remove(); // يزيل #box من DOM تمامًا box.detach(); // يزيل #box لكن يمكنك إعادة إرفاقه box.empty(); // #box يبقى، لكن محتوياته تختفي

مثال عملي: مدير مهام مع حذف

HTML: <div class="task-manager"> <input type="text" id="taskInput" placeholder="أدخل مهمة"> <button id="addTask">إضافة مهمة</button> <ul id="taskList"></ul> <div class="trash"> <h4>سلة المهملات</h4> <ul id="trashList"></ul> <button id="emptyTrash">إفراغ السلة</button> </div> </div>
jQuery: $(document).ready(function() { // إضافة مهمة $("#addTask").click(function() { let taskText = $("#taskInput").val().trim(); if (taskText) { let task = createTask(taskText); $("#taskList").append(task); $("#taskInput").val(""); } }); // إنشاء عنصر مهمة function createTask(text) { return $("<li>", { class: "task-item", html: "<span class='task-text'>" + text + "</span>" + "<button class='delete-btn'>حذف</button>" + "<button class='restore-btn' style='display:none'>استعادة</button>" }); } // حذف مهمة (نقل إلى السلة باستخدام detach) $("#taskList").on("click", ".delete-btn", function() { let task = $(this).parent(); // الفصل يحافظ على معالجات النقر let detachedTask = task.detach(); // إخفاء زر الحذف، إظهار زر الاستعادة detachedTask.find(".delete-btn").hide(); detachedTask.find(".restore-btn").show(); // إضافة إلى السلة $("#trashList").append(detachedTask); }); // استعادة مهمة من السلة $("#trashList").on("click", ".restore-btn", function() { let task = $(this).parent(); // فصل من السلة let restoredTask = task.detach(); // إظهار زر الحذف، إخفاء زر الاستعادة restoredTask.find(".delete-btn").show(); restoredTask.find(".restore-btn").hide(); // إعادة إلى قائمة المهام $("#taskList").append(restoredTask); }); // إفراغ السلة (إزالة دائمة) $("#emptyTrash").click(function() { if (confirm("حذف جميع المهام في السلة نهائيًا؟")) { $("#trashList").empty(); // يزيل جميع الأطفال } }); });

تقنيات إزالة متقدمة

إزالة متحركة: // تلاشي ثم إزالة $(".notification").fadeOut(500, function() { $(this).remove(); }); // انزلاق لأعلى ثم إزالة $(".panel").slideUp(300, function() { $(this).remove(); }); // رسوم متحركة مخصصة ثم إزالة $(".card").animate({ opacity: 0, height: 0, padding: 0, margin: 0 }, 400, function() { $(this).remove(); }); // إزالة مع تأخير setTimeout(function() { $(".temporary-message").remove(); }, 5000);
إزالة مجمعة مع تأكيد: // إزالة العناصر المحددة function removeSelected() { let selected = $(".item.selected"); let count = selected.length; if (count === 0) { alert("لم يتم تحديد عناصر"); return; } if (confirm("حذف " + count + " عنصر؟")) { selected.fadeOut(300, function() { $(this).remove(); updateCount(); }); } } // إزالة التكرارات function removeDuplicates() { let seen = {}; $(".item").each(function() { let text = $(this).text().trim(); if (seen[text]) { $(this).remove(); } else { seen[text] = true; } }); }

إدارة الذاكرة

منع تسرب الذاكرة: // سيئ: احتمال تسرب الذاكرة $(".dynamic-content").html("<div>محتوى جديد</div>"); // المحتوى القديم تمت إزالته لكن الأحداث قد تبقى // جيد: التنظيف قبل الاستبدال $(".dynamic-content").empty().html("<div>محتوى جديد</div>"); // أفضل: إزالة صريحة باستخدام .remove() $(".dynamic-content").children().remove(); $(".dynamic-content").html("<div>محتوى جديد</div>"); // أفضل ممارسة للتطبيقات الكبيرة function safeReplace(container, newContent) { $(container).children().each(function() { // إزالة البيانات والأحداث $(this).removeData(); $(this).off(); }).remove(); $(container).append(newContent); }
تحذير من تسرب الذاكرة: قم دائمًا بتنظيف مستمعي الأحداث والبيانات قبل إزالة العناصر في التطبيقات الكبيرة. استخدم Chrome DevTools Memory Profiler للكشف عن التسريبات.

مثال عملي: معرض صور مع حذف

تطبيق كامل: $(document).ready(function() { let deletedImages = []; // تخزين للتراجع // حذف صورة $(".gallery").on("click", ".delete-img", function(e) { e.preventDefault(); let imageCard = $(this).closest(".image-card"); // تخزين للتراجع المحتمل deletedImages.push({ element: imageCard.detach(), position: imageCard.index() }); // إظهار إشعار التراجع showUndoNotification(); // حذف نهائي بعد 10 ثوان setTimeout(function() { if (deletedImages.length > 0) { deletedImages.shift().element.remove(); } }, 10000); }); // التراجع عن الحذف function showUndoNotification() { let notification = $("<div>", { class: "notification", html: "تم حذف الصورة. <button id='undo-delete'>تراجع</button>" }); $("body").append(notification); setTimeout(function() { notification.fadeOut(300, function() { $(this).remove(); }); }, 10000); } // وظيفة التراجع $(document).on("click", "#undo-delete", function() { if (deletedImages.length > 0) { let deleted = deletedImages.pop(); let gallery = $(".gallery"); let children = gallery.children(); if (deleted.position >= children.length) { gallery.append(deleted.element); } else { deleted.element.insertBefore(children.eq(deleted.position)); } $(".notification").remove(); } }); // مسح جميع الصور $("#clearGallery").click(function() { if (confirm("حذف جميع الصور؟")) { $(".gallery").empty(); deletedImages = []; } }); });
تمرين: أنشئ نظام سلة تسوق يتضمن:
  • إزالة عناصر فردية من السلة
  • نقل العناصر إلى "الحفظ لوقت لاحق" (باستخدام detach)
  • نقل العناصر مرة أخرى إلى السلة
  • مسح السلة بالكامل مع تأكيد
  • إفراغ قسم "العناصر المحفوظة"
  • التراجع عن الإزالة خلال 5 ثوان

إضافي: أضف رسوم متحركة عند إزالة العناصر أو نقلها، وعرض تحديثات عدد العناصر.

أفضل الممارسات

  • استخدم .remove() للحذف الدائم
  • استخدم .detach() عندما تحتاج إلى إعادة إدراج العناصر لاحقًا
  • استخدم .empty() لمسح محتويات الحاوية
  • قم دائمًا بتحريك الإزالة للحصول على تجربة مستخدم أفضل
  • أكد قبل عمليات الحذف الجماعية
  • نظف معالجات الأحداث لمنع تسرب الذاكرة
  • نفذ وظيفة التراجع لعمليات الحذف المهمة
  • حدّث العدادات بعد عمليات الإزالة

الملخص

في هذا الدرس، تعلمت كيفية إزالة العناصر من DOM:

  • استخدام .remove() للحذف الدائم للعناصر
  • استخدام .detach() للحفاظ على البيانات والأحداث
  • استخدام .empty() لمسح محتويات الحاوية
  • فهم الاختلافات بين طرق الإزالة
  • تنفيذ عمليات الحذف المتحركة والمؤكدة
  • إدارة الذاكرة ومنع التسريبات
  • بناء وظيفة التراجع

بعد ذلك، سنستكشف استنساخ العناصر لتكرار هياكل DOM بكفاءة.