فهم تصفية والبحث عن العناصر
بعد تحديد العناصر باستخدام jQuery، غالبًا ما تحتاج إلى تضييق أو تحسين اختيارك. تسمح لك طرق التصفية بتقليل مجموعة العناصر المطابقة بناءً على معايير محددة، بينما تساعدك طرق البحث في العثور على عناصر محددة داخل اختيارك.
هذه الطرق ضرورية لبناء واجهات ديناميكية وتفاعلية حيث تحتاج إلى تحكم دقيق في العناصر المتأثرة بالكود الخاص بك.
لماذا التصفية والبحث؟
- الدقة: استهداف العناصر التي تحتاجها بالضبط
- الأداء: العمل مع مجموعات أصغر من العناصر
- المنطق الشرطي: تطبيق سلوكيات مختلفة بناءً على خصائص العنصر
- الاختيار الديناميكي: التكيف مع محتوى الصفحة المتغير
ملاحظة: طرق التصفية تقلل من الاختيار الحالي، بينما طرق البحث تجد عناصر جديدة داخل الاختيار الحالي. فهم هذا الفرق هو مفتاح إتقان التنقل في jQuery.
طريقة filter()
تقلل طريقة filter() مجموعة العناصر المطابقة إلى تلك التي تطابق محددًا أو تجتاز اختبار دالة.
HTML:
<ul class="products">
<li class="product" data-price="50">منتج أ</li>
<li class="product" data-price="150">منتج ب</li>
<li class="product sale" data-price="75">منتج ج</li>
<li class="product" data-price="200">منتج د</li>
</ul>
jQuery - تصفية بمحدد:
// الحصول فقط على المنتجات المخفضة
$(".product").filter(".sale");
// الحصول على المنتجات بسمة معينة
$(".product").filter("[data-price]");
jQuery - تصفية بدالة:
// الحصول على المنتجات تحت $100
$(".product").filter(function() {
return $(this).data("price") < 100;
});
// الحصول على المنتجات بأسماء طويلة
$(".product").filter(function() {
return $(this).text().length > 10;
});
// تطبيق خصم على المنتجات المصفاة
$(".product").filter(function() {
return $(this).data("price") > 100;
}).addClass("premium");
نصيحة: عند استخدام دالة مع filter()، أرجع true للاحتفاظ بالعنصر في الاختيار، أو false لإزالته.
طريقة not()
طريقة not() هي عكس filter() - إنها تزيل العناصر من المجموعة المطابقة التي تطابق محددًا أو دالة.
HTML:
<div class="menu">
<a href="#" class="link active">الرئيسية</a>
<a href="#" class="link">المنتجات</a>
<a href="#" class="link">من نحن</a>
<a href="#" class="link disabled">اتصل بنا</a>
</div>
jQuery - not بمحدد:
// الحصول على جميع الروابط باستثناء النشط
$(".link").not(".active");
// الحصول على جميع الروابط باستثناء المعطل
$(".link").not(".disabled");
// الحصول على الكل باستثناء الأول والأخير
$(".link").not(":first, :last");
jQuery - not بدالة:
// الحصول على جميع الروابط غير الفارغة
$(".link").not(function() {
return $(this).text().trim() === "";
});
// إزالة تأثير التمرير من الكل باستثناء النشط
$(".link").not(".active").removeClass("hover");
طريقة has()
تصفي طريقة has() العناصر التي تحتوي على عنصر واحد على الأقل يطابق محددًا. إنها مثالية لتصفية الأب-الطفل.
HTML:
<div class="cards">
<div class="card">
<h3>بطاقة 1</h3>
<img src="image1.jpg">
</div>
<div class="card">
<h3>بطاقة 2</h3>
<p>لا صورة هنا</p>
</div>
<div class="card">
<h3>بطاقة 3</h3>
<img src="image3.jpg">
</div>
</div>
jQuery:
// الحصول فقط على البطاقات التي تحتوي على صور
$(".card").has("img");
// إضافة حد للبطاقات التي تحتوي على صور
$(".card").has("img").css("border", "2px solid blue");
// الحصول على عناصر القائمة التي تحتوي على روابط
$("li").has("a").addClass("has-link");
// الحصول على الأقسام التي تحتوي على نماذج
$("section").has("form").addClass("interactive");
نصيحة: has() أكثر كفاءة من استخدام filter() مع find() عندما تحتاج فقط إلى التحقق من وجود عناصر تابعة.
طريقة is()
تتحقق طريقة is() مما إذا كان عنصر واحد على الأقل في المجموعة يطابق محددًا. تُرجع true أو false، وليس كائن jQuery.
HTML:
<div class="container">
<input type="checkbox" class="agree" checked>
<button class="submit">إرسال</button>
</div>
jQuery:
// التحقق مما إذا كان مربع الاختيار محددًا
if ($(".agree").is(":checked")) {
console.log("وافق المستخدم على الشروط");
}
// التحقق مما إذا كان العنصر مرئيًا
if ($(".modal").is(":visible")) {
$(".modal").hide();
}
// التحقق مما إذا كان العنصر يحتوي على فئة
if ($(".submit").is(".disabled")) {
console.log("الزر معطل");
}
// التحقق من شروط متعددة
if ($(".element").is(":visible, :animated")) {
console.log("العنصر مرئي أو متحرك");
}
// استخدام عملي في معالج الأحداث
$(".submit").on("click", function() {
if ($(this).is(".disabled")) {
return false; // لا ترسل
}
// إرسال النموذج
});
مهم: is() تُرجع قيمة منطقية (true/false)، وليس كائن jQuery. لا يمكنك تسلسل طرق jQuery أخرى بعد is().
طريقة eq()
تقلل طريقة eq() المجموعة المطابقة إلى العنصر في فهرس معين. الفهارس تبدأ من الصفر.
HTML:
<ul class="list">
<li>عنصر 1</li>
<li>عنصر 2</li>
<li>عنصر 3</li>
<li>عنصر 4</li>
</ul>
jQuery:
// الحصول على العنصر الأول (فهرس 0)
$("li").eq(0);
// الحصول على العنصر الثالث (فهرس 2)
$("li").eq(2);
// الحصول على العنصر الأخير (فهرس سالب)
$("li").eq(-1);
// الحصول على العنصر قبل الأخير
$("li").eq(-2);
// تمييز العنصر الثالث
$("li").eq(2).addClass("highlight");
// إزالة العنصر الثاني
$("li").eq(1).remove();
طرق first() و last()
اختصارات للحصول على العنصر الأول أو الأخير في مجموعة مطابقة.
HTML:
<div class="gallery">
<img src="photo1.jpg">
<img src="photo2.jpg">
<img src="photo3.jpg">
</div>
jQuery:
// الحصول على الصورة الأولى (نفس eq(0))
$("img").first();
// الحصول على الصورة الأخيرة (نفس eq(-1))
$("img").last();
// إضافة حد إلى الأول والأخير
$("img").first().css("border-left", "3px solid red");
$("img").last().css("border-right", "3px solid red");
// إزالة العنصر الأول من القائمة
$(".list li").first().remove();
طريقة slice()
تقلل طريقة slice() المجموعة إلى مجموعة فرعية محددة بنطاق من الفهارس.
HTML:
<ul class="items">
<li>عنصر 1</li>
<li>عنصر 2</li>
<li>عنصر 3</li>
<li>عنصر 4</li>
<li>عنصر 5</li>
</ul>
jQuery:
// الحصول على العناصر 2، 3، و 4 (فهارس 1، 2، 3)
$("li").slice(1, 4);
// الحصول على جميع العناصر من الفهرس 2 فصاعدًا
$("li").slice(2);
// الحصول على العناصر من النهاية
$("li").slice(-3); // آخر 3 عناصر
// إخفاء العناصر الوسطى
$("li").slice(1, -1).hide();
// تنسيق نطاق من العناصر
$("li").slice(1, 3).css("background", "yellow");
طريقة each()
تتكرر طريقة each() على كل عنصر في المجموعة المطابقة، وتنفذ دالة لكل واحد.
HTML:
<div class="products">
<div class="product" data-id="101">منتج أ</div>
<div class="product" data-id="102">منتج ب</div>
<div class="product" data-id="103">منتج ج</div>
</div>
jQuery:
// تسجيل كل معرف منتج
$(".product").each(function(index, element) {
console.log("الفهرس: " + index);
console.log("المعرف: " + $(element).data("id"));
});
// إضافة رقم الفهرس إلى كل عنصر
$(".product").each(function(index) {
$(this).prepend("<span>" + (index + 1) + ". </span>");
});
// نمط مختلف للعناصر الزوجية/الفردية
$(".product").each(function(index) {
if (index % 2 === 0) {
$(this).addClass("even");
} else {
$(this).addClass("odd");
}
});
// إيقاف التكرار مبكرًا
$(".product").each(function(index) {
if ($(this).data("id") === 102) {
return false; // توقف عن التكرار
}
console.log("معالجة: " + $(this).text());
});
نصيحة: داخل each()، this يشير إلى عنصر DOM الخام. استخدم $(this) لتحويله إلى كائن jQuery والوصول إلى طرق jQuery.
طريقة map()
تمرر طريقة map() كل عنصر عبر دالة وتُرجع كائن jQuery جديد يحتوي على القيم المُرجعة.
HTML:
<ul class="fruits">
<li data-price="2.50">تفاح</li>
<li data-price="1.75">موز</li>
<li data-price="3.00">برتقال</li>
</ul>
jQuery:
// الحصول على مصفوفة من جميع الأسعار
var prices = $("li").map(function() {
return $(this).data("price");
}).get(); // [2.50, 1.75, 3.00]
// الحصول على مصفوفة من جميع أسماء الفواكه
var names = $("li").map(function() {
return $(this).text();
}).get();
// حساب السعر الإجمالي
var total = $("li").map(function() {
return $(this).data("price");
}).get().reduce((sum, price) => sum + price, 0);
console.log("الإجمالي: $" + total); // الإجمالي: $7.25
مثال عملي: تصفية منتجات متقدمة
HTML:
<div class="shop">
<div class="filters">
<select id="category-filter">
<option value="all">جميع الفئات</option>
<option value="electronics">إلكترونيات</option>
<option value="clothing">ملابس</option>
</select>
<input type="number" id="max-price" placeholder="السعر الأقصى">
<input type="checkbox" id="sale-only"> تخفيضات فقط
</div>
<div class="products">
<div class="product" data-category="electronics" data-price="999">
<h3>لابتوب</h3>
<p class="price">$999</p>
</div>
<div class="product sale" data-category="clothing" data-price="49">
<h3>سترة</h3>
<p class="price">$49</p>
</div>
<div class="product" data-category="electronics" data-price="699">
<h3>هاتف</h3>
<p class="price">$699</p>
</div>
</div>
</div>
jQuery:
function filterProducts() {
var category = $("#category-filter").val();
var maxPrice = parseFloat($("#max-price").val()) || Infinity;
var saleOnly = $("#sale-only").is(":checked");
// ابدأ بجميع المنتجات
var $products = $(".product");
// تصفية حسب الفئة
if (category !== "all") {
$products = $products.filter("[data-category='" + category + "']");
}
// تصفية حسب السعر
$products = $products.filter(function() {
return $(this).data("price") <= maxPrice;
});
// تصفية حسب التخفيضات
if (saleOnly) {
$products = $products.filter(".sale");
}
// إظهار المنتجات المصفاة، إخفاء الآخرين
$(".product").not($products).fadeOut();
$products.fadeIn();
// إظهار العدد
console.log("عرض " + $products.length + " منتجات");
}
// إرفاق التصفية بالمدخلات
$("#category-filter, #max-price, #sale-only").on("change", filterProducts);
مثال عملي: تصفية صفوف الجدول
HTML:
<input type="text" id="search" placeholder="بحث في الجدول...">
<table class="data-table">
<tr><td>أحمد محمد</td><td>مطور</td><td>$80,000</td></tr>
<tr><td>فاطمة علي</td><td>مصممة</td><td>$75,000</td></tr>
<tr><td>خالد حسن</td><td>مدير</td><td>$90,000</td></tr>
</table>
jQuery:
$("#search").on("keyup", function() {
var searchTerm = $(this).val().toLowerCase();
$(".data-table tr").filter(function() {
var rowText = $(this).text().toLowerCase();
return rowText.indexOf(searchTerm) === -1;
}).hide();
$(".data-table tr").filter(function() {
var rowText = $(this).text().toLowerCase();
return rowText.indexOf(searchTerm) !== -1;
}).show();
});
مثال عملي: التحقق من صحة النموذج
HTML:
<form class="registration">
<input type="text" name="username" required>
<input type="email" name="email" required>
<input type="password" name="password" required>
<input type="text" name="phone">
<button type="submit">تسجيل</button>
</form>
jQuery:
$(".registration").on("submit", function(e) {
// الحصول على جميع الحقول المطلوبة
var $required = $(this).find("input[required]");
// تصفية الحقول الفارغة
var $empty = $required.filter(function() {
return $(this).val().trim() === "";
});
if ($empty.length > 0) {
e.preventDefault();
$empty.addClass("error");
alert($empty.length + " حقول مطلوبة فارغة");
}
// التحقق من صحة تنسيق البريد الإلكتروني
var $email = $(this).find("input[type='email']");
if (!$email.filter(function() {
var email = $(this).val();
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}).length) {
e.preventDefault();
$email.addClass("error");
alert("تنسيق البريد الإلكتروني غير صحيح");
}
});
// إزالة الخطأ عند الإدخال
$(".registration input").on("input", function() {
$(this).removeClass("error");
});
جدول المقارنة
| الطريقة |
تُرجع |
حالة الاستخدام |
filter() |
كائن jQuery (مخفض) |
الاحتفاظ بعناصر مطابقة للمعايير |
not() |
كائن jQuery (مخفض) |
إزالة عناصر مطابقة للمعايير |
has() |
كائن jQuery (مخفض) |
الاحتفاظ بعناصر تحتوي على أحفاد |
is() |
منطقي (true/false) |
التحقق مما إذا كانت العناصر تطابق محددًا |
eq() |
كائن jQuery (عنصر واحد) |
الحصول على عنصر في فهرس معين |
first() / last() |
كائن jQuery (عنصر واحد) |
الحصول على العنصر الأول أو الأخير |
slice() |
كائن jQuery (نطاق) |
الحصول على مجموعة فرعية بنطاق فهرس |
each() |
كائن jQuery (الأصلي) |
التكرار وتنفيذ الإجراءات |
map() |
كائن jQuery (محول) |
تحويل العناصر إلى قيم جديدة |
تمرين عملي
السيناريو: إنشاء دليل موظفين مع قدرات تصفية متقدمة.
بنية HTML:
<div class="directory">
<div class="controls">
<input type="text" id="name-search" placeholder="البحث بالاسم">
<select id="department-filter">
<option value="all">جميع الأقسام</option>
<option value="engineering">الهندسة</option>
<option value="design">التصميم</option>
<option value="marketing">التسويق</option>
</select>
<input type="number" id="min-salary" placeholder="الحد الأدنى للراتب">
</div>
<div class="employees">
<div class="employee" data-dept="engineering" data-salary="85000">
<h3>أحمد محمد</h3>
<p>مطور أول</p>
</div>
<div class="employee" data-dept="design" data-salary="70000">
<h3>فاطمة علي</h3>
<p>مصممة UI</p>
</div>
<div class="employee" data-dept="engineering" data-salary="95000">
<h3>خالد حسن</h3>
<p>قائد تقني</p>
</div>
</div>
</div>
مهامك:
- تصفية الموظفين حسب الاسم (باستخدام
filter() ومطابقة النص)
- تصفية حسب القسم (باستخدام
filter() مع سمة البيانات)
- تصفية حسب الحد الأدنى للراتب (باستخدام
filter() مع دالة)
- دمج جميع التصفيات الثلاثة معًا
- عرض عدد الموظفين المرئيين
- إضافي: استخدم
map() لحساب متوسط راتب الموظفين المرئيين
- إضافي: ميز الموظف الأول والأخير المرئي بشكل مختلف
- إضافي: أضف رسالة "لا توجد نتائج" عندما لا يطابق أي موظف
تلميح: سلسل عدة استدعاءات
filter() أو دمج الشروط في دالة تصفية واحدة.
النقاط الرئيسية
filter() تحتفظ بالعناصر المطابقة، not() تزيلها
has() تصفي حسب وجود الأحفاد - رائعة لمنطق الأب-الطفل
is() تُرجع قيمة منطقية - استخدمها للفحوصات الشرطية، وليس التسلسل
eq()، first()، last()، slice() تحدد حسب الموضع
each() تتكرر للتأثيرات الجانبية، map() تحول إلى قيم جديدة
- طرق التصفية قابلة للتسلسل ويمكن دمجها لمنطق اختيار معقد
- استخدم دائمًا
$(this) داخل استدعاءات التكرار للوصول إلى طرق jQuery