فهم التنقل بين الأشقاء
يتيح لك التنقل بين الأشقاء الحركة أفقيًا عبر شجرة DOM - التحرك بين العناصر التي تشترك في نفس الأب. تسمى هذه العناصر الشقيقة.
طرق الأشقاء مفيدة بشكل لا يصدق لبناء واجهات حيث تحتاج العناصر إلى التفاعل مع جيرانها، مثل التبويبات، الدوارات، قوائم التنقل، وحقول النماذج.
ما هي الأشقاء؟
بنية HTML:
<div class="parent">
<p>الطفل الأول</p> <!-- شقيق div و span -->
<div>الطفل الثاني</div> <!-- شقيق p و span -->
<span>الطفل الثالث</span> <!-- شقيق p و div -->
</div>
جميع العناصر الثلاثة (p, div, span) هي أشقاء لأنها تشترك في نفس الأب (.parent). إنها على نفس المستوى في شجرة DOM.
ملاحظة: الأشقاء هي عناصر على نفس المستوى مع نفس الأب. إنها ليست أسلافًا ولا أحفادًا لبعضها البعض.
طريقة siblings()
تُرجع طريقة siblings() جميع الأشقاء لكل عنصر في المجموعة المطابقة، باستثناء العنصر نفسه.
HTML:
<ul class="menu">
<li class="item">الرئيسية</li>
<li class="item active">المنتجات</li>
<li class="item">من نحن</li>
<li class="item">اتصل بنا</li>
</ul>
jQuery:
// الحصول على جميع أشقاء العنصر .active (يُرجع الرئيسية، من نحن، اتصل بنا)
$(".active").siblings();
// الحصول فقط على أشقاء li (نفس النتيجة في هذه الحالة)
$(".active").siblings("li");
// الحصول على أشقاء بفئة معينة
$(".active").siblings(".item");
// إزالة الفئة من جميع الأشقاء
$(".active").siblings().removeClass("active");
نصيحة: siblings() مثالية لتنفيذ أنماط "واحد نشط في كل مرة" مثل التبويبات، حيث يؤدي النقر على تبويب واحد إلى إلغاء تنشيط جميع الآخرين.
طريقة next()
تُرجع طريقة next() الشقيق التالي المباشر لكل عنصر. إنها تتقدم فقط عنصر واحد للأمام.
HTML:
<div class="steps">
<div class="step" data-step="1">الخطوة 1</div>
<div class="step" data-step="2">الخطوة 2</div>
<div class="step" data-step="3">الخطوة 3</div>
</div>
jQuery:
// الحصول على الشقيق التالي للخطوة 1 (يُرجع الخطوة 2)
$("[data-step='1']").next();
// الحصول على الشقيق التالي إذا كان لديه فئة معينة
$("[data-step='1']").next(".step");
// إضافة فئة إلى الخطوة التالية
$("[data-step='1']").next().addClass("active");
طريقة nextAll()
تُرجع طريقة nextAll() جميع الأشقاء التاليين لكل عنصر، وليس فقط الشقيق التالي المباشر.
HTML:
<div class="list">
<div class="item">عنصر 1</div>
<div class="item current">عنصر 2</div>
<div class="item">عنصر 3</div>
<div class="item">عنصر 4</div>
</div>
jQuery:
// الحصول على جميع الأشقاء بعد .current (يُرجع عنصر 3 وعنصر 4)
$(".current").nextAll();
// الحصول فقط على divs التي تأتي بعد
$(".current").nextAll("div");
// تنسيق جميع العناصر التالية
$(".current").nextAll().css("opacity", "0.5");
طريقة nextUntil()
تُرجع طريقة nextUntil() جميع الأشقاء التاليين حتى (لكن دون تضمين) عنصر محدد. هذا مفيد لتحديد نطاق من العناصر.
HTML:
<div class="content">
<h2 class="start">القسم 1</h2>
<p>فقرة 1</p>
<p>فقرة 2</p>
<h2 class="end">القسم 2</h2>
<p>فقرة 3</p>
</div>
jQuery:
// الحصول على جميع العناصر بين .start و .end (يُرجع كلتا الفقرتين)
$(".start").nextUntil(".end");
// إخفاء جميع الفقرات حتى h2 التالي
$(".start").nextUntil("h2").hide();
// تحديد الفقرات فقط
$(".start").nextUntil(".end", "p").addClass("section-content");
طريقة prev()
تُرجع طريقة prev() الشقيق السابق المباشر لكل عنصر. إنها عكس next().
HTML:
<div class="carousel">
<div class="slide">شريحة 1</div>
<div class="slide">شريحة 2</div>
<div class="slide active">شريحة 3</div>
</div>
jQuery:
// الحصول على الشريحة السابقة (يُرجع شريحة 2)
$(".active").prev();
// إظهار الشريحة السابقة
$(".active").prev(".slide").fadeIn();
طريقة prevAll()
تُرجع طريقة prevAll() جميع الأشقاء السابقين لكل عنصر.
HTML:
<div class="tasks">
<div class="task">مهمة 1</div>
<div class="task">مهمة 2</div>
<div class="task completed">مهمة 3</div>
<div class="task">مهمة 4</div>
</div>
jQuery:
// الحصول على جميع المهام قبل .completed (يُرجع مهمة 1 ومهمة 2)
$(".completed").prevAll();
// وضع علامة على جميع المهام السابقة كمنجزة
$(".completed").prevAll(".task").addClass("done");
طريقة prevUntil()
تُرجع طريقة prevUntil() جميع الأشقاء السابقين حتى (لكن دون تضمين) عنصر محدد.
HTML:
<form>
<input type="text" name="first">
<input type="text" name="middle">
<input type="email" name="email">
<input type="text" name="last">
</form>
jQuery:
// الحصول على جميع المدخلات من email إلى الخلف حتى (لكن دون تضمين) first
$("[name='email']").prevUntil("[name='first']");
// التحقق من صحة جميع الحقول قبل email
$("[name='email']").prevUntil(":first").each(function() {
if ($(this).val() === "") {
$(this).addClass("error");
}
});
مثال عملي: التنقل بين التبويبات
HTML:
<div class="tabs">
<div class="tab-nav">
<button class="tab-btn active" data-tab="home">الرئيسية</button>
<button class="tab-btn" data-tab="profile">الملف الشخصي</button>
<button class="tab-btn" data-tab="settings">الإعدادات</button>
</div>
<div class="tab-content">
<div class="tab-pane active" id="home">محتوى الرئيسية</div>
<div class="tab-pane" id="profile">محتوى الملف الشخصي</div>
<div class="tab-pane" id="settings">محتوى الإعدادات</div>
</div>
</div>
jQuery:
$(".tab-btn").on("click", function() {
// إزالة active من جميع الأشقاء
$(this).siblings().removeClass("active");
// إضافة active إلى التبويب المنقور
$(this).addClass("active");
// الحصول على معرف التبويب
var tabId = $(this).data("tab");
// إخفاء جميع لوحات التبويبات وإظهار المحدد
$("#" + tabId).addClass("active")
.siblings().removeClass("active");
});
مثال عملي: دوار الصور
HTML:
<div class="carousel">
<button class="prev-btn">←</button>
<div class="carousel-track">
<div class="carousel-slide"><img src="img1.jpg"></div>
<div class="carousel-slide active"><img src="img2.jpg"></div>
<div class="carousel-slide"><img src="img3.jpg"></div>
</div>
<button class="next-btn">→</button>
</div>
jQuery:
// زر التالي
$(".next-btn").on("click", function() {
var current = $(".carousel-slide.active");
var next = current.next(".carousel-slide");
if (next.length) {
current.removeClass("active");
next.addClass("active");
} else {
// العودة إلى الشريحة الأولى
current.removeClass("active");
$(".carousel-slide").first().addClass("active");
}
});
// زر السابق
$(".prev-btn").on("click", function() {
var current = $(".carousel-slide.active");
var prev = current.prev(".carousel-slide");
if (prev.length) {
current.removeClass("active");
prev.addClass("active");
} else {
// الانتقال إلى آخر شريحة
current.removeClass("active");
$(".carousel-slide").last().addClass("active");
}
});
مثال عملي: قائمة أكورديون
HTML:
<div class="accordion">
<div class="accordion-item">
<h3 class="accordion-header">القسم 1</h3>
<div class="accordion-body">المحتوى 1</div>
</div>
<div class="accordion-item">
<h3 class="accordion-header">القسم 2</h3>
<div class="accordion-body">المحتوى 2</div>
</div>
<div class="accordion-item">
<h3 class="accordion-header">القسم 3</h3>
<div class="accordion-body">المحتوى 3</div>
</div>
</div>
jQuery:
$(".accordion-header").on("click", function() {
var item = $(this).parent();
var body = $(this).next(".accordion-body");
// تبديل الأكورديون الحالي
body.slideToggle();
item.toggleClass("active");
// إغلاق جميع الأكورديونات الأخرى (الأشقاء)
item.siblings(".accordion-item").removeClass("active")
.find(".accordion-body").slideUp();
});
مثال عملي: نموذج متعدد الخطوات
HTML:
<div class="wizard">
<div class="wizard-step active">
<h3>الخطوة 1: المعلومات الشخصية</h3>
<input type="text" name="name">
<button class="next-step">التالي</button>
</div>
<div class="wizard-step">
<h3>الخطوة 2: العنوان</h3>
<input type="text" name="address">
<button class="prev-step">رجوع</button>
<button class="next-step">التالي</button>
</div>
<div class="wizard-step">
<h3>الخطوة 3: التأكيد</h3>
<button class="prev-step">رجوع</button>
<button class="submit">إرسال</button>
</div>
</div>
jQuery:
// الخطوة التالية
$(".next-step").on("click", function() {
var currentStep = $(this).closest(".wizard-step");
var nextStep = currentStep.next(".wizard-step");
if (nextStep.length) {
currentStep.removeClass("active");
nextStep.addClass("active");
}
});
// الخطوة السابقة
$(".prev-step").on("click", function() {
var currentStep = $(this).closest(".wizard-step");
var prevStep = currentStep.prev(".wizard-step");
if (prevStep.length) {
currentStep.removeClass("active");
prevStep.addClass("active");
}
});
تسلسل طرق الأشقاء
يمكنك تسلسل طرق الأشقاء معًا لأنماط تنقل معقدة.
أمثلة:
// الحصول على 3 أشقاء تاليين
$(".start").next().next().next();
// أفضل: استخدم nextAll() مع slice
$(".start").nextAll().slice(0, 3);
// الحصول على الشقيق السابق للشقيق السابق
$(".current").prev().prev();
// الحصول على جميع الأشقاء باستثناء الحالي
$(".current").siblings();
// إخفاء الحالي وجميع التاليين
$(".current").add($(".current").nextAll()).hide();
خطأ شائع: تذكر أن siblings() تستثني العنصر نفسه. إذا كنت بحاجة لتضمين العنصر الحالي، استخدم $(".current").add($(".current").siblings()).
جدول المقارنة
| الطريقة |
الاتجاه |
تُرجع |
الأفضل استخدامها لـ |
siblings() |
الاثنان |
جميع الأشقاء |
إلغاء تنشيط التبويبات/العناصر الأخرى |
next() |
للأمام |
الشقيق التالي فقط |
الانتقال إلى العنصر التالي |
nextAll() |
للأمام |
جميع الأشقاء التاليين |
عمليات جماعية للأمام |
nextUntil() |
للأمام |
أشقاء حتى نقطة |
تحديد نطاق للأمام |
prev() |
للخلف |
الشقيق السابق فقط |
الانتقال إلى العنصر السابق |
prevAll() |
للخلف |
جميع الأشقاء السابقين |
عمليات جماعية للخلف |
prevUntil() |
للخلف |
أشقاء حتى نقطة |
تحديد نطاق للخلف |
تمرين عملي
السيناريو: إنشاء جدول تسعير حيث يؤدي اختيار خطة واحدة إلى إلغاء تحديد الأخريات وإظهار مقارنة.
بنية HTML:
<div class="pricing">
<div class="plan-card" data-plan="basic">
<h3>أساسي</h3>
<p class="price">$9/شهر</p>
<button class="select-plan">اختر</button>
</div>
<div class="plan-card" data-plan="pro">
<h3>محترف</h3>
<p class="price">$29/شهر</p>
<button class="select-plan">اختر</button>
</div>
<div class="plan-card" data-plan="enterprise">
<h3>مؤسسي</h3>
<p class="price">$99/شهر</p>
<button class="select-plan">اختر</button>
</div>
</div>
مهامك:
- عند النقر على زر "اختر"، أضف فئة "selected" إلى الأب
.plan-card
- أزل فئة "selected" من جميع البطاقات الشقيقة
- اجعل جميع البطاقات الشقيقة باهتة قليلاً (opacity: 0.6)
- احتفظ بالبطاقة المحددة بعتامة كاملة
- إضافي: أضف شارة "شائع" للبطاقة الوسطى فقط
- إضافي: أظهر/أخفِ قسم مقارنة بين الخطة المحددة وأشقائها
تلميح: استخدم
closest() للحصول على البطاقة، ثم
siblings() لإلغاء تحديد الآخرين.
النقاط الرئيسية
siblings() تحصل على جميع الأشقاء - مثالية لأنماط "واحد نشط في كل مرة"
next() و prev() تتحرك عنصر واحد للأمام/للخلف
nextAll() و prevAll() تحصل على جميع الأشقاء في اتجاه واحد
nextUntil() و prevUntil() تحدد نطاقات من الأشقاء
- جميع الطرق تقبل محددات اختيارية لتصفية النتائج
- التنقل بين الأشقاء ضروري للتبويبات، الدوارات، والواجهات المتسلسلة
- تذكر:
siblings() تستثني العنصر نفسه