تعلّم jquery وظائف الانتقال عبر الصّفحة والتّعديل على العناصر في jQuery


محمد فوّاز عرابي

توفّر jQuery أدوات قويّة لإيجاد العنصر أو العناصر التي تريدها في الصّفحة، ثمّ العمل بهذه العناصر للوصول إلى النّتيجة المرغوبة. تسهّل jQuery بأدواتها هذه عمليّات كانت لتكون أكثر تعقيدًا لو أردنا تنفيذها من خلال وظائف DOM الأصليّة.

سنطّلع في هذا الجزء على بعض (لا كلّ) وظائف الانتقال عبر الصّفحة وتّعديل العناصر في jQuery. وقبل أن نبدأ، علينا فهم بعض المصطلحات الضّروريّة. لنفترض أنّ لدينا نصّ HTML التّالي:

<ul>
  <li>
    <span>
      <i>Foo</i>
    </span>
  </li>
  <li>Bar</li>
</ul>
  • نقول عن عنصر القائمة الأوّل (<li>) أنّه ابن (child) القائمة غير المرتّبة (<ul>).
  • نقول عن القائمة غير المرتّبة (<ul>) أنّها والد (parent) عنصري القائمة الاثنين.
  • نقول عن العنصر <span> أنّه خَلَفُ (descendant) القائمة غير المرتّبة.
  • نقول عن القائمة غير المرتّبة أنّها سَلَفٌ (ancestor) لكلّ ما داخلها.
  • نقول عن عنصري القائمة أنّهما شقيقان (siblings).

الانتقال عبر الصّفحة (Traversal)

تسمح jQuery لنا بالانتقال عبر عناصر HTML الّتي تكوّن صفحتنا. إذ نُنشئ أوّلًا تحديدًا مبدئيًّا ثمّ ننتقل عبر DOM انطلاقًا منه. وخلال مسيرنا عبر DOM، فإنّنا نُغيّر من تحديدنا الأوّل فنضيف إليه أو نحذف منه بعض العناصر، أو نستبدل به تحديدًا آخر بالكامل في بعض الأحيان.

تصفية التّحديدات

بإمكانك تصفية تحديد موجودٍ بحيث يتضمّن فقط العناصر الّتي تطابق معاييرَ مُحدّدة. بإمكانك مثلًا إجراء التّصفية بإحدى الطّرق التّالية:

var listItems = $( 
'li' );

// صفِّ التّحديد ليحوي فقط العناصر ذات الصّنف 'special'
var special = listItems.filter( '.special' );

// صفّ التّحديد ليحوي فقط العناصر من غير الصّنف 'special'
var notSpecial = listItems.not( '.special' );

// صفّ التّحديد ليحوي فقط العناصر الّتي تتضمّن span
var hasSpans = listItems.has( 'span' );

من المهمّ أن تعرف أن الوظيفة ‎.not()ليست عكس ‎.is()‎، لأنّ ‎.is()‎ تُعيد قيمة منطقيّة (true أو false)، بينما تُعيد ‎.not()‎ كائن jQuery جديدًا.

إيجاد العناصر انطلاقًا من تحديد

يمكن الاستفادة من تحديد أوّليّ كأساس لإنشاء تحديدات إضافيّة؛ فإذا كان لديك تحديدٌ يحوي عنصر قائمة مُفردًا مثلًا، وأردت التّعامل مع "أشقّائه" أو مع القائمة غير المُرتّبة الّتي تحويه، فبإمكانك إنشاء تحديد جديد انطلاقًا من التّحديد الموجود بسهولة:

// اختر 
أوّل عنصر قائمة في الصّفحة
var listItem = $( 'li' ).first(); // أيضًا: .last()

// اختر أشقّاء عنصر القائمة
var siblings = listItem.siblings();

// اختر الشّقيق التّالي لعنصر القائمة
var nextSibling = listItem.next(); // أيضًا: .prev()

// اختر والد عنصر القائمة
var list = listItem.parent();

// اختر عناصر القائمة الّتي تنحدر مباشرةً من القائمة
var listItems = list.children();

// اختر كلّ عناصر القائمة ضمن القائمة، بما في ذلك العناصر الفرعيّة
var allListItems = list.find( 'li' );

// اختر كل أسلاف عنصر القائمة ذوي الصّنف "module"
var modules = listItem.parents( '.module' );

// اختر أقرب سلفٍ لعنصر القائمة له الصّنف "module"
var module = listItem.closest( '.module' 
);

بإمكانك كذلك الإضافة على التّحديد الحاليّ باستخدام الوظيفة ‎.add()‎، الّتي تقبل مُحدِّدًا أو مصفوفة عناصر أو نص HTML أو كائن jQuery.

var list = $( '#my-unordered-list' );

// افعل شيئًا ما بالقائمة ثم ...

var listAndListItems = list.add( '#my-unordered-list li' 
);

العودة إلى التّحديد الأصليّ

تحتفظ jQuery بإشارة إلى تحديد الأصليّ عندما تستخدمه للانتقال إلى تحديدات أخرى انطلاقًا منه، في حال أردت العودة إلى التّحديد الأصليّ. افترض مثلًا أنّك حدّدت قائمة غير مرتّبه، ثمّ أردت التّعديل على عناصر القائمة، ثمّ العودة مجدّدًا للعمل على القائمة غير المرتّبة، عندها بإمكانك استخدام الوظيفة ‎.end()‎ للرّجوع إلى التّحديد الأصليّ:

$( '#my-unordered-list' )
 .find('li')

 // نحن الآن نعمل على عناصر القائمة
 .addClass('special')

.end()

// عدنا الآن للعمل على القائمة ذاتها
.addClass('super-special');

تُسهِّل الوظيفة ‎.end()‎ إجراء تعديلات كثيرة في جملة واحدة، إلّا أنّ هذا الأسلوب لا يُلقي بالًا لوضوح النّصّ البرمجيّ، فهو أشبه بأن تحكي قصّة دون أن تلتقط أنفاسك. لهذا السّبب لا أنصحك بالإكثار من استعماله، فهو يؤدّي في معظم الحالات إلى جعل قراءة النّصّ البرمجيّ وصيانته وتنقيحه أكثر صعوبة.

فيما يلي حلّ أفضل للمشكلة ذاتها:

var list = $( 
'#my-unordered-list' );
var listItems = list.find('li');

listItems.addClass( 'special' );
list.addClass( 'super-special' );

توفّر jQuery أيضًا الوظيفة ‎.addBack()‎ إن أردت إضافة تحديدك الأصليّ إلى التّحديد الحاليّ. مثال:

$( 'li.special' )

 .siblings()

  // نحن نعمل الآن على أشقّاء التّحديد السّابقة
  .removeClass( 'important' )

 .addBack()

 // الآن نعمل على عناصر القائمة الأصليّة وأشقائها **معًا**
 .addClass( 'urgent' );

هل اختلط عليك الأمر؟ الوظيفة ‎.addBack()‎ تشبه الوظيفة ‎.end()‎ في عيوبها، فكلاهما (وإن كان لهما استخدامها) يزيدان تعقيد النّصّ البرمجيّة. الحلّ الأفضل هو استخدام الوظيفة ‎.add()‎ لدمج التّحديدين الأصليين معًا:

var specialListItems = $( 
'li.special' );
var otherListItems = specialListItems.siblings();

otherListItems.removeClass( 'important' );
specialListItems.add( otherListItems ).addClass( 'urgent' 
);

هناك وظائف عديدة لم نتطرّق إليها هنا، يمكنك الاطّلاع عليها في وثائق الانتقال عبر الصّفحة.

التّعامل مع العناصر (Manipulation)

تسمح وظائف التّعامل مع العناصر في jQuery بتغيير DOM الصّفحة بصياغة أكثر بساطة من تلك الّتي توفّرها وظائف DOM الخام. تُعيد وظائف التّعامل مع العناصر في jQuery كائن jQuery الّتي استدعيت للعمل عليه، وهذا يعني إمكانيّة ربطها في سلسلة أو دمجها مع وظائف jQuery أخرى كالّتي ناقشناها في الفقرات السّابقة.

تعديل العناصر

كثيرةٌ هي طرق تعديل العناصر في jQuery. سنطّلع فيما يلي على طرق إنجاز المهام الأكثر شيوعًا.

إضافة أو حذف الأصناف (classes)

يمكن الاستفادة من أصناف الكائنات في HTML بأن نستهدفها في CSS بغرض تنسيقها، كما يُستفاد منها في إنشاء تحديدات jQuery. فمثلًا يمكن لعنصر في الصّفحة أن يقع تحت الصّنف hidden، والّذي يُستخدم في CSS لجعل خاصّة display موافقة للقيمة none للعناصر من هذا الصّنف، ثمّ يمكن حذف هذا الصّنف أو إضافته لتغيير حالة ظهور العناصر الموافقة في jQuery:

$( 
'li' ).addClass( 'hidden' );
$( 'li' ).eq( 1 ).removeClass( 'hidden' 
);

جرّب المثال في ساحة التّجربة (تأكد من ضغط زر Run with JS في هذا المثال وكلّ الأمثلة التالية)

إن تطلّبت حالتك إضافة صنفٍ أو حذفه مرارًا، فبإمكانك استخدام الوظيفة ‎.toggleClass()‎ الّتي تُبدّل حالة الصّنف على العنصر، فتضيفه إن لم يكن موجودًا أو تحذفه إن وُجد:

$( 'li' ).eq( 1 
).toggleClass( 'hidden' );

جرّب المثال في ساحة التّجربة

تغيير المظهر

ملاحظة: يُفضّل دومًا استخدام الأصناف واستهدافها بقواعد CSS لتغيير طريقة عرض العناصر، والاقتصار على استخدام jQuery في إضافة هذه الأصناف أو حذفها كما ورد للتوّ. في هذه الفقرة سنتعرّف كيف نُغيّر مظاهر العناصر مُباشرةً في jQuery، ولكننا نُفضِّل دومًا الأسلوب الأوّل إن كان يُحقِّق النّتائج ذاتها.

عندما تعجز عن تحقيق هدفك بإضافة الأصناف أو حذفها، فإنّ jQuery تقدّم الوظيفة .css() الّتي تسمح بتعيين مظهر العناصر مباشرةً، ولعلّ هذا يكون ضروريًّا عادةً عندما تحتاج إلى إسناد قيم عدديّة لا يمكن حسابها إلّا أثناء عمل التّطبيق، كمعلومات توضّع العناصر في الصّفحة. لا يُفضَّل استخدام الوظيفة ‎.css()‎ لإجراء تنسيقات بسيطة مثل ‎display: none‎، بل يُفضَّل في معظم الحالات إنجاز الغاية ذاتها باستخدام الأصناف وCSS.

افترض مثلًا أنّنا نريد تعيين مظهر العنصر بالاعتماد على عرض والده، وربّما يصعب أو يستحيل معرفة عرض الوالد مُسبقًا عند اعتماد تخطيط مرنٍ للصّفحة. في هذه الحالة قد نلجأ إلى الوظيفة ‎.css()‎ لتنسيق العنصر:

var list = $( 
'#my-unordered-list' );
var width = Math.floor( list.width() * 0.1 );

list.find('li').each(function( index, elem ) {
  var padding = width * index;
  $( elem ).css( 'padding-right', padding + 'px' 
);
});

جرّب المثال في ساحة التّجربة

إن احتجت إلى تعيين أكثر من خاصّة في وقت واحدٍ، مرّر كائنًا إلى الوظيفة ‎.css()‎ بدلًا من اسم الخاصّة وقيمتها. لاحظ أنّ عليك إحاطة أيّة خاصّة تحوي الرّمز "-" بعلامتي اقتباس:

$( 
'li' ).eq( 1 ).css({
 'font-size': '20px',
 'padding-right': '20px'
});

جرّب المثال في ساحة التّجربة

تغيير قيم النّماذج (forms)

تقدّم jQuery الوظيفة ‎.val()‎ لتعديل قيمة العناصر في النّماج مثل input وselect.

بإمكانك تمرير سلسلة نصّيّة لتعيين محتوى حقول input النّصّيّة:

$( 
'input[type="text"]' ).val( 'new value' 
);

جرّب المثال في ساحة التّجربة

بالنّسبة للعناصر من نوع select، بإمكانك تعيين الخيار المُختار باستخدام ‎.val()‎ أيضًا:

$( 'select' ).val( '2' 
);

جرّب المثال في ساحة التّجربة

أمّا لحقول input من نوع checkbox، فعليك تعيين الخاصّة checked على العنصر بالوظيفة ‎.prop()‎.

$( 
'input[type="checkbox"]' ).prop( 
'checked', 'checked' );

جرّب المثال في ساحة التّجربة

ملاحظة: أُضيفت الوظيفة ‎.prop()‎ في الإصدارة 1.6 من jQuery؛ وقبل ذلك كانت تُستخدم الوظيفة ‎.attr()‎ للغرض ذاته، وهي ما تزال تعمل في الإصدارات الحديثة من jQuery، ولكنّها في حالة checked تكتفي باستدعاء ‎.prop()‎. إن كنت تستخدم إصدارةً أحدث من 1.6، فأنصحك باستخدام ‎.prop()‎ دومًا لتعيين الخاصّة checked وخصائص عناصر DOM الأخرى. اطّلع على الوثائق لتفاصيل أكثر.

تغيير الصّفات (attributes) الأخرى

بإمكانك استخدام وظيفة ‎.attr()‎ لتغيير صفات العناصر، فيمكنك مثلًا تغيير عنوان رابط (الخاصّة title لعنصر <a>):

$( 'a' ).attr( 'href', 
'new title');

عند تعيين قيمة لصفة، بإمكانك تمرير دالّة في موضع المُعامل الثّاني للوظيفة، ومثلها مثل كلّ دوالّ الكتابة السّابقة، تتلقّى هذه الدّالّة مُعاملين اثنين: دليل العنصر الّذي تعمل عليه، والقيمة الحاليّة للصّفة. يجب أن تُعيد هذه الدّالة القيمة الجديدة للصّفة:

$( 'a' ).attr( 
'href', function(index, value) {
  return value + '?special=true';
});

جرّب المثال في ساحة التّجربة

بإمكانك حذف الصّفات أيضًا، وذلك باستخدام ‎.removeAttr()‎.

الحصول على معلومات من العناصر

ناقشنا في الجزء السّابق (أساسيّات jQuery) فكرة وظائف القراءة والكتابة. كلّ الوظائف الّتي يمكن استخدامها لتغيير العناصر، يمكن أيضًا استخدامها لقراءة معلومات من تلك العناصر. فيمكن مثلًا استخدام الوظيفة ‎.val()‎ الّتي وصفناها أعلاه كوظيفة قراءة وكتابة معًا:

var input = $( 'input[type="text"]' );
input.val( 'new value' );
input.val(); // returns 'new value'

وكذلك الأمر بالنّسبة للوظيفة ‎.css()‎، إذ يمكن استخدامها لقراءة قيمة خصائص CSS مُفردة بإمرار اسم الخاصّة فقط دون قيمة:

var listItemColor = $( 'li' ).css( 
'color' );

عندما تُستخدم وظائف التّعامل مع العناصر للقراءة، فإنّها تعمل فقط مع العنصر الأول في التّحديد، باستثناء الوظيفة ‎.text()‎ الّتي تقرأ المحتوى النّصيّ لكلّ العناصر المُحدّدة إن لم يُمرّر معامل إليها.

إضافة العناصر إلى الصّفحة

سواءٌ حدّدت عنصرًا أو أنشأت واحدًا جديدًا، فبإمكانك إضافة هذا العنصر إلى الصّفحة يمكن فعل ذلك بطريقتين: باستدعاء وظيفة تتبع للعنصر (أو العناصر) المطلوب إضافته، أو باستدعاء وظيفة تتبع لعنصر مرتبط بذلك الّذي تريد إضافته.

افترض مثلًا أنّك تريد نقل عنصر في قائمة من رأسها إلى ذيلها، هناك عدّة طرق لفعل ذلك.

بإمكانك مثلًا إضافة العنصر إلى القائمة باستدعاء الوظيفة ‎.appendTo()‎ على عنصر القائمة ذاته:

var listItem = $( '#my-unordered-list li' ).first();
listItem.appendTo( '#my-unordered-list' );

جرّب المثال في ساحة التّجربة

وبإمكانك أيضًا إضافة العنصر باستدعاء ‎.append()‎ على القائمة:

var listItem = $( '#my-unordered-list li' ).first();
$( '#my-unordered-list' ).append( listItem );

أو إضافته باستدعاء ‎.insertAfter()‎ على العنصر المُراد نقله مُمرّرًا العنصر الأخير في القائمة إلى الوظيفة:

var listItems = $( '#my-unordered-list li' );
listItems.first().insertAfter( listItems.last() );

جرّب المثال في ساحة التّجربة

أو إضافته باستدعاء ‎.after()‎ على العنصر الأخير في القائمة مُمرًّرا العنصر الأولى في القائمة إلى الوظيفة:

var listItems = $( '#my-unordered-list li' );
listItems.last().after( listItems.first() );

جرّب المثال في ساحة التّجربة

هناك طرق آخرى كثير لإضافة العناصر، فبإمكانك إضافتها حول عناصر أخرى أو داخلها أو خارجها بحسب حاجتك.

تعتمد أكثر الطّرق كفاءة في إضافة عنصر إلى الصّفحة على العناصر الّتي تتوفّر بين يديك بالفعل. فقد ترغب في إضافة العنصر إلى القائمة غير المُرتّبة في المثال السّابق إن كنت قد حدّدت القائمة غير المرتّبة من قبل لغرض آخر؛ أو إن كنت قد حدّدت عناصر القائجة جميعها، فقد يكون إضافة العنصر الأول بعد العنصر الأخير أمرًا أسهل.

عندما تختار الطّريقة المناسبة لإضافة العنصر، فلا تكتفِ بالنّظر في سهولة الطّريقة، بل فكّر في إمكانيّة صيانتها لاحقًا. تجنّب الطّرق الّتي تعتمد على افتراض بنية مُحدِّدة بدقَّة لصفحتك، فقد تقرّر تغيير هذه البنية فيما بعد.

نسخ العناصر

بإمكانك إنشاء نسخة من عنصر أو مجموعة عناصر باستخدام الوظيفة ‎.clone()‎ في jQuery، وستُنشئ النُّسخة في الذّاكرة دون أن تُدرج في الصّفحة، فعليك فعل ذلك بنفسك إن أردته. بإمكانك تعديل العناصر المنسوخة قبل إضافتها:

var clones = $( 'li' ).clone();

clones.html(function( index, oldHtml ) {
  return oldHtml + '!!!';
});

$( '#my-unordered-list' ).append( clones );

جرّب المثال في ساحة التّجربة

ملاحظة*: لن تمنعك jQuery من نسخ عنصر ذي مُعرِّف (ID)، ولكن عليك التأكّد من حذف المُعرِّف أو تغييره في العنصر المنسوخ بتعديل الصّفة id قبل إدراجه في المستند، إذ لا ينبغي أ يوجد عنصران بمُعرِّف واحدٍ في الصّفحة.

حذف العناصر

هناك ثلاث طرق لحذف العناصر من الصّفحة: ‎.remove()‎‏ و‎.detach()‎‏ و‎.replaceWith()‎‏، ولكلّ منها غرضٌ مُختلف.

يجب استخدام ‎.remove()‎‏ عند الحاجة لحذف العناصر بصورة دائمة، فهي ستحذف مع العنصر كلّ مُتوليّات الأحداث المُرتبطة به (event handlers). تُعيد الوظيفة ‎.remove()‎‏ إشارةً إلى العناصر المُحذوفة، ولكن عند إضافة هذه العناصر مرّة ثانيةً، فلن تكون أيّة أحداث مُرتبطةً بها.

$( '#my-unordered-list li' ).click(function() {
  alert( $( this ).text() );
});

var removedListItem = $( '#my-unordered-list li' ).first().remove();

removedListItem.appendTo( '#my-unordered-list' );
removedListItem.trigger( 'click' ); // لا رسالة تنبيه!

جرّب المثال في ساحة التّجربة

تُفيد الوظيفة ‎.detach()‎‏ في حذف العناصر مؤقّتًا من الصّفحة، فمثلًا إن رغب في إجراء تعديلات كبيرة على بنية الصّفحة باستخدام jQuery، فقد يكون حذف العناصر مؤقّتًا من الصّفحة ثمّ إضافتها ثانيةً أفضل أداءً بمراحل. ستحتفظ العناصر المحذوفة بهذه الوظيفة بمُتولّيات الأحداث المُرتبطة بها، ويمكن بعد ذلك إضافتها إلى الصّفحة مُجدّدًا باستخدام ‎.appendTo()‎‏ أو غيرها من وظائف الإضافة.

$( 
'#my-unordered-list li' ).click(function() {
  alert( $( this ).text() );
});

var detachedListItem = $( '#my-unordered-list li' 
).first().detach();

// افعل شيئًا ما مُعقّدًا بعنصر القائمة

detachedListItem.appendTo( '#my-unordered-list' );
detachedListItem.trigger( 'click' ); // 
alert!

أخيرًا لدينا الوظيفة ‎.replaceWith()‎‏ الّتي تُحلِّ عنصرًا أو نصّ HTML محلّ عنصرٍ أو عناصر أخرى. تُعاد العناصر الّتي أُزيلت من الوظيفة، ولكنّ كلّ متولّيات الأحداث المرتبطة بها تُحذف، تمامًا كالوظيفة ‎.remove()‎‏.

$( '#my-unordered-list li' ).click(function() {
  alert( $( this ).text() );
});

var replacedListItem = $( '#my-unordered-list li' ).first()
  .replaceWith( '<li>new!</li>' );

replacedListItem.appendTo( '#my-unordered-list' );

replacedListItem.trigger( 'click' ); // لا رسالة تنبيه!

جرّب المثال في ساحة التّجربة

خاتمة

تعلّمنا في هذا الجزء الطّرق المختلفة للانتقال بين العناصر في الصّفحة، وكيفيّة نقلها وتغييرها وإضافة عناصر جديدة. سنتعلّم في الجزء القادم كيف نُنصِت لتفاعل المستخدم مع صفحتنا.

ترجمة (بشيء من التصرف) للجزء الثالث من سلسلة  jQuery Fundamentals لمؤلّفتها Rebecca Murphey.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن