المحتوى عن 'dom'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • نصائح وإرشادات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • التجارة الإلكترونية
  • الإدارة والقيادة
  • مقالات ريادة أعمال عامة

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • ASP.NET
    • ASP.NET Core
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • التسويق بالرسائل النصية القصيرة
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 9 نتائج

  1. dom

    في سلسلة فهم شجرة DOM، ناقشنا شجرة DOM وكيفية الوصول والتنقلالتنقل وإضافة وإزالة وتعديل العقد والعناصر باستخدام وحدة تحكّم أدوات المطوّر. table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } code { background-color: rgb(250, 250, 250); border-radius: 3px; } بإمكاننا إجراء أي تغيير على شجرة DOM حتى هذه اللحظة، من وجهة نظر المستخدم فإنّه ليسَ مفيدًا للغاية لأننا قمنا بتنفيذ التغييرات يدويًّا فقط. سنتعرَّف الآن على الأحداث وربط كل شيء معها لإنشاء مواقع تفاعلية. ما هي الأحداث؟ الأحداث (event) هي الإجراءات التي تحدث في المتصفّح والتي يبدأها المستخدم أو المتصفّح. فيما يلي عدّة أمثلة عن الأحداث الشائعة التي يمكن أن تحدث على موقع الويب: انتهاء الصفحة من التحميل نقر المستخدم على زر تحويم المستخدم سهم الفأرة فوق قائمة منسدلة إرسال المستخدم بياناته ضغط المستخدم على أحد مفاتيح لوحة مفاتيحه. بإمكان المطورين إظهار رسائل للمستخدم للتحقق من صحة بيانات، والاستجابة إلى ضغط زرٍّ، والعديد من الإجراءات الأخرى وذلك عبر برمجة استجابات جافاسكربت على حدث معيّن. سنتطرق إلى مُعَالِجَاتَ الأحداث ومُسْتمعي الأحداث وكائنات الأحداث. كما سنعرّج لثلاث طرقٍ مختلفة لكتابة التعليمات البرمجيّة للتعامل مع الأحداث، وبعض الأحداث الأكثر شيوعًا. ستتمكّن من تقديم تجربة ويب أكثر تفاعلية للمستخدمين النهائيين، من خلال التعرف على الأحداث. معالجات الأحداث ومستمعي الأحداث عندما ينقر المستخدم على زر أو يضغط المفتاح، يتم قدحُ الحدث، ويُسمّى آنذاك حدث النقر click أو حدث الضغط keypress على التوالي. معالج الأحداث (event handler) هو دالَة جافاسكربت تعمل عند وقوع حدثٍ ما. يقوم مستمع الحدث (event listener) بإرفاق واجهة استجابة لعنصر، ممَّا يسمح لهذا العنصر بالانتظار لإطلاق الحدث المحدّد أو ويكأنه يتنصَّت ويستمع إلى صوت إطلاق ذلك الحدث المتمثِّل بعيار ناري. هناك ثلاث طرق لإسناد الأحداث إلى العناصر: مُعَالِجَات الأحداث المضمّنة (Inline event handlers). خاصيات معالج الحدث (Event handler properties). مستمعو الأحداث (Event listeners). سنتعرف على ثلاث الطرق جَمِيعِها للتأكّد من أنك على دراية كاملة بكلِّ طريقة لإطلاق الحدث، ومناقشة إيجابيات وسلبيات كل طريقة. الخصيّات المضمّنة لمعالج الأحدث لبدء التعرف على معالجات الأحداث، سننظر أولاً في معالج الحدث المضمَّن (inline event handler9). لنبدأ بمثالٍ بسيط للغاية، يتكون من العنصرين زرٍّ button وفقرة p. ونريد من المستخدم أن يضغط على الزر لتغيير محتوى النص في الفقرة. لنبدأ بصفحة HTML تحتوي على زرٍ. سنشير إلى ملف جافاسكربت وسنضيف الشيفرة البرمجية فيما بعد: الملف events.html: <!DOCTYPE html> <html lang="en-US"> <head> <title>Events</title> </head> <body> <!-- إضافة زر --> <button>Click me</button> <p>Try to change me.</p> </body> <!-- ملف جافاسكربت --> <script src="js/events.js"></script> </html> سنضيف خاصية على الزر مباشرةً تسمّى onclick ( أي عند النقر، نفِّذ ...). ستكون قيمة خاصيّة هي دالة ننشئها تسمّى changeText()‎ تمثِّل معالج الحدث. الملف events.html: <!DOCTYPE html> <html lang="en-US"> <head> <title>Events</title> </head> <body> <button onclick="changeText()">Click me</button> <p>Try to change me.</p> </body> <script src="js/events.js"></script> </html> لننشئ الملف events.js ضمن المسار ‎‎js/‎‎. سننشئ الدالة changeText()‎ التي ستعدّل محتوى النص المتمثِّل بقيمة الخاصية textContent على عنصر الفقرة p. الملف js/events.js: // تعديل نصِّ الفقرة عبر هذه الدالّة const changeText = () => { const p = document.querySelector('p'); p.textContent = "I changed because of an inline event handler."; } عند تحميلك الصفحة events.html لأول مرة ستبدو كما يلي: حينما يتمُّ النقر على الزر من قبل المستخدم أو غيره، فإن محتوى نصّ الفقرة سيتغيّير من Try to change me. إلى I changed because of an inline event handler. تعدُّ معالجات الأحداث المضمّنة طريقةً مباشرةً لبدء فهم الأحداث، ولكن يجب ألا تستخدم بشكل عام خارج نطاق الاختبار والأغراض التعليميّة. يمكنك مقارنة معالجات الأحداث المضمَّنة بأنماط CSS المضمَّنة في عنصر HTML. من العمليّ للغاية الحفاظ على ورقة أنماط منفصلة للأصناف بدلًا من إنشاء أنماط مضمّنة في كل عنصر، تمامًا كما هو أكثر جدوى للحفاظ على شيفرات جافاسكربت التي تتم معالجتها بالكامل من خلال ملف منفصل بدلًا من إضافتها إلى كل عنصر. خاصيات معالج الأحداث الخطوة التالية، هي الانتقال من معالج الأحداث المضمّنة إلى خاصية معالج الأحداث. يعمل هذا بشكل مشابه جدًّا لمعالج مضمَّن، باستثناء أننا نقوم بتعيين خاصية العنصر في الجافاسكربت بدلًا من خاصية HTML. سيكون الإعداد هو نفسه هنا، باستثناء أننا لم نعد ندرج onclick="changeText()‎"‎ في شيفرة العنصر: الملف events.html: ... <body> <button>Click me</button> <p>I will change.</p> </body> ... ستظلُّ وظيفتنا متشابهة أيضًا، إلا أننا نحتاج الآن إلى الوصول إلى العنصر button في جافاسكربت. يمكننا ببساطة الوصول إلى الخاصية onclick مثلما نصل إلى الخاصية style أو id أو أي خاصية عنصر أخرى، ثم نقوم بتعيين مرجع للدالة المراد تنفيذها. الملف js/events.js: // الدالة المراد تنفيذها عند وقوع الحدث والتي تعدِّل محتوى الفقرة const changeText = () => { const p = document.querySelector('p'); p.textContent = "I changed because of an event handler property."; } // button إضافة معالج حدث كخاصية للعنصر const button = document.querySelector('button'); button.onclick = changeText; ملاحظة: لا تتبع معالجات الأحداث عُرْفَ سنام الجمل (camelCase) التي تلتزم بها معظم تعليمات جافاسكربت البرمجية. لاحظ أن الرمز هو onclick، وليس onClick. عند تحميل الصفحة لأول مرة ، سيعرض المتصفح ما يلي: الآن عند النقر فوق الزر، سيكون له تأثير مماثل كما كان من قبل: لاحظ بتمريرنا مرجع الدالة المراد تنفيذها إلى الخاصية onclick، فإننا لا نقوم بتضمين الأقواس، حيث أننا لا نستدعي الدالّة في تلك اللحظة، ولكننا نمرّر مرجعًا إليها. button.onclick = changeText; تعدُّ خاصيَّة معالج الأحداث أكثرَ قابليَّةٍ للصيانة من المعالج المضمَّن، إلَّا أنها تعاني عقباتً مماثلة. فمثلاً، محاولةُ تعييِّن عدّة خصائص onclick منفصلة سيطبق التأثير على آخر محاولة. كما هو موضَّح أدناه. الملف js/events.js: const p = document.querySelector('p'); const button = document.querySelector('button'); const changeText = () => { p.textContent = "Will I change?"; } const alertText = () => { alert('Will I alert?'); } // يمكن تعديل الأحداث button.onclick = changeText; button.onclick = alertText; في المثال أعلاه، لن تعرض النقرة على الـ button سوى تنبيه، ولن تغيّر النصّ p، لأن alert()‎ هو آخر تعليمة برمجية أضيفت إلى الخاصية. من خلال فهم كل من معالجات الأحداث المضمّنة وخصائص معالج الأحداث، دعنا ننتقل إلى مستمعي الأحداث. مستمعي الأحداث أحدث إضافة إلى معالجات الأحداث في جافاسكربت هي مستمعي الحدث. يراقب مستمع الحدث حدثًا على عنصر. بدلاً من إسناد الحدث مباشرةً إلى خاصيّة في العنصر، سنستخدم التابع addEventListener()‎ للاستماع للحدث. يأخذ addEventListener()‎ معاملين إلزاميين - الحدث الذي يجب الاستماع إليه، ودالَّة ردِّ نداء لتنفيذها عند اطلاق الحدث. ملف الـ HTML لمستمع الأحداث الخاص بنا هو نفسه في المثال السابق. الملف events.html: ... <button>Click me</button> <p>I will change.</p> ... سنظلّ نستخدم نفس الدالّة changeText()‎ كما سابقًا ولكن سنربطها مع التابع addEventListener()‎ على الزر. الملف js/events.js: // الدالة المراد تنفيذها عند وقوع الحدث والتي تعدِّل محتوى الفقرة const changeText = () => { const p = document.querySelector('p'); p.textContent = "I changed because of an event listener."; } // الاستماع لحدث النقر const button = document.querySelector('button'); button.addEventListener('click', changeText); لاحظ أنه مع أوّل طريقتين، تمّت الإشارة إلى حدث النقر باسم onclick، ولكن مع مستمعي الأحداث يشار إليه باسم click. تُسْقَطُ on من الكلمة لكل مُسْتَمِع حدث. في القسم التالي، سنأخذ المزيد من الأمثلة على أنواع الأحداث الأخرى. عند إعادة تحميل الصفحة بشيفرة جافاسكربت أعلاه، ستتلقى الخَرْج التالي: للوهلة الأولى، يبدو مستمعو الأحداث متشابهين جدًا مع خصائص معالج الأحداث، لكن لديهم بعض المزايا. يمكننا تعيين عدّة مستمعين على نفس العنصر، كما هو موضَّح في المثال أدناه. الملف js/events.js: const p = document.querySelector('p'); const button = document.querySelector('button'); const changeText = () => { p.textContent = "Will I change?"; } const alertText = () => { alert('Will I alert?'); } // يمكن إضافة عدة مستمعات إلى الحدث نفسه والعنصر نفسه أيضًا button.addEventListener('click', changeText); button.addEventListener('click', alertText); سيتمُّ إطلاق الحدثين في المثال أعلاه، ممّا يوفِّر للمستخدم كلًّ من التنبيه والنصِّ المعدّل بعد النقر فوق التنبيه. ستستخدام غالباً دالّات مجهولة (Anonymous functions) بدلاً من مرجع دالّة على مُسْتَمع الحدث. الدالّات المجهولة هي دالّات غير مُسَمَّاة. // دالة مجهولة يراد تنفيذها عند إطلاق الحدث button.addEventListener('click', () => { p.textContent = "Will I change?"; }); من المُمْكِن أيضًا استخدام دالّة removeEventListener()‎ لإزالة حدث واحد أو جميع الأحداث من عنصر. // button من العنصر alert حذف الدالة button.removeEventListener('click', alertText); يمكنك استخدام addEventListener()‎على الكائنين document و window. يُعَدُّ مُسْتَمِعُو الأحداث حاليًا الطريقةَ الأكثرَ شيوعًا والمفضَّلة للتعامل مع الأحداث في جافاسكربت. الأحداث المشتركة تعلمّنا عن معالجات الأحداث المضمّنة، وخصائص معالج الأحداث، ومستمعي الأحداث باستخدام حدث النقرات، ولكن هناك العديد من الأحداث في جافاسكربت. سنتطرق لأكثر الأحداث شيوعًا أدناه. أحداث الفأرة أحداث الفأرة هي من بين الأحداث الأكثر استخدامًا. تشير إلى الأحداث التي تنطوي على نقر زر الفأرة أو تحريك المؤشر وتحويمه (hovering). تتوافق هذه الأحداث أيضًا مع الإجراء المماثل على جهاز يعمل باللمس. الحدث الوصف click يُطلَق عند الضغط بزر الفأرة أو عند الإفلات على العنصر dblclick يُطلَق عندما يتم النقر فوق عنصر مرتين mouseenter يُطلَق عندما يدخل المؤشر داخل عنصر mouseleave يُطلَق عندما يترك المؤشر عنصرًا mousemove يُطلَق في كل مرة يتحرك فيها المؤشر داخل عنصر ما`` إن حدث النقر click هو حدثٌ مركَّب يتألف من الجمع بين حدثين هما mousedown و mouseup، ويُطلَق حينَ الضغط على زر الفأرة لأسفل أو رفعه، على التوالي. يؤدي استخدام الحدثين mouseenter و mouseleave بالترادف إلى إعادة إنشاء تأثير التحويم الذي يستمر ما دام مؤشر الفأرة على العنصر. أحداث النموذج أحداث النموذج form هي إجراءات تتعلق بالنماذج، مثل عناصر الإدخال input التي يتم تحديدها أو غير المحددة، والنماذج التي يتم إرسالها. الحدث وصف submit يُطلَق عند إرسال النموذج focus يُطلَق عند تلقِي عنصر (مثل المدخلات) التركيز blur يُطلَق حينَ يفقد العنصر التركيز يتحقق التركيزfoucus عند تحديد عنصر، على سبيل المثال، من خلال النقر بالفأرة أو الانتقال إليه عبر المفتاح TAB غالبًا ما تستخدم جافاسكربت لإرسال النماذج وإرسال القيم إلى لغة الواجهة الخلفية. تتمثّلُ ميزة استخدام جافاسكربت لإرسال النماذج بأنه لا يتطلب إعادة تحميل الصفحة لإرسال النموذج، ويمكن استخدام جافاسكربت للتحقق من حقول الإدخال المطلوبة. أحداث لوحة المفاتيح تُستخدم أحداث لوحة المفاتيح لمعالجة إجراءات لوحة المفاتيح، مثل الضغط على مفتاح ما، ورفع الضغط عن مفتاح، واستمرار ضغط مفتاح. الحدث وصف keydown يُطلَق مرة واحدة عند الضغط على أي مفتاح keyup يُطلَق مرة واحدة عندما يتم تحرير (إفلات الضغط) المفتاح المضغوط keypress يُطلَق بشكل مستمر أثناء الضغط على المفتاح قد يبدو الحدثين keydown و keypress متشابهين إلا أنهما لا يتيحان الوصول إلى جميع المفاتيح بالضبط. في حين أنَّ keydown يقرّ بكل ضغطَة (أي الضغط على أي مفتاح)، يستثني الحدث keypress المفاتيح التي لا يولد الضغط عليها حرفًا، مثل المفاتيح SHIFT و DELETE و ALT وغيرها. أحداث لوحة المفاتيح لها خصائص محددة للوصول إلى المفاتيح الفردية. إذا مُرِّرَ المعامل الأول (الكائن event) عبر مستمع الحدث، فيمكننا الوصول إلى مزيد من المعلومات حول الإجراء الذي حدث أهمها ثلاثة خصائص تتعلق بكائنات لوحة المفاتيح هي: keycode و key و code. إذا ضغط المستخدم على المفتاح a على لوحة المفاتيح، فستظهر الخصائص التالية المتعلقة بهذا المفتاح: خاصية وصف مثال keyCode عدد يتعلق بالمفتاح 65 key يمثل اسم الحرف a code يمثل المفتاح الفعلي الذي يتم الضغط عليه keyA لإظهار كيفية جمع هذه المعلومات عبر وحدة التحكم جافاسكربت، يمكننا كتابة سطور التعليمات البرمجيّة التالية: // keyCode و key و code التحقق من الخاصيات document.addEventListener('keydown', event => { console.log('key: ' + event.keyCode); console.log('key: ' + event.key); console.log('code: ' + event.code); }); بمجرد ضغط ENTER في الطرفية، يمكننا آنذاك الضغط على أي مفتاح من لوحة المفاتيح، في هذا المثال، سنضغط a. Output keyCode: 65 key: a `code: KeyA` إنَّ الخاصيَّةَ keyCode هي عدد يمثلُّ قيمة المفتاح الذي ضُغِطَ بينما تمثِّل خاصيَّةَ key اسم الحرف، التي يمكن أن تتغيّر - على سبيل المثال، ضغط المفتاح a مع SHIFT سيؤدي A. وتمثِّلُ الخاصيِّةُ code المفتاح الفيزيائي على لوحة المفاتيح. لاحظ أنَّ keyCode في طريقها إلى الزوال ويفضل استخدام code في مشاريع جديدة. لمعرفة المزيد، يمكنك عرض القائمة الكاملة للأحداث على شبكة مطوري Mozilla. كائنات الحدث يتكون الكائن Event من الخاصيّات والتوابع التي يمكن لجميع الأحداث الوصول إليها. بالإضافة إلى Event الكائن العام، كل نوع من أنواع الأحداث له امتدادات خاصة به، مثل KeyboardEvent و MouseEvent. سيمرَّر الكائن Event من خلال دالّة المستمع كمعامل. وعادة ما يكتب باسم event أو e. يمكننا الوصول إلى الخاصية code التابعة للـحدث keydown لتكرار عناصر تحكم لوحة المفاتيح في لعبة مثلًا. قم بإنشاء ملف HTML يحوي العنصر <p> وحملّه في المتصفح. الملف event-test-p.html: <!DOCTYPE html> <html lang="en-US"> <head> <title>Events</title> </head> <body> <p></p> </body> </html> ثم اكتب شفرة جافاسكربت التالية في طرفية أدوات المطور . // تمرير حدث إلى مستمع document.addEventListener('keydown', event => { var element = document.querySelector('p'); // إسناد قيمة رموز المفاتيح المراد الضغط عليها إلى متغيرات var a = 'KeyA'; var s = 'KeyS'; var d = 'KeyD'; var w = 'KeyW'; // تحديد الاتجاه لكل مفتاح switch (event.code) { case a: element.textContent = 'Left'; break; case s: element.textContent = 'Down'; break; case d: element.textContent = 'Right'; break; case w: element.textContent = 'Up'; break; } }); عند الضغط على أحد المفاتيح - a، أو s، أو d، أو w سترى خرجًا مشابهًا لما يلي: يمكنك الاستمرار في تطوير كيفية استجابة المتصفح للمستخدم حينَ الضغط على هذه المفاتيح، ويمكن إنشاء موقع ويب أكثر ديناميكية. سنتطرق إلى إحدى خصائص الأحداث الأكثر استخدامًا: الخاصيِّةُ target. في المثال التالي ، لدينا ثلاثة عناصر div ضمن قسم واحد section. الملف event-test-div.html: <!DOCTYPE html> <html lang="en-US"> <head> <title>Events</title> </head> <body> <section> <div id="one">One</div> <div id="two">Two</div> <div id="three">Three</div> </section> </body> </html> باستخدام event.target في جافاسكربت ضمن طرفيّة أدوات المطور (Developer Console)، يمكننا وضع مستمع حدث واحد على العنصر section الخارجي والحصول على العنصر الأكثر تداخلًا. const section = document.querySelector('section'); // طباعة الهدف المحدَّد section.addEventListener('click', event => { console.log(event.target); }); يؤدي النقر فوق أي عنصر من هذه العناصر إلى إعادة إخراج العنصر المحدد ذي الصلة إلى الطرفية باسـتخدام event.target. إتاحة وضع مُسْتَمع حَدَث واحد فقط، يُمَكِّنُ من الوصول إلى العديد من العناصر المتداخلة، وهذا في غاية الأهمية. باستخدام الكائن Event، يمكننا إعداد استجابات متعلقة بجميع الأحداث، بما في ذلك الأحداث العامة والإضافات الأكثر تحديدًا. الخلاصة الأحداث هي الإجراءات التي تحدث على موقع ويب، مثل النقر فوق الفأرة أو تحويم المؤشر أو إرسال نموذج أو تحميل صفحة أو الضغط على مفتاح في لوحة المفاتيح. تصبح جافاسكربت تفاعليًا وديناميكيًا حقًا عندما نتمكن من جعل مواقع الويب تستجيب للإجراءات التي اتخذها المستخدم. تعلمنا -في هذا الدليل ما هي الأحداث، وأمثلة عن الأحداث الشائعة، والفرق بين معالجات الأحداث ومستمعي الأحداث، وكيفية الوصول إلى الكائن Event. ستتمكن من إنشاء مواقع وتطبيقات ديناميكية، باستخدام هذه المعلومات. ترجمة - وبتصرف- للمقال Understanding Events in JavaScript لصاحبته Tania Rascia
  2. تعلمنا فيما سبق في هذه السلسلة "كيف تجري تغيرات على شجرة DOM" والتعامل مع شجرة DOM من إنشاء، وإدراج، واستبدال وإزالة عناصر من المستند بتوابع مضمنة. أصبحت الآن مؤهلًا لاستخدام قدرات JavaScript التفاعلية وتعديل عناصر الويب لبزيادة كفاءتك في التعامل مع شجرة DOM. table { width: 100%; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } سنكمل في هذا المقال موضوع إجراء التعديل على شجرة DOM بتعديل الأنماط والأصناف والخاصيات الأخرى لعقد عناصر HTML. وهذا سيعطيك فهمًا أكبر للتعامل مع العناصر الأساسية لشجرة DOM. استعراض تحديد العناصر استخدمت مكتبة شائعة ضمن الجافاسكربت تسمى jQuery لتحديد وتعديل عناصر شجرة DOM. سهَّلت هذه المكتبة من اختيار عنصر أو أكثر ضمن المستند وتعديلها وتغييرها في آن معًا. راجعنا في مقال "الوصول إلى العناصر في شجرة DOM" التوابع الخاصة بـ DOM التي تحدد العقد وتعدل عليها عبر جافاسكربت الصرفة فقط. لنتذكر أن التابعين document.querySelector()‎ و document.getElementById()‎ يستخدمان للوصول إلى عنصر واحد. نستطيع الوصول العنصر باستخدام العنصر div أو عبر الخاصية id. <div id="demo-id">Demo ID</div> بالإمكان اختيار أي عنصر في الصفحة بأي نوع من المحدِّدات باستخدام التابع querySelector()‎. // كلا التابعين سيعيد عنصرًا واحدًا const demoId = document.querySelector('#demo-id'); بإمكاننا تحديث جزء من العنصر كالنص داخله بسهولة، حينما نصل إلى العنصر. // تغيير النصّ لعنصر واحد demoId.textContent = 'Demo ID text updated.'; حينما نصل إلى عدة عناصر باستخدام محدد مشترك، مثل صنف محدد، يمكننا إجراء تعديل على جميع العناصر داخل حلقة تكرارية. لدينا عنصرين من div ذوي صنف مشترك. <div class="demo-class">Demo Class 1</div> <div class="demo-class">Demo Class 2</div> للإمساك بجميع العناصر ذات الصنف demo-class مثلًا، سنستخدم querySelectorAll()‎، وسنستخدم forEach()‎ للوصول إلى العنصر وتطبيق التغيير. كما بالإمكان الوصول إلى عنصر محدد بـ querySelectorAll()‎ بنفس الطريقة التي تستخدمها مع مصفوفة، باستخدام الأقواس المربعة. // demo الحصول على قائمة بجميع العناصر ذات الصنف const demoClasses = document.querySelectorAll('.demo-class'); // تغيير النصّ لعدّة عناصر باستخدام حلقة تكراريّة demoClasses.forEach(element => { element.textContent = 'All demo classes updated.'; }); // الوصول للعنصر الأول ضمن القائمة demoClasses[0]; هذا هو أحد أهم الاختلافات التي يجب معرفتها عند الانتقال من jQuery إلى JavaScript الصرفة. لن تشرح العديد من الأمثلة على تعديل العناصرعملية تطبيق هذه التوابع والخصائص على عناصر متعددة. غالبًا ما يتم إرفاق الخاصيات والتوابع الواردة في هذه المقالة بـ «مسمتعي الأحداث» (event listener) من أجل الاستجابة للنقرات، التحويم (hover)، ومشغلات (triggers) أخرى. ملاحظة: سيعيد التابعان getElementsByClassName()‎ و getElementsByTagName()‎ مجموعة عناصر HTML لا يمكنها استعمال forEach()‎ على عكس العناصر التي يعيدها التابعquerySelectorAll()‎. في هذه الحالات، ستحتاج إلى استخدام حلقة for الاعتيادية للتكرار عبر مجموعة العناصر تلك. تعديل الخاصيات تحتوي الخاصيات (التي هي قيم) على معلومات إضافية عن عناصر HTML. تأتي عادةً في ثنائيات الاسم/القيمة، وقد تكون أساسية اعتمادًا على العنصر. إن الخاصية src التابعة للعنصرimg، والخاصية href التابعة للعنصر a، وكذلك الخاصيات class و id، و style هي أحد أكثر الخاصيات شيوعًا. للحصول على قائمة كاملة بخاصيات HTML، قم بعرض قائمة الخاصيات على شبكة مطوري Mozilla. ستُسبَق العناصر المخصصة التي ليست جزءًا من معيار HTML بـالبادئة data-. لدينا أربع توابع لتعديل خاصيات العنصر في جافاسكربت: التابع الوصف مثال hasAttribute()‎ يعيد القيمة true أو false إن كان العنصر يملك خاصية محدَّدة أم لا. element.hasAttribute('href');‎ getAttribute()‎ يعيد قيمة الخاصية المحددة أو null. element.getAttribute('href');‎ setAttribute()‎ يضيف أو يحدّث قيمة لخاصية محددة. element.setAttribute('href', 'index.html');‎ removeAttribute()‎ يزيل خاصية محدَّدة من عنصر. element.removeAttribute('href');‎ لننشئ ملف HTML جديد يحوي العنصر img مع خاصية واحدة. سنربط العنصر بصورة عامة عبر رابط، إلا أنه من الممكن ربط الوسم بصورة محلية في حال عدم توفر اتصال بالإنترنت. attributes.html <!DOCTYPE html> <html lang="en"> <body> <img src="https://js-tutorials.nyc3.digitaloceanspaces.com/shark.png"> </body> </html> افتح الملف السابق على متصفح متطور، وافتح الطرفية في وحدة تحكم المطور (Developer Console)، وستشاهد ما يلي: سنختبر طرق الخاصية (دالات) عبر المثال التالي: // إسناد عنصر صورة const img = document.querySelector('img'); img.hasAttribute('src'); // يعيد القيمة المنطقية صح img.getAttribute('src'); // "...shark.png" يعيد img.removeAttribute('src'); // وقيمتها src يحذف الخاصية أزلت الخاصية src والقيمة المرتبطة بها الموجودة العنصر img بعد المثال السابق، ولكن بإمكانك إعادة تعيين تلك الخاصية وإسناد القيمة لصورة بديلة باستخدام img.setAttribute()‎: img.setAttribute('src', 'https://js-tutorials.nyc3.digitaloceanspaces.com/octopus.png'); يمكننا تعديل الخاصية مباشرةً بإسناد قيمة جديدة إليها كخاصية للعنصر، وإعادة تعيين src للصورة shark.png بالشكل التالي: img.src = 'https://js-tutorials.nyc3.digitaloceanspaces.com/shark.png'; يمكن تحرير أي خاصيّة بهذا التابع وكذلك مع التوابع المذكورة أعلاه. إن التابعينhasAttribute()‎ و getAttribute()‎ عادةً ما يُستخدمان مع عبارات شرطية، بينما تُستخدَم setAttribute()‎ و removeAttribute()‎ مباشرةً لتعديل شجرة DOM. تعديل الأصناف تتوافق الخاصية "class" مع محددات الصنف في CSS. لا يجب الخلط مع أصناف ES6، وهو نوع خاص من دالات جافاسكربت. تُسْتخدمُ أصناف CSS لتطبيق الأنماط على عناصر متعددة، على عكس المعرفات التي لا يمكن أن توجد إلا مرة واحدة في كل صفحة. في جافاسكربت، لدينا الخاصيتين className و classList للعمل مع الخاصية class. التابع / الخاصية الوصف مثال className قراءة أو كتابة قيمة الخاصية class. element.className; classList.add()‎ إضافة قيمة صنف أو أكثر. element.classList.add('active'); classList.toggle()‎ تبديل صنف محدَّد أي إضافة إن لم يكن موجودًا أو إزالته إن كان موجودًا. element.classList.toggle('active'); classList.contains()‎ تحقق إذا كانت قيمة الصنف موجود. element.classList.contains('active'); classList.replace()‎ استبدال قيمة صنف موجود بقيمة صنف جديد. element.classList.replace('old', 'new'); classList إزالة قيمة صنف. element.classList.remove('active'); سنقوم بإنشاء ملف HTML آخر يحوي عنصرين بعدة أصناف للعمل مع توابع الصنف. الملف classes.html: <!DOCTYPE html> <html lang="en"> <style> body { max-width: 600px; margin: 0 auto; font-family: sans-serif; } .active { border: 2px solid blue; } .warning { border: 2px solid red; } .hidden { display: none; } div { border: 2px dashed lightgray; padding: 15px; margin: 5px; } </style> <body> <div>Div 1</div> <div class="active">Div 2</div> </body> </html> عند فتح الملف classes.html في متصفح الويب، يجب أن تتلقى عرضًا مماثلاً لما يلي: عُرِّفت الخاصيِّة className بهذا الاسم لمنع التعارض مع الكلمة المحجوزة class الموجودة في جافاسكربت وغيرها من اللغات التي لديها إمكانية الوصول إلى شجرة DOM. بإمكانك استخدام className لإسناد قيمة مباشرة إلى الصنف. // div اختيار أول عنصر const div = document.querySelector('div'); // الأول div للعنصر warning إسناد الصنف div.className = 'warning'; أسندنا الصنف warning (تحذير) المعرف في قيم CSS للملف classes.html للعنصر div الأول. ستتلقى المُخْرَجَ التالي: لاحظ أنه في حال وجود أصناف مسبقًا على العنصر، فإن هذا سيؤدي إلى تجاوزها. يمكنك إضافة عدة أصناف بفصلها بمسافة فارغة باستخدام الخاصية className، أو استخدامها دون معاملات الإسناد للحصول على قيمة الصنف في العنصر. الطريقة الأخرى لتعديل الأصناف هي عن طريق الخاصية classList، والتي تأتي مع بعض الدالات التوابع المفيدة. هذه التوابع مشابهة للتوابع addClass، و removeClass، و toggleClass الموجودة في jQuery. // الثاني عن طريق اسم الصنف div اختيار العنصر const activeDiv = document.querySelector('.active'); activeDiv.classList.add('hidden'); // hidden إضافة الصنف activeDiv.classList.remove('hidden'); // hidden إزالة الصنف activeDiv.classList.toggle('hidden'); // hidden إضافة أو إزالة الصنف activeDiv.classList.replace('active', 'warning'); // active مكان الصنف warning تبديل الصنف بعد تنفيذ التوابع أعلاه، ستبدو صحفة الويب الخاصة بك كما يلي: إن استخدام التابع classList.add()‎ سيضيف صنفًا جديدًا إلى قائمة الأصناف الموجودة، على عكس استخدام className. يمكنك أن تضيف عدة أصناف مفصولة بالفاصلة. من الممكن أيضًا استخدام setAttribute لتعديل صنف العنصر. تعديل الأنماط تعتبر الخاصية style من الأنماط المضمنة على عنصر HTML. سيتم تطبيق الأنماط على العناصر عبر ورقة أنماط غالبًا، كما فعلنا سابقًا في هذه المقالة، ولكن في بعض الأحيان يتعين علينا إضافة أو تعديل نمط مضمَّن مباشرة. سنقدِّمُ مثالًا قصيرًا لشرح كيفية تعديل الأنماط باستخدام جافاسكربت. يوجد ملف HTML جديد أدناه بعنصر div يحتوي على بعض الأنماط المضمَّنة فيه مباشرةً. الملف styles.html: <!DOCTYPE html> <html lang="en"> <body> <div style="height: 100px; width: 100px; border: 2px solid black;">Div</div> </body> </html> عند فتح الملف styles.html في المتصفح، سيبدو على الشكل التالي: إحدى طرق تعديل الأنماط هي باستعمال التابع setAttribute()‎. // div إمساك العنصر const div = document.querySelector('div'); // div تطبيق النمط على العنصر div.setAttribute('style', 'text-align: center'); ومع ذلك، سيؤدي إلى إزالة جميع الأنماط الضمنية من العنصر (أي حذف العنصر style السابق بما يحويه وإضافة العنصر الجديد مع القيمة المعطاة). وبما أن هذا ليس هو التأثير المطلوب، فمن الأفضل استخدام الخاصية style مباشرةً بالشكل التالي: div.style.height = '100px'; div.style.width = '100px'; div.style.border = '2px solid black'; تُكْتَبُ خاصيات الـ CSS في حالة أسياخ الشواء (kebab-case)، وهي كلمات بأحرف صغيرة مفصولة بشرطة. لاحظ أنه من المهم معرفة أن حالة أسياخ الشواء لخاصيات الـ CSS لا يمكن استخدامها مع الخاصية style جافاسكربت. بدلاً من ذلك، ستستبدل بمكافئها من حالة سنام الجمل (الحرف الأول صغير وباقي الكلمات متصلة بأحرف كبيرة). بعبارة أخرى، سنستخدم textAlign بدلًا من text-glign في الخاصية style للجافاسكربت. // إلى دائرة وتوسيط النصِّ عاموديًا div تحويل العنصر div.style.borderRadius = '50%'; div.style.display = 'flex'; div.style.justifyContent = 'center'; div.style.alignItems = 'center'; بعد الانتهاء من تعديلات النمط أعلاه، سيظهر الملف styles.html دائرة على الشكل التالي: إذا تم تطبيق العديد من التغييرات المتعلقة بالنمط على عنصر ما، فإن أفضل مسار للعمل هو تطبيق الأنماط على صنف جديد. ومع ذلك، هناك بعض الحالات التي يكون فيها تعديل خاصية النمط المضمن ضروريًا أو أكثر وضوحًا. الخلاصة تحتوي عناصر HTML غالبًا على معلومات إضافية مسندة إليها عبر الخاصيات. قد تتكون الخاصيات من ثنائية الاسم/القيمة، وعدد قليل من الخاصيات الأكثر شيوعًا هي class و style. تعلمنا في هذا الدليل كيفية الوصول إلى خاصيات عنصر HTML ضمن شجرة DOM وتعديلها وحذفها باستخدام جافاسكربت. كما تعلمنا إضافة أصناف CSS وإزالتها وتبديلها واستبدالها في عنصر، وكيفية تحرير أنماط CSS. ترجمة -وبتصرف- للمقال Understanding the DOM — Document Object Model لصاحبته Lisa Tagliaferri
  3. تحدثنا في مقالتين سابقتين عن طريقة الوصول إلى العناصر في DOM و التنقل بين عقد شجرة DOM وتعلمنا كيف يستطيع مطورو الويب استخدام الأصناف، والوسم، والمعرفات لإيجاد عقدة في DOM بالإضافة إلى استخدام خصائص القرابة بين هذه العقد للتنقل فيما بينها بهدف الوصول في النهاية إلى العقدة المطلوبة. الخطوة التالية الآن ستكون احترافية بشكل أكبر حيث سنتعلم طريقة إضافة، وتغيير، واستبدال، وإزالة العقد من DOM. وسنتدرّب على ذلك عبر برنامج قائمة مهام بسيط مع لغة جافاسكربت. سنتعلم في هذه المقالة كيفية إنشاء العقد وإضافتها إلى DOM، واستبدال وإزالة عقد قديمة. إنشاء عقد جديدة في مواقع الويب الثابتة، يتم إضافة العناصر بشكل مباشر من خلال كتابة ملف HTML باللاحقة ‎.html ولكن في تطبيقات الويب الديناميكية المتغيرة باستمرار، تُضَاف العناصر والنصوص بشكل آلي من خلال جافاسكربت باستخدام توابع مثل createElement()‎ و createTextNode()‎ التي تنشئ عقدة جديدة في DOM. table { width: 100%; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } الخاصية / التابع التوصيف createElement()‎ إنشاء عقدة جديدة من نوع عنصر createTextNode()‎ إنشاء عقدة جديدة من نوع نص node.textContent الوصول أو تعديل المحتوى النصي لعقدة العنصر node.innerHTML الوصول أو تعديل محتوى HTML في العنصر لنبدأ أولًا بإنشاء الملف index.html ونقوم بحفظه في مجلد المشروع. <!DOCTYPE html> <html lang="en"> <head> <title>Learning the DOM</title> </head> <body> <h1>Document Object Model</h1> </body> </html> نضغط بالزر الأيمن على أي مكان في الصفحة لتظهر لدينا قائمة نختار منها "Inspect" لفتح أدوات التطوير ثم نختار اللسان Console. سنقوم الآن باستخدام التابع ()createElement الموجود في الكائن document من أجل إنشاء عنصر جديد هو p: > const paragraph = document.createElement('p'); للتأكد من أنه تم إنشاء العنصر p، ندخل التعليمة التالية إلى الطرفية: > console.log(paragraph) حيث سيكون الخرج هو: <p></p> نلاحظ أن المتغير paragraph أعطانا كخرج عنصر p فارغ وهو غير مفيد من دون وجود نص فيه، لذلك سنقوم بإضافة النص من خلال تعديل الخاصية textContent بالشكل التالي: > paragraph.textContent = "I'm a brand new paragraph."; > console.log(paragraph) عندها سيكون الخرج هو: <p>I'm a brand new paragraph.</p> إن استخدام ()createElement و textContent معًا يؤدي إلى بناء عقدة عنصر كاملة. ولكن يمكن أيضًا استخدام تابع بديل لتعديل محتوى العنصر من خلال الخاصيةinnerHTML التي تسمح بإضافة تعليمات HTML ونص عادي إلى العنصر بآن واحد: > paragraph.innerHTML = "I'm a paragraph with <strong>bold</strong> text."; تحذير: إن طريقة استخدام innerHTML شائعة لإضافة محتوى إلى العنصر ولكن سيصبح الموقع عرضة لخطر هجوم cross-site scripting (xxs) والذي يتم من خلال إضافة سطر تعليمة جافاسكربت قد تؤدي إلى ضرر بالموقع باستخدام innerHTML غير مرغوب فيه، لذلك ينصح باستخدام textContent وبالتالي سيتم التخلص من وسوم HTML فورًا. كما أنه من الممكن استخدام التابع createTextNode()‎ لإضافة عقدة نص، كما في التعليمة: > const text = document.createTextNode("I'm a new text node."); > console.log(text) وسيكون الخرج هو بالشكل: "I'm a new text node." إذًا، نستطيع من خلال هذه التوابع إنشاء عقد عناصر ونصوص جديدة، ولكن هذه العقد لن تصبح مرئية في واجهة الموقع حتى يتم إدخالها إلى المستند document. إضافة عقد إلى DOM نحتاج الآن بعد بناء عقد العناصر والنصوص إلى إضافتها إلى document ويتم ذلك من خلال استخدام مجموعة من التوابع مثل appendChild()‎ و insertBefore()‎ لإضافة العناصر في بداية، وسط، أو نهاية عنصر الأب، كما يمكن استخدام التابع replaceChild(‎) لاستبدال عقدة قديمة بأخرى جديدة. الخاصية / التابع التوصيف node.appendChild()‎ إضافة عقدة كابن أخير للعنصر الأب node.insertBefore()‎ إضافة عقدة على نفس مستوى عقدة الأب قبل عقدة الأخ المحددة node.replaceChild()‎ استبدال العقدة الحالة بأخرى جديدة للتمرن على هذه التوابع سنقوم بإنشاء قائمة المهام التالية باستخدام html: Buy groceries Feed the cat Do laundry وعند تحميل الملف السابق إلى المتصفح فإنه سيبدو بالشكل: الآن سنقوم بإضافة عنصر جديد إلى نهاية قائمة المهام، وللقيام بذلك سننشئ عنصرًا ونضيف له نصًّا كما فعلنا في المقطع السابق: > // ليمثل قائمة المهام ul إنشاء عنصر > const todoList = document.querySelector('ul'); > // إنشاء مهمة جديدة أي عنصر قائمة > const newTodo = document.createElement('li'); > newTodo.textContent = 'Do homework'; الأن سنقوم بإضافة هذه المهمة إلى نهاية القائمة باستخدام التابع appendChild()‎: > // إضافة مهمة جديدة إلى نهاية القائمة > todoList.appendChild(newTodo); عند فتح ملف html الخاص بالقائمة، سنلاحظ أنه تم إضافة عنصر li جديد في نهاية ul: <ul> <li>Buy groceries</li> <li>Feed the cat</li> <li>Do laundry</li> <li>Do homework</li> </ul> قد نحتاج لإضافة مهمة جديدة إلى القائمة ولكنها على رأس الأولويات، وبالتالي نحتاج لإضافتها في رأس القائمة. وللقيام بذلك، سنبدأ أولًا بإنشاء عنصر من خلال التابع createElement()‎ ولكنه غير قابل للاستخدام بعد: > // إنشاء مهمة جديدة > const anotherTodo = document.createElement('li'); > anotherTodo.textContent = 'Pay bills'; ولإضافة هذا العنصر إلى رأس القائمة، سنستخدم التابع insertBefore()‎ حيث نمرر لهذا التابع متغيرين الأول هو العقدة الجديدة التي نريد إضافتها والثاني هو العقدة الأخ الذي يأتي مباشرة بعد العقدة الجديدة وسيكون شكل التعليمة كما يلي: parentNode.insertBefore(newNode, nextSibling); الآن، لتطبيق التعليمة السابقة عمليًا على قائمتنا، سنضيف العقدة التي بنيناها سابقًا والمسماة anotherTodo قبل العنصر الأول من أبناء القائمة والذي هو العنصر “Buy groceries”: > // إضافة مهمة جديدة إلى بداية القائمة > todoList.insertBefore(anotherTodo, todoList.firstElementChild); الآن سيصبح شكل ملف todo.html هو: <ul> <li>Pay bills</li> <li>Buy groceries</li> <li>Feed the cat</li> <li>Do laundry</li> <li>Do homework</li> </ul> وعند تحميل الملف السابق على المتصفح سيظهر كمايلي: إذًا تمت إضافة العقدة الجديدة بنجاح لبداية القائمة، وهكذا نكون قد تعلمنا كيفية إضافة عقدة ابن لعقدة أب ولكن يمكننا أيضًا استبدال هذه العقدة الموجودة بعقدة جديدة. لتعديل عقدة موجودة في قائمة المهام، سننشئ أولًا عنصرًا جديدًا: > const modifiedTodo = document.createElement('li'); > modifiedTodo.textContent = 'Feed the dog'; سنقوم بالاستبدال باستخدام التابع replaceChild()‎ الذي يشبه التابع insertBefore()‎حيث يتم تمرير متحولين له الأول هو العقدة الجديدة والثاني هو العقدة المراد استبدالها، حيث أن الشكل العام لهذه التعليمة هو: parentNode.replaceChild(newNode, oldNode); الآن سنقوم باستبدال العنصر الثالث في القائمة بالعنصر الجديد: > // استبدال مهمة موجودة مسبقًا بأخرى > todoList.replaceChild(modifiedTodo, todoList.children[2]); حيث سيتم تلقائيًا تعديل تعليمات ملف html لتصبح بالشكل: <ul> <li>Pay bills</li> <li>Buy groceries</li> <li>Feed the dog</li> <li>Do laundry</li> <li>Do homework</li> </ul> ويصبح شكل صفحة الويب: باستخدام توابع appendChild()‎، و insertBefore()‎، و replaceChild()‎ يمكننا إضافة العناصر إلى أي مكان في DOM. حذف عقد من DOM بما أننا تعرفنا على طريقة إنشاء عناصر وإضافتهم إلى DOM أو تعديل العناصر الموجودة، تبقى لنا الخطوة الأخيرة لإتمامها وهي تعلم كيفية حذف عنصر موجود في DOM. نستطيع حذف العقد الأبناء من العقدة الأب باستعمال التابع removeChild()‎ كما نستطيع حذف العقدة نفسها باستخدام التابع remove()‎. التابع التوصيف node.removeChild()‎ حذف عقدة ابن node.remove()‎ حذف العقدة نفسها بالعودة إلى مثال قائمة المهام السابق، سنحذف عناصر من القائمة بعد الانتهاء منها. مثلًا سنقوم بحذف المهمة "Do homework" الموجودة في نهاية القائمة (أي هي الابن الأخير للقائمة) وذلك باستخدام التابع removeChild()‎: >todoList.removeChild(todoList.lastElementChild); بالعودة لملف html نلاحظ أن عنصر li الأخير قد حُذِف: <ul> <li>Pay bills</li> <li>Buy groceries</li> <li>Feed the dog</li> <li>Do laundry</li> </ul> الآن سنستخدم التابع الآخر وهو remove()‎ والذي يقوم بحذف العقدة نفسها مباشرة: > // Remove second element child from todoList > todoList.children[1].remove(); وبالتالي يصبح ملف html بالشكل التالي: <ul> <li>Pay bills</li> <li>Feed the dog</li> <li>Do laundry</li> </ul> باستخدام التابعين removeChild()‎ و remove()‎، يمكننا إزلة أي عقدة من DOM كما يمكننا استخدام الخاصية innerHTML لإزالة عقدة ابن من العنصر الأب من خلال استبدال الابن بسلسلة نصية فارغة (empty string) بالشكل "" ولكن هذه الطريقة غير مفضلة في الاستخدام. ملخص تعلمنا في هذه المقالة كيفية استخدام الجافا سكربت لإنشاء عقد وعناصر جديدة ثم إضافتها إلى DOM، واستبدال أو حذف العقد والعناصر الموجودة. وبهذا نكون قد تعلمنا طريقة الوصول إلى عناصر DOM والتنقل بين العقد وتعديلها وبالتالي يمكنك البدء بإنشاء واجهة تطيبق ويب باستخدام الجافا سكربت. ترجمة -وبتصرف- للمقالة How To Make Changes to the DOM للكاتبة Tania Rascia
  4. مقدمة تحدثنا في المقال السابق عن البنية الشجرية لـ DOM وعن العقد Nodes المكونة لها وهي عبارة عن كائنات objects من الممكن أن تكون نصوص أو تعليقات أو عناصر. في الغالب يمكن الوصول إلى محتوى DOM من خلال عقد عناصر html، ولمعرفة كيفية الوصول إلى عناصر DOM بشكل احترافي من الضروري امتلاك معلومات كافية عن قواعد وأساسيات css، لذلك سنقوم في هذه المقالة بتعلم كيفية الوصول إلى عناصر DOM من خلال ID والصف class والوسم tag، ومحددات الاستعلام query selectors. نظرة عامة سنستعرض في هذا المقال خمس توابع methods هي: الطرق محدد بناء الجملة يحصل على getElementById() #demo ID getElementsByClassName() .demo Class getElementsByTagName() demo Tag querySelector() Selector (single) querySelectorAll() Selector (all) من المهم عند دراستنا ل DOM أن تقوم بتطبيق الأمثلة على حاسبك للتأكد من فهم جميع المعلومات بشكل جيد. سنبدأ بإنشاء ملف access.html في مجلد المشروع والذي سنقوم بتطبيق جميع أمثلتنا عليه في هذه المقالة. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Accessing Elements in the DOM</title> <style> html { font-family: sans-serif; color: #333; } body { max-width: 500px; margin: 0 auto; padding: 0 15px; } div, article { padding: 10px; margin: 5px; border: 1px solid #dedede; } </style> </head> <body> <h1>Accessing Elements in the DOM</h1> <h2>ID (#demo)</h2> <div id="demo">Access me by ID</div> <h2>Class (.demo)</h2> <div class="demo">Access me by class (1)</div> <div class="demo">Access me by class (2)</div> <h2>Tag (article)</h2> <article>Access me by tag (1)</article> <article>Access me by tag (2)</article> <h2>Query Selector</h2> <div id="demo-query">Access me by query</div> <h2>Query Selector All</h2> <div class="demo-query-all">Access me by query all (1)</div> <div class="demo-query-all">Access me by query all (2)</div> </body> </html> في ملف html هذا نلاحظ أن لدينا العديد من العناصر التي يمكن الوصول إليها من خلال توابع method الخاصة بـ document وعند فتح هذا الملف في المتصفح سيكون مشابه لهذه الصفحة: سنستخدم العديد من التوابع methods التي ذكرناها في المقال سابقًا للوصول إلى العناصر المتاحة في هذا الملف. الوصول للعناصر باستخدام ID أسهل طريقة للوصول إلى عنصر محدد في DOM هو المعرف الخاص بها ID(Identification). حيث يمكن الوصول إلى العنصر من خلال ID باستخدام التابع getElementById() مع العنصر document. document.getElementById(); ولكن للحصول على هذه الخاصية في الوصول إلى العنصر من خلال id يجب أولًا إضافة الصفة id للعنصر. مثلًا سنضيف المعرف demo للعنصر div <div id="demo">Access me by ID</div> الآن في تبويب console سنقوم بالوصول إلى العنصر واسناده للمتحول demoId > const demoId = document.getElementById('demo'); في حال تمرير المتحول demoId إلى تابع log سنحصل على عنصر html كاملًا. > console.log(demoId); سيكون الخرج عندها العنصر كاملًا <div id="demo">Access me by ID</div> للتأكد من وصولنا إلى العنصر الصحيح سنقوم بتغيير حدود العنصر border property إلى اللّون البنفسجي > demoId.style.border = '1px solid purple'; وعند تنفيذ هذه التعليمات سنلاحظ أن حدود العنصر قد تغيرت إلى اللّون البنفسجي: إن الوصول إلى أي عنصر من خلال ID الخاص به هي أكثر طريقة فعالة وسريعة للوصول إلى عنصر ضمن DOM، ومع ذلك هذه الطريقة لديها عدة عيوب وهي أن ID دائمًا يجب أن يكون متفردًا في الصفحة ولذلك لا يمكن الوصول إلا إلى عنصر واحد فقط من خلال التابع getElementById. ولذلك في حال الحاجة إلى إضافة تابع لأكثر من عنصر في الصفحة فإن إضافته باستخدام id سيؤدي إلى تكرار كتابة التابع لكل عنصر على حدى. الوصول للعناصر باستخدام class تستخدم خاصية class للوصول إلى عنصر أو أكثر في DOM وذلك من خلال التابع getElementByClassName() document.getElementsByClassName(); ونستطيع من خلال الخاصية class الوصول إلى أكثر من عنصر، كما في هذا المثال حيث سنعطي لعنصرين نفس اسم الصف demo <div class="demo">Access me by class (1)</div> <div class="demo">Access me by class (2)</div> الآن في تبويبة console سنبني متحول demoClass ونسند له العناصر التي استطعنا الوصول إليها من خلال اسم الصف demo > const demoClass = document.getElementsByClassName('demo'); والآن أصبح بالإمكان الوصول إلى العناصر وتعديلها باستخدام class كما فعلنا في المثال السابق باستخدم ID. سنقوم الآن بتغيير خاصية الحدود border من خلال المتحول demoClass، demoClass.style.border = '1px solid orange'; ولكن ستظهر لنا رسالة خطأ بأنه لا يمكن تحديد العنصر Output Uncaught TypeError: Cannot set property 'border' of undefined والسبب في هذا الخطأ أن المتحول demoClass لايحوي عنصرًا واحدًا فقط وإنما مصفوفة كائنات من هذه العناصر للتأكد من ذلك سنكتب التعليمة التالية لمعرفة عدد عناصر المصفوفة المُسند إلى deomClass console.log(demoClass); والخرج سيكون هو عدد العناصر في المصفوفة Output (2) [div.demo, div.demo] حتى نستطيع الوصول إلى العناصر بشكل صحيح يجب أن نتعامل مع المتحول demoClass على أنه مصفوفة جافا سكربت يتم الوصول إليها من خلال رقم دليل العنصر index number. الآن نستطيع تغيير حدود كل العنصر الأول في المصفوفة باستخدام رقم الدليل 0 demoClass[0].style.border = '1px solid orange'; بشكل عام للوصول إلى العناصر من خلال الصف calss سنقوم بتغيير جميع العناصر التي تمتلك نفس اسم الصف باستخدام حلقة for التي تقوم بالمرور على جميع العناصر التي تحويها المصفوفة for (i = 0; i < demoClass.length; i++) { demoClass[i].style.border = ‘lpx solid orange’; } وعند تنفيذ هذه التعليمات سيصبح شكل صفحة الويب إذًا استطعنا الوصول إلى جميع العناصر التي تمتلك الصف demo وتغيير خاصية حدودها border إلى اللّون البرتقالي. الوصول للعناصر باستخدام Tag طريقة الوصول للعنصر من خلال اسم الوسم html tag name هو أقل الطرق تخصيصًا حيث يمكننا الوصول إلى العديد من العناصر باستخدام تابع getElementsByTagName() document.getElementsByTagName(); سنستخدم كمثال هنا العنصر article للوصول إليه من خلال اسم الوسم، نلاحظ العنصرين الذين يحملان اسم الوسم article <article>Access me by tag (1)</article> <article>Access me by tag (2)</article> وبنفس الطريقة التي وصلنا للعناصر من خلال اسم الصف class فإن التابع getElementsByTagName تعيد لنا مصفوفة array من العناصر حيث يمكن تعديل كل tag في المستند من خلال حلقة for const demoTag = document.getElementsByTagName(‘article’); for (i = 0; i < demoTag.length; i++) { demoTag[i].style.border = ‘1px solid blue’; } وبمجرد تنفيذ هذه التعليمات سيصبح شكل صفحة الويب بالشكل وهكذا قمنا بتعديل خاصية الحدود border لجميع العناصر article إلى اللّون الأزرق. محددات الاستعلام Query Selector في حال كان لديك خبرة سابقة في jQuery API ربما ستكون لديك معرفة سابقة مع توابع jQuery التي تستطيع الوصول لعناصر DOM من خلال محددات css $('#demo'); // returns the demo ID element in jQuery يمكننا الحصول على نفس النتيجة في الجافا سكربت من خلال استخدام التوابع querySelector() و querySelectorAll() document.querySelector(); document.querySelectorAll(); للوصول إلى عنصر واحد نستخدم تابع querySelector. فمثلًا يمكننا الوصول إلى العنصر الذي لديه المعرف demo-query من خلال التابع querySelector() <div id="demo-query">Access me by query</div> حيث نمرر للتابع المعرف id مع إضافة الرمز #، وسنقوم بإسناد العنصر للثابت demoQuery const demoQuery = document.querySelector('#demo-query'); ولكن في حالة استخدمنا التابع السابق مع المحددات التي تعطينا أكثر من عنصر واحد مثل class أو tag فإن querySelector() سيعيد لنا العنصر الأول فقط الذي يتطابق مع الاستعلام، ولكن نستطيع استخدام التابع querySelectorAll() من أجل الحصول على جميع العناصر المتطابقة مع الاستعلام. في مثالنا نلاحظ أن لدينا عنصرين يملكان اسم الصف demo-query-all <div class="demo-query-all">Access me by query all (1)</div> <div class="demo-query-all">Access me by query all (2)</div> إن اسم المحدد للخاصية class يجب أن يسبق بنقطة عند تمريره للتابع querySelectorAll() أي سنمرر في هذا المثال .demo-query-all const demoQueryAll = document.querySelectorAll('.demo-query-all'); باستخدام التابع forEach() يمكننا تطبيق اللّون الأخضر على حدود هذه العناصر deomQueryAll.forEach(query => { query.style.border = ‘1px solid green’; }); تعتبر الفاصلة , في حال وضعناها بين القيم للتابع querySelector() كعملية OR مثلاً إذا قمنا بكتابة التابع بالشكل querySelector(‘div, article’) أي تعني أن يجد لنا العنصر div أو article بغض النظر عمن سيظهر أولًا في الملف. أما في حالة وجود الفاصلة بين القيم للتابع querySelectorAll فإنها تعني العملية AND أي في حال كتبنا التابع querySelectroAll(‘div, article’) فإنها تعني إعادة العناصر التي تحوي القيم articl و div الموجودة ضمن المستند. إن استخدام توابع محددات الاستعلامات يعطينا القدرة العالية في البرمجة للوصول إلى أي عنصر أو مجموعة عناصر ضمن DOM بنفس المحددات التي نستخدمها في ملف css. وفي هذه المقالة يوجد قائمة بجميع المحددات الخاصة بال css التي جمعت بواسطة شبكة مطوري Mozilla. تعليمات الجافا سكربت كاملة سأذكر هنا التعليمات التي كتبناها بلمف access.js بشكل كامل. حيث يمكن إضافة ملف js إلى ملف html قبل إغلاق body. // Assign all elements const demoId = document.getElementById('demo'); const demoClass = document.getElementsByClassName('demo'); const demoTag = document.getElementsByTagName('article'); const demoQuery = document.querySelector('#demo-query'); const demoQueryAll = document.querySelectorAll('.demo-query-all'); // Change border of ID demo to purple demoId.style.border = '1px solid purple'; // Change border of class demo to orange for (i = 0; i < demoClass.length; i++) { demoClass[i].style.border = '1px solid orange'; } // Change border of tag demo to blue for (i = 0; i < demoTag.length; i++) { demoTag[i].style.border = '1px solid blue'; } // Change border of ID demo-query to red demoQuery.style.border = '1px solid red'; // Change border of class query-all to green demoQueryAll.forEach(query => { query.style.border = '1px solid green'; }); وسيكون الشكل النهائي لملف html هو <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Accessing Elements in the DOM</title> <style> html { font-family: sans-serif; color: #333; } body { max-width: 500px; margin: 0 auto; padding: 0 15px; } div, article { padding: 10px; margin: 5px; border: 1px solid #dedede; } </style> </head> <body> <h1>Accessing Elements in the DOM</h1> <h2>ID (#demo)</h2> <div id="demo">Access me by ID</div> <h2>Class (.demo)</h2> <div class="demo">Access me by class (1)</div> <div class="demo">Access me by class (2)</div> <h2>Tag (article)</h2> <article>Access me by tag (1)</article> <article>Access me by tag (2)</article> <h2>Query Selector</h2> <div id="demo-query">Access me by query</div> <h2>Query Selector All</h2> <div class="demo-query-all">Access me by query all (1)</div> <div class="demo-query-all">Access me by query all (2)</div> <script src="access.js"></script> </body> </html> ملخص في هذه المقالة تعلمنا 5 طرق للوصول إلى عناصر html الموجودة في DOM وهي من خلال المعرف ID، الصف class، الوسم html tag name، ومن خلال المحددات selector. التوابع التي يمكن استخدامها للحصول على عنصر أو مجموعة عناصر تعتمد على مدى دعم المتصفح المستخدم لها وعدد العناصر التي تتم معالجتها. والآن يمكنك الوصول إل عناصر html الموجودة في المستند باستخدام الجافا سكربت و DOM. هذه المقالة هي ترجمة للمقالة How To Access Elements in the DOM وكاتبتها Tania Rascia. table { width: 100%; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; }
  5. مقدمة تعلمنا في المقال السابق طريقة الوصول إلى العناصر في DOM عن كيفية استخدام التوابع الملحقة بالكائن document بهدف الوصول إلى عناصر html بإحدى الطرق التالية: معرف العنصر ID، صف العنصر class، اسم الوسم tag name، أو محددات الاستعلام query selectors. كما شرحنا في مقال البنية الشجرية لـ DOM عن العقدة الأب لـ DOM الممثلة بالكائن document، كما تطرقنا إلى شرح مفصل عن العقد الأبناء التي تبنى من خلالها الشجرة وعن أنواعها (العناصر، التعليقات، والنصوص). ولكننا نحتاج غالبًا للانتقال بين عقد شجرة DOM بدون المرور على جميع العقد التي تسبق العقدة المطلوبة، لذلك سنتحدث في هذه المقالة عن كيفية التنقل في شجرة DOM من الأعلى إلى الأسفل وبالعكس، إضافة إلى التنقل بين أفرع الشجرة من خلال باستخدام تعليمات الجافا سكربت و html. الإعداد: لنبدأ أولًا بإنشاء ملف nodes.html والذي يحوي التعليمات التالية: <!DOCTYPE html> <html> <head> <title>Learning About Nodes</title> <style> * { border: 2px solid #dedede; padding: 15px; margin: 15px; } html { margin: 0; padding: 0; } body { max-width: 600px; font-family: sans-serif; color: #333; } </style> </head> <body> <h1>Shark World</h1> <p>The world's leading source on <strong>shark</strong> related information.</p> <h2>Types of Sharks</h2> <ul> <li>Hammerhead</li> <li>Tiger</li> <li>Great White</li> </ul> </body> <script> const h1 = document.getElementsByTagName('h1')[0]; const p = document.getElementsByTagName('p')[0]; const ul = document.getElementsByTagName('ul')[0]; </script> </html> عند فتح هذا الملف من خلال متصفح الانترنت، سنشاهد الصفحة التالية: في صفحة الويب هذه لدينا مستند html يحوي على عدد قليل من العناصر وأساسيات css مرفقة به من خلال الوسم style من أجل تحسين طريقة إظهار العناصر، كما قمنا ببناء عدد قليل من المتحولات باستخدام تعليمات الجافا سكربت والتي ذكرت ضمن الوسم script حيث ستساعدنا بالوصول إلى العناصر. كما نلحظ وجود عنصر واحد من العناصر التالية h1، p، ul لذا يمكن الوصول إليها من خلال الدليل الأول index للتابع getElementsByTagName. عقدة الجذر Root Node يعتبر الكائن doucment العقدة الجذر root node لجميع العقد في DOM. ولكن في الحقيقة كائن document هو إحدى خصائص الكائن window والذي يمكن تعريفه بأنه كائن عام global وذو مستوى عالي top-level object حيث يمثل تبويب المتصفح الذي يظهر فيه صفحة الويب. يمكننا من خلال كائن window أن نصل إلى معلومات عن شريط الأدوات، طول وارتفاع النافذة، الرسائل الظاهرة في المتصفح، والإنذارات، في حين أن كائن document يتضمن كل الأحداث والخصائص الأخرى الموجودة داخل window. يتضمن الجدول المرفق عناصر الجذر التي يمتلكها كل document حتى لو كان ملف html المحمل إلى المتصفح فارغ وهي عبارة عن 3 عقد سيتم إضافتها وتفسيرها في DOM. table { width: 100%; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; } الخاصية العقدة نوع العقدة document #document DOCUMENT_NODE document.documentElement html Element_NODE getElementsByTagName() head Element_NODE querySelector() body Element_NODE وبما أن عناصر html، head، body شائعة جدًا فإنها تمتلك الخصائص الخاصة بها في المستند. سنقوم بفتح تبويب console ضمن أدوات المطورين DevTools حتى نختبر هذه الخصائص الأربع من خلال كتابتها في console ومشاهدة النتائج. كما يمكننا أيضًا اختبار العناصر h1، p، و ul. عقد الآباء Parent Nodes لدينا في DOM ثلاث أنواع من العقد معرفة حسب نوع العلاقة فيها بينها وهي الآباء parents، الأبناء children، والشقيقة siblings. تعرف العقدة الأب parent بأنها أي عقدة تمتلك عقدًا أقل في مستوى level أقل منها في التدرّج الهرمي للـ DOM، أو يمكن تعريفها بأنها العقد الأقرب لعقدة الجذر document. يمكن الوصول دومًا للعقدة الأب بواسطة إحدى الخاصيتين parentNode أو parentElement. Gets Property ParentNode parentNode ParentElementNode parentElement في مثالنا nodes.html نلاحظ أن: html هي العقدة الأب لكل من عقد head، body، و script العقدة body هي العقدة الأب لكل من h1، h2، و ul ولكنها ليست العقدة الأب لـ li لأنها في المستوى الأقل منها بمستويين. يمكننا اختبار طريقة الوصول إلى العقدة الأب التي ذكرناها سابقًا، حيث سنقوم بمعرفة أب العنصر p من خلال الخاصية parentNode، وكما نذكر أننا قمنا ببناء المتحول p في التعليمات السابقة وإسناد القيمة document.getElementsByTagName('p')[0] وللوصول للأب نكتب التعليمة التالية في تبويب console > p.parentNode; وسيكون الخرج: Output ► <body>...</body> ويمكن استعمال parentNode مرتين للوصول إلى جد p. يمكن الاستعانة بالعديد من الخصائص التي تمكننا من الوصول إلى العقدة الأب ولكن يوجد فيما بينها القليل من الاختلافات كما سنبينها الآن > // Assign html object to html variable > const html = document.documentElement; > > console.log(html.parentNode); // > #document > console.log(html.parentElement); // > null إن الأب لأي عقدة هو من نوع عقدة العنصر element nodes بينما لايمكن للعقد من نوع نص أو تعليقات أن تكون أب لأي عقدة أخرى وبما أن العقدة الأب لـ html هي العقدة الجذر document node لذلك نلاحظ أن القيمة المرجعة هي Null في السطر الأخير من التعليمات. بشكل عام إن استخدام الخاصية parentNode شائع أكثر في الانتقال ضمن DOM. العقد الأبناء Children Nodes إن أبناء أي عقدة هي جميع العقد الموجودة في المستوى الذي يليه مباشرة أما العقد الموجود في المستوى الذي يلي مستوى الأبناء تسمى العقد الأحفاد. Gets Property Child Nodes childNodes First Child Node firstChild Last Child Node lastChild Element Child Nodes children First Child Element Node firstElementChild Last Child Element Node lastElementChild إن خاصية ChildNode ستعيد قائمة بأبناء العقدة. على سبيل المثال في ملف nodes.html السابق نلاحظ أن عنصر ul لديه 3 عناصر أبناء من li وبالتالي عند إدخال التعليمة: > ul.childNodes; وسيكون الخرج: Output ► (7) [text, li, text, li, text, li, text] نلاحظ أننا حصلنا على قائمة بأبناء العنصر ul والتي تحوي العناصر li الثلاث التي ذكرناها بالإضافة إلى عُقد النصوص text nodes ويعود السبب في ذلك لأننا كتبنا ملف html بطريقة يدوية ولم يتم توليده بواسطة الجافا سكربت. مع العلم أن كل ما يوجد بين العناصر يعتبره DOM عقدة نص text node، ولكن يعمل تبويب Elements الموجودة في أدوات التطوير الخاصة بالمتصفح DevTools بحذف الفراغات البيضاء من النص وبالتالي لا يعتبرها عقد نصوص. مثلًا إذا حاولنا تغيير لون الخلفية للابن الأول باستخدام خاصية firstChild سنفشل لأن أول عقدة هي نص. > ul.firstChild.style.background = 'yellow'; وستكون رسالة الخطأ هي Output > Uncaught TypeError: Cannot set property 'background' of undefined لذلك فإن الخصائص children، firstElementChild، و lastElementChild وجدت لكي نستطيع الحصول على العقدة من نوع عنصر element node فقط، أي في حال كتابة ul.children سنحصل على مصفوفة تحوي 3 عقد من نوع عنصر هي li. باستخدام الخاصية firstElementChild سنقوم بتغيير لون الخلفية للعنصر الأول li التي هي ابن للعقدة ul > ul.firstElementChild.style.background = 'yellow'; وعند تنفيذ هذه التعليمة سيتغير لون الخلفية عند معالجة شجرة DOM تظهر بعض الخصائص المفيدة للعناصر element properties. في تطبيقات الويب التي تم توليدها باستخدام الجافا سكربت الأكثر احتمالًا، هو استخدام الخصائص التي تختار جميع العقد، وفي هذه الحالة الخطوط والمساحات البيضاء لن تكون موجودة. بالعودة للمثال السابق يمكن استخدام حلقة for ... of من أجل تطبيق اللون الأصفر في الخلف على جميع العناصر الأبناء children. for (let element of ul.children) { element.style.background = 'yellow'; } بتطبيق هذه التعليمات سيظهر اللون الأصفر في خلفية جميع الأبناء وبما أن العنصر p يمتلك نوعي عقد من الأبناء وهي العناصر والنصوص في داخله، فإنه يمكن للخاصية childNodes أن تكون مفيدة في الوصول إلى لهذه المعلومات. for (let element of p.childNodes) { console.log(element); } حيث سيكون الخرج عبارة عن ثلاثة أسطر كل سطر يمثل ابن للعقدة p Output "The world's leading source on " <strong>shark</strong> " related information." إن خاصيتي children و childNode تعيد مصفوفة ولكنها لاتمتلك جميع خصائص وتوابع المصفوفات، ولكنها تظهر بشكل مشابه للمصفوفات في الجافا سكربت. ولكن يمكن الوصول إلى العقد من خلال رقم الدليل index أو من خلال خاصية طول المصفوفة length document.body.children[3].lastElementChild.style.background = 'fuchsia'; التعليمة السابقة هي عبارة عن إضافة اللون الفوشي لخلفية العقدة الابن الأخيرة (li) التابعة للعنصر الابن رقم 3 (ul) والتي هي بدورها ابن للعقدة body. إن استخدام خصائص الأب والابن تساعد في الوصول إلى أي عقدة ضمن شجرة DOM. العقد الشقيقة Sibling Nodes العقد الشقيقة sibling of nodes هي العقد الموجودة في نفس المستوى في شجرة DOM ويمكن أن تكون من أنواع مختلفة من العقد سواء عنصر، نص أو تعليق Gets Property Previous Sibling Node previousSibling Next Sibling Node nextSibling Previous Sibling Element Node previousElementSibling Next Sibling Element Node nextElementSibling إن خصائص العقد الشقيقة تعمل بنفس الطريقة التي تعمل فيها عند العقد الأبناء، حيث نجد مجموعة من الخصائص للتنقل بين العقد بكل أنواعها وهي previousSibling و nextSibling ومجموعة أخرى تساعد على التنقل بين العقد من نوع عناصر فقط وهي previousElementSibling و nextElementSibling. في مثالنا nodes.html سنختار الابن الأوسط للعنصر ul const tiger = ul.children[1]; وبما أننا بنينا DOM الخاص بنا من الصفر وليس بناء على تطبيق ويب باستخدام الجافا سكربت فإننا نحتاج لاستخدام خصائص العناصر الأشقاء للوصول إلى عقد العناصر السابقة واللاحقة مع العلم أن الفراغات البيضاء موجودة في DOM كعقد من نوع text tiger.nextElementSibling.style.background = 'coral'; tiger.previousElementSibling.style.background = 'aquamarine'; وبتنفيذ التعليمات السابقة سنلاحظ أن لون الخلفية عند Hammerhead وGreat White قد تغير ملخص تحدثنا في هذه المقالة عن كيفية الوصول إلى جميع عناصر مستند HTML وكيفية التحرك بين العقد في شجرة DOM من خلال خصائص العقد الأب، الابن، والشقيقة. وبهذا ستكون قادرًا على الوصول إلى أي عقدة ضمن شجرة DOM في أي موقع ويب. هذه المقالة ترجمة للمقالة How To Traverse the DOM للكاتبة Tania Rascia
  6. مقدمة عندما نتكلم عن DOM فإننا نتكلم عن بنية شجرية تحوي العديد من الكائنات objects التي تدعى العقد nodes. لقد تكلمنا في المقال السابق (مدخل إلى DOM) عن تعريف DOM وكيفية الوصول إلى الكائن document وطريقة تعديل خصائصه من خلال console بالإضافة إلى إيضاح الفرق بين ماهية HTML و DOM. في هذه المقالة فسنتحدث عن مصطلحات HTML التي تعتبر قواعد أساسية للتنسيق برمجة موقع الويب الذي يتضمن html، الجافا سكربت ومفاهيم DOM. حيث سنتعلم من خلال هذا المقال كيفية بناء شجرة DOM و كيفية إضافة العقد الخاصة بها Nodes حسب نوعها، أخيرًا سنقوم ببناء برنامج باستخدام الجافا سكربت بدلًا من استخدام console وذلك لتعديل DOM. مصطلحات HTML إن فهم مصطلحات Html و الجافا سكربت تعتبر أمرًا ضروريًا لفهم كيفية العمل مع DOM. ولذلك سنقوم بمراجعة بعض مصطلحات html سنبدأ أولًا بالنظر إلى عنصر html التالي <a href="index.html">Home</a> إن عنصر html السابق a هو عبارة عن عنصر يُضاف لربط صفحة الويب الخاصة بنا بصفحة أو محتوى آخر، في هذا المثال لتحقيق إمكانية الوصول إلى صفحة index.html a هو الوسم tag href هو الصفة attribute index.html هو قيمة الصف home هو النص الذي نضيفه للعنصر كل ماهو موجود بين علامتي <> هو عبارة عن عنصر html سنعمل على صفحة index.html التي بنيناها بالمقالة السابقة <!DOCTYPE html> <html lang="en"> <head> <title>Learning the DOM</title> </head> <body> <h1>Document Object Model</h1> </body> </html> إن الطريقة الأسهل للوصول إلى عنصر عبر الجافا سكربت هي استخدام الصفة id ويمكننا ربط أي عنصر في html بـ id خاص به، فمثلًا سنقوم بإضافة id خاص بالعنصر a في المثال السابق وقيمتها هي nav ... <body> <h1>Document Object Model</h1> <a id="nav" href="index.html">Home</a> </body> ... الآن سنقوم بتحميل إو إعادة تحميل صفحة index.html للتأكد بتعديل DOM الخاص بصفحتنا التي عدلناها. سنستخدم التابع getElementById() للوصول إلى العنصر كاملًا من خلال كتابة التعليمة التالية في تبويبة console document.getElementById('nav'); عندها سيكون الخرج في تبويبة console بالشكل <a id="nav" href="index.html">Home</a> حيث نلاحظ أننا حصلنا على العنصر كاملآ من خلال استخدام تابع getElementById() ، ولكن يمكننا إسناد عنصر html إلى متحول variable للوصول إليه بشكل أسرع من استخدام التابع السابق. let navLink = document.getElementById('nav'); وهكذا أصبح navLink هو عبارة عن متحول يحوي على عنصر a الخاص وبالتالي يمكننا تعديل الصفات attribute التي يحويها وقيمها بسهولة، فمثلًا يمكننا تعديل قيمة الصفة href بالشكل التالي navLink.href = 'https://www.wikipedia.org'; كما يمكننا تعديل المحتوى النصي للمتحول من خلال إعادة إسناد قيمة نصية جديدة للخاصية textContent navLink.textContent = 'Navigate to Wikipedia'; الآن عندما سنستعرض العنصر a إما من خلال console أو من خلال تمرير الفأة على الوسم a سنشاهد كيف تم تعديل العنصر navLink; وسيكون الخرج هو Output <a id="nav" href="https://www.wikipedia.org/">Navigate to Wikipedia</a> كما سنشاهد أن هذه سينعكس على شكل واجهة الموقع ولكن عند تحديث الصفحة سيتم التراجع عن كل التعديلات التي قمنا بها. وبنهاية هذه الفقرة يجب أن نكون قد تعلمنا كيفية التعامل مع توابع document وطريقة الوصول إليها وإسناد العنصر إلى متحول وتغيير الصفات الخاصة بالعنصر من خلال استخدام المتحول المُسند إليه. شجرة DOM والعقد المكونة لها تعرف جميع العناصر التي تنتمي لل DOM كعقد nodes ولها أنواع متعددة لكن يوجد 3 أنواع هي الأكثر استخداما عقد العنصر Element nodes عقد النص Text nodes عقد التعليقات Comment nodes عندما يتم تمثيل عنصر html كعنصر داخل DOM سنشير له بأنه عقدة العنصر element nodes، وأي نص خارج هذا العنصر سنشير له بأنه عقدة النص text node، وأخيرًا التعليقات التي نكتبها داخل html سنشي لها في DOM بأنها عقد التعليقات Comment node. بالإضافة إلى هذه الأنواع الثلاثة تعتبر document بأنها عقدة قائمة بذاتها تسمى document node والتي تعتبر بأنها جذر العقد الأخرى كافة التي يحتويها ملف DOM. إذًا يتضمن DOM بنية شجرية تحوي العديد من القعد المتداخلة والتي غالبًا ما يشار لها بشجرة DOM أو DOM tree وتشبه بنيتها إلى حد كبير بنية شجرة العائلة التي تضمن الآباء، الأبناء والأشقاء وتلك هي الحال أيضًا بالنسبة للعلاقة بين عقد شجرة DOM. لنرى هذه العلاقات بين عقد شجرة DOM بشكل عملي سنقوم ببناء ملف nodes.html والتي يحوي على أنواع العقد الثلات: عقد النص text، التعليقات comment والعناصر element <!DOCTYPE html> <html> <head> <title>Learning About Nodes</title> </head> <body> <h1>An element node</h1> <!-- a comment node --> A text node. </body> </html> عقدة العنصر html هي العقدة الأب parent node أما عقد العناصر head و body فهي عقد أشقاء وأبناء للقعدة html. أما عقدة body فهي تملك 3 عقد أبناء وهي جميعها عقد أخوة، مع العلم أن نوع العقدة لايؤثر على مستواها. ملاحظة: {.underline} عند العمل مع DOM المولد من قبل html فإن كثرة الفراغات المضافة إلى تعليمات html سيؤدي إلى خلق العديد من عقد النصوص text nodes الفارغة. والتي لاتظهر في تبويبة "Elements" الموجودة في DevTools في chrome. تمييز نوع العقدة كل العقد في المستند document تملك نوع مخصص والتي يمكن الحصول عليها من خلال الخاصية nodeType. قامت شبكة مطوري Mozilla بتحديث قائمتها لـ ثوابت نوع العقدة. وسنذكر هنا قائمة بأكثر أنواع العقد الشائعة وكيفية التعامل معها في هذه المقال نوع العقدة القيمة مثال عقدة العنصر ELEMENT_NODE 1 العنصر < body > عقدة النص TEXT_NODE 3 أي نص ليس جزء من العنصر عقدة التعليق COMMENT_NODE 8 < !--- html comment --- > في تبويبة "Elemnets" الموجودة في أدوات المطوريين قد تلاحظ أنه في حال قمت بالضغط على أي عنصر في DOM وتم تظليله فستلاحظ أنه سيظهر بجانبه القيمة ==$0 ولذلك فإن أحد الطرق السهلة للوصول إلى العنصر النشيط من خلال أدوات التطوير هو كتابة $0. في تبويبة "console" الخاصة بالصفحة nodes.html سنقوم بالضغط على أول عنصر موجود في body وهو h1 الآن سنحصل على نوع العقدة المفعلة حاليًا وذلك من خلال الوصول إليها عبر خاصية nodeType لذلك ندخل التعليمة التالية في console $0.nodeType; وسيكون عندها الخرج هو 1 بالشكل التالي Output 1 وجدنا أن الخرج هو 1 المرتبط بالعنصر المختار h1 والذي يشير إلى نوع ELEMENT_NODE. وبتجربة التعليمة السابقة على نص أو تعليق في ملف HTML فإننا سنحصل على الخرج 3 و 8 بالترتيب. كما يمكننا الحصول على نوع العقدة من دون الحاجة إلى تظليل العنصر في DOM قبل معرفته وذلك من خلال التعليمة document.body.nodeType; حيث سيكون الخرج هو 1 أيضًا. بالإضافة إلى الخاصية nodeType، يمكن استخدام الخاصية nodeValue للحصول على القيمة أو التعليق في عقد النص والتعليق، كما أن الخاصية nodeName تساعدنا في الحصول على اسم الوسم الخاص بالعنصر. تعديل DOM باستخدام الأحداث تعرفنا إلى الآن إلى كيفية تعديل DOM من خلال console ولكن هذا التعديل مؤقت فبمجرد تحديث صفحة الويب ستُلغى هذه التعديلات. في المقالة مدخل إلى DOM استخدمنا console من أجل تعديل لون خلفية الشاشة، الآن يمكن الجمع بين ما تعلمناه سابقًا مع المعلومات في هذه المقالة لبناء زر تفاعلي عندما يتم الضغط عليه. بالعودة إلى ملف index.html سنضيف زر من خلال العنصر button ونضيف له id كما أننا سنضيف رابط جديد لملف جافا سكربت موجود في المجلد js/scripts.js <!DOCTYPE html> <html lang="en"> <head> <title>Learning the DOM</title> </head> <body> <h1>Document Object Model</h1> <button id="changeBackground">Change Background Color</button> <script src="scripts.js"></script> </body> </html> يعرف الحدث event في الجافا سكربت بأنه الفعل الذي يقوم به المستخدم كمثال عندما يقوم المستخدم بتمرير الفأرة فوق عنصر، الضغط على عنصر، أو الضغط على زر معين في لوحة المفاتيح. في هذا المثال نريد للزر الذي بنيناه أن ينتظر ويكون مستعدًا لتلقي الفعل من قبل المستخدم من خلال استخدام event listener للزر. أولًا نقوم ببناء ملف scripts.js ونحفظه في مجلد js ثم سنضيف تعليمات الجافا سكربت التي تقوم بإيجاد العنصر وإسناده إلى متحول let button = document.getElementById('changeBackground'); ثم نضيف التابع addEventListener الذي يعمل على جعل الزر ينتظر حتى يتم الضغط عليه من أجل تنفيذ التابع function الذي يقوم بالفعل في هذا المثال الفعل هو تغيير لون الخلفية. ... button.addEventListener('click', () => { // action will go here }); حيث سنكتب داخل التابع function التعليمة الخاصة بتغيير لون الخلفية إلى لون fuchsia ... document.body.style.backgroundColor = 'fuchsia'; حيث ستكون التعليمات بالترتيب كما يلي let button = document.getElementById('changeBackground'); button.addEventListener('click', () => { document.body.style.backgroundColor = 'fuchsia'; }); وحالما نقوم بحفظ هذا الملف وإعادة تحديث ملف index.html ثم الضغط على زر الموجود في الشاشة فإن الحدث event الذي صممناه لتغير لون الخلفية سوف يعمل مباشرة. ملخص في هذه المقالة قمنا باستذكار المصطلحات التي تساعدنا على فهم وتعديل DOM كما تعرفنا على البنية الشجرية لل DOM وأنواع العقد المستخدمة في إنشائها مثل عناصر html، النصوص، والتعليقات. كما قمنا في النهاية بإنشاء سكربت يسمح للمستخدم بتعديل شكل الموقع من دون الحاجة إلى إدخال التعليمات يدويًا إلى تبويبة console. هذه المقالة هي ترجمة للمقالة Understanding the DOM Tree and Nodes وكاتبتها Tania Rascia
  7. dom

    مقدمة إن نموذج تمثيل المستند ك جسم أو كائن Document Object Model والذي يشار له اختصارا ب DOM يعتبر أحد الطرق الأساسية في بناء مواقع متفاعلة فيما بينها، حيث تُعتبر هذه الطريقة واجهة تسمح للغات البرمجة بمعالجة محتوى المواقع وهيكليتها. أحد اللغات المرتبطة بالـ DOM في المتصفحات هي الجافا سكربت وذلك لأنها لغة برمجة تعمل في مواقع الويب من جهة المستخدم client-side. حيث يمكن الاستفادة من مفاهيم DOM في بناء مواقع ويب متفاعلة مثل إضافة عرض صور للموقع من خلال شاشة عرض بطريقة تدوير الصور، أو إظهار لافتة تنبّه المستخدم إلى وقوعه في خطأ عند محاولته إدخال معلومات ناقصة ضمن الحقول المطلوبة، أو التبديل في قوائم التصفح الخاصة بالموقع ويتم تنفيذ هذه العمليات الثلاث من خلال لغة الجافاسكربت ولكن من خلال معالجة DOM. في هذا المقال سنتعلم ماهو DOM وكيفية التعامل معه من خلال تعريف كائن object هو document والتمييز بين أسطر التعليمات المكتوبة بلغة HTML وبين DOM. ملاحظة: لاتعتبر DOM لغة برمجة كما الحال في لغات البرمجة الاعتيادية كالجافا أو الجافا سكربت... حيث يتم تنفيذ وتطبيق مفاهيمها من خلال لغات برمجة أخرى وهنا سنستخدم لغة الجافا سكربت. المتطلبات الأساسية لفهم كيفية تطبيق مفاهم DOM بشكل فعال وتنفيذه في تطبيقات الويب من المهم أن تكون لديك معرفة سابقة بـ HTML و CSS بالإضافة إلى معرفة القواعد الأساسية حول طريقة كتابة تعليمات الجافا سكربت وهيكليتها. ما هي DOM للبدء ببناء أي موقع ويب مهما كان بسيط سنبدأ أولًا بإنشاء مستند HTML، حيث يقوم برنامج المتصفح الذي يستخدمه الزائر لمشاهدة الموقع بتفسير تعليمات html و CSS وتحويلهم إلى المحتوى، الهيكلية والتصميم الذي نشاهده أمامنا في الصفحة النهائية. بالإضافة لذلك يقوم المتصفح ببناء تمثيل للمستند يُعرف بأنه نموذج كائن المستند Document Object Model ويسمح هذا النموذج للجافا سكربت بالوصول إلى المحتوى المُعبّر عنه كنص text أو كعناصر element ضمن المستند ورؤيتها على شكل أغراض objects. ولسهولة فهم هذا المفهوم الجديد سنتعرف عليه من خلال مثال عملي يبدأ بتطوير موقع بسيط وذلك بإنشاء ملف جديد يسمى index.html ثم حفظه ضمن مجلد المشروع project directory <!DOCTYPE html> <html lang="en"> <head> <title>Learning the DOM</title> </head> <body> <h1>Document Object Model</h1> </body> </html> إن أسطر التعليمات السابقة هي أساسيات HTML لبناء موقع ويب. سنستخدم هنا متصفح Chrome ولكن يمكنك الوصول إلى نفس الخرج من خلال المتصفحات الحديثة الأخرى. أولًا سنقوم بفتح ملف index.html الذي قمنا ببنائه من خلال متصفح chrome عندها سيظهر أمامك صفحة ويب فارغة وتحوي فقط عنوان هو "Document Object Model" ومن خلال النقر بالزر اليميني في أي مكان بالصفحة ستظهر لدينا قائمة نختار منها "Inspect" والتي ستفتح لنا على جانب الصفحة أدوات التطوير، سيظهر لدينا DOM تحت تبويب "Elements" في هذه الحالة نلاحظ أن DOM الذي قمنا بإظهاره مطابق تمامًا لتعليمات html التي كتبناها سابقًا لبناء الموقع، وعند تمرير السهم فوق العنصر سنلاحظ أن مايقابله من صفحة الويب المفتوحة أمامنا ستُظلّل باللون الأزرق، كما أن السهم الموجود على جانب كل عنصر يسمح بتوسيع العناصر المكتوبة بالداخل. كائن المستند Document كائن المستند document هو عبارة عن كائن مُدمج يملك عدد من الخصائص properties والطرق methods التي يمكن استخدامها للوصول إلى الموقع وتعديله. لفهم كيفية عمل DOM يجب أولًا فهم كيف تعمل الكائنات objects في الجافا سكريبت، ويمكن ذلك من خلال الإطلاع على مقالة برمجة الكائنات Objects في جافاسكريبت في أدوات التطوير التي أظهرناها سابقًا بجانب ملف index.html ننتقل إلى التبويبة "Console" ونكتب document داخل console ثم نضغظ زر Enter حيث نلاحظ أن الخرج هو نفسه الخرج الموجود في تبويبة "Elements" document; Output #document <!DOCTYPE html> <html lang="en"> <head> <title>Learning the DOM</title> </head> <body> <h1>Document Object Model</h1> </body> إن كتابة المستند document أو العمل مباشرة في تبويب console ليست أمرًا شائعًا نقوم به خارج debugging ولكنه يساعد في ترسيخ مفهوم كائن المستند document وكيفية تعديله ومعرفه العناصر الأخرى المدرجة ضمنه. ماهو الفرق بين DOM وتعليمات HTML حاليًا في المثال السابق الذي طرحناه تبدو لنا DOM كما لو أنها تعليمات HTML نفسها ولكن يوجد أمثلة يقوم فيها المتصفح بتوليد DOM مختلف عن تعليمات HTML مثل: تعديل DOM من خلال تعليمات الجافا سكربت والتي يتم تنفيذها في جانب المستخدم. قيام المتصفح بتصحيح الأخطاء الموجودة في التعليمات HTML المكتوبة سابقًا بشكل تلقائي. سنقوم الآن باكتشاف آلية تعديل DOM من خلال استخدام الجافا سكربت التي تُطبق في جانب المستخدم. أولًا ندخل في console التعليمة document.body; عندها سيكون الخرج: Output <body> <h1>Document Object Model</h1> </body> سنلاحظ هنا أن document هو عبارة عن كائن أما body فهو خاصية property لهذا الكائن لذلك من للوصول إلى هذه الخاصية نكتب اسم الكائن ثم نقطة ثم الخاصية document.body عندها سيكون الخرج هو جميع عناصر body الموجودة في المستند document. نستطيع من خلال console تغيير بعض الصفات الظاهرة في الكائن body في هذا الموقع فمثلًا يمكن تغيير صفات style الخاصية بالـ body مثل تغيير لون الخلفية ويتم ذلك من خلال التعليمة document.body.style.backgroundColor = 'fuchsia'; بعد كتابة هذه التعليمة وإدخالها سنلحظ تغير لون خلفية الموقع للون الفوشيا: بالانتقال إلى تبويبة "Elements" أو من خلال كتابة تعليمة document.body في console مرة أخرى سنلاحظ أن DOM قد تغير Output <body style="background-color: fuchsia;"> <h1>Document Object Model</h1> </body> ملاحظة: رأينا في المثال السابق عند تغيير لون الخلفية أن خاصية لون الخلفية في CSS والذي يكتب بالشكل background-color تمت كتابته بالشكل backgroundColor في الجافا سكربت وبنفس هذا الترتيب فإن أي خاصية في CSS يمكن كتابتها في الجافا سكربت بطريقة camelCase والتي تعني أن الحرف الأول من الكلمة الأولى صغير بينما الحرف الأول من الكلمة الثانية كبير. عند الضغط بالزر اليميني على الصفحة واختيار "View Page Source" سنلاحظ أن التعليمات الظاهرة لاتحوي على الصفة attribute الجديدة للون الخلفية الذي أضفناه من خلال الجافا سكربت وذلك لأن التعليمات الأساسية الموجودة في جانب الخادم Server التي تم بناء الموقع من خلالها لاتتأثر بأي تعليمات كتبت في جانب المستخدم بلغة الجافا سكربت، ولذلك في حال قمنا بتحديث الصفحة فإن الخاصية التي أضفناها ستُلغى. بالنسبة للحالة الأخرى التي ذكرناها عن اختلاف DOM و تعليمات HTML وهي عندما يتم تصحيح الأخطاء المكتوبة في التعليمات source code آليًا من قبل المتصفح، كمثال شائع فإن الوسم tbody يجب أن يرافق الوسم table دائمًا ولكن غالبًا لايقوم المطورون بتضمين هذه الوسوم بالشكل الصحيح ضمن HTML وعندها يقوم المتصفح تلقائيًا بتصيح هذا الخطأ وإضافة الوسم tbody وبالتالي يتم تغيير DOM. بالإضافة إلى ذلك دائمًا يصحح DOM الوسوم التي لايتم إغلاقها. ملخص عرضنا في هذه المقالة تعريف للـ DOM واستطعنا الوصول إلى كائن المستند document باستخدام الجافا سكربت وconsole من أجل تغيير خصائص تابعة للكائن document، كما تعرفنا على الفرق بين HTML و DOM. أما في المقالة التالية سنقوم باستعراض معلومات مهمة عن HTML وشجرة DOM وكيفية التعامل مع عقدها Nodes وماهي الأنواع الشائعة منها. ترجمة بتصرف للمقال Introduction to DOM وكاتبتها Tania Rascia
  8. css 101

    يشرح هذا الجزء من سلسلة تعليم CSS كيف تعمل CSS في المتصفّحات وما الهدف من وجود DOM. سنتعلّم أيضًا كيف نُحلّل مستندًا بسيطًا. فهرس السلسلة: مدخل إلى أوراق الأنماط المتتالية (CSS). آلية عمل تعليمات CSS داخل المتصفحات. (هذا الدرس) المحددات (Selectors) في CSS. كيفية كتابة تعليمات CSS يسهل قراءتها. تنسيق نصوص صفحات الويب باستخدام CSS. التعامل مع الألوان في CSS. إضافة محتوى إلى صفحة ويب باستخدام CSS. تنسيق القوائم (Lists) في CSS. تعرف على الصناديق (Boxes) في CSS. رصف العناصر (Layout) في CSS. الجداول (Tables) في CSS. التعامل مع أجهزة العرض المختلفة والمطبوعات في CSS. كيفية عمل CSS عندما يعرض المتصفّح المستند، فإنّه يجمع محتواه مع معلومات التنسيق، ويُعالج المستند على مرحلتين: يحوّل المتصفّح لغة الرّماز وCSS إلى DOM (اختصارًا لـDocument Object Model). يُمثّل DOM المستند في ذاكرة الحاسوب، ويجمع محتوى المستند مع تنسيقه. يعرض المتصفّح محتويات DOM. تستخدم لغات الرّماز عناصر (elements) لتعريف هيكل المستند. يُحدّد العنصر بوسم (tag)، وهو نص يبدأ بالرّمز ‎<‎ وينتهي بالرّمز ‎>‎. معظم العناصر لها زوجان من الوسوم، وسم في البداية وآخر في النهاية. لكتابة وسم البداية أدرج اسم العنصر بين ‎<>‎، أما وسم النّهاية فيكتب بإضافة ‎/‎ بعد ‎<‎ وقبل اسم العنصر. قد يكون لبعض العناصر وسم بادئ فقط، أو وسم وحيد فيه تأتي ‎/‎ بعد اسم العنصر، وذلك تبعًا للغة الرّماز. قد يكون العنصر أيضًا حاويًا على عناصر آخرى ضمن وسْمَيه الأول والأخير. عليك التأكد من إغلاق الوسوم ضمن العنصر الحاوي. لـDOM بنية تشبه الشجرة، حيث يصبح كل عنصر أو خاصّة أو سلسلة من النصوص في لغة الرماز عقدة (node) في البنية الشجريّة. تُحدّد العُقد بعلاقتها بالعقد الأخرى، فبعض العناصر هي آباء (parent nodes) لعناصر آخرى (children nodes)، وقد يكون للأبناء إخوة (sibling nodes). يُعينك فهم DOM على تصميم وتنقيح وصيانة CSS، لأنّه يمثّل نقطة التقاء CSS مع محتوى المستند. مثال يُنشئ الوسم ‎<p>‎ ونظيره ‎</p>‎ عنصرًا حاويًا: <p> <strong>C</strong>ascading <strong>S</strong>tyle <strong>S</strong>heets </p> في هيكل DOM، تُعتير العقدة P أبًا، أبناؤه هي العقد STRONG والعقد النصيّة، وبالمثل فإنّ العقد STRONG آباء للعقد النّصيّة. ├─STRONG │ └─"C" ├─"ascading" ├─STRONG │ └─"S" ├─"tyle" ├─STRONG │ └─"S" └─"heets" تدريب: تحليل DOM باستخدام أداة فحص DOM لتحليل هيكل DOM، نحتاج إلى برنامج خاصّ، بإمكانك استخدام إضافة DOM Inspector من Mozilla لتحقيق ذلك. ما عليك إلا تثبيت الإضافة (المزيد من التفاصيل أدناه). استخدم متصفح Mozilla لفتح مستند HTML الذي أنشأته. من قائمة المتصفّح اختر: أدوات > DOM Inspector أو أدوات > تطوير الويب > DOM Inspector. تفاصيل أكثر إن لم يحوِ متصفح Mozilla عندك على أداة فحص DOM، فبإمكانك تثبيت الإضافة من موقع الإضافات وإعادة تشغيل المتصفح ثم العودة لهذا الدّرس. إن لم ترغب بتثبيت هذه الإضافة (أو لم تكن تستعمل متصفح من Mozilla)، بإمكانك استخدام Web X-Ray Goggles كما هو مشروح في القسم التالي. بإمكانك أيضًا تجاوز هذا القسم والمتابعة. في أداة فحص DOM، وسّع عقد المستند بالنقر على الأسهم. ملاحظة: قد تؤدي المسافات في ملف HTML إلى عرض عقد نصية فارغة، يمكنك تجاهلها. يبدو جزء من النتيجة مشابهًا لما يلي، تبعًا للعقد الّتي وسّعتها: │ ▼╴P │ │ │ ▼╴STRONG │ │ └#text │ ├╴#text │ ►╴STRONG │ │ عندما تختار أيّة عقدة، بإمكانك استخدام اللوحة على يمين DOM Inspector للاطّلاع على معلومات إضافية عنها، فمثلًا: يعرض DOM Inspector النص في اللوحة على اليمين عندما تحتار عقدة نصيّة. عندما تختار عقدة تمثّل عنصرًا، تُحلّل الأداة هذه العقدة وتقدّم معلومات كثيرة في اللّوحة على اليمين، يكون من ضمنها معلومات التنسيق. تمرين انقر على عقدة من نوع STRONG في أداة فحص DOM، ثم استخدم اللوحة على اليمين لإيجاد الموضع الّذي يُعيّن فيه لون العقدة إلى أحمر، والموضع الّذي يُجعل فيه خطّها أعرض من النصّ العاديّ. شاهد الحل في القائمة فوق اللوحة على اليمين، اختر CSS Rules، سترى عنصرين مُدرجين، أحدهما هو المصدر الداخلي الّذي ي يُعرّف font-width على أنّها bolder، والآخر آتٍ من ورقة الأنماط الّتي تُحرّرها والّذي يُعرّف color على أنّه red. استخدام Web X-Ray Goggles تعرض الأداة Web X-Ray Goggles معلومات أقل من DOM Inspector، ولكنّها أبسط في التثبيت والاستعمال: اذهب إلى الصّفحة الرئيسيّة للأداة. اسحب رابط العلامة المرجعيّة إلى شريط المتصفّح. افتح مستند HTML الّذي أنشأته. فعّل الأداة بالنقر على العلامة المرجعيّة في الشّريط. اسحب مؤشّر الفأرة فوق العناصر المختلفة في المستند. تتالي الأنماط ووراثتها سنتعلّم الآن كيف تتفاعل الأنماط المتتالية، وكيف ترث العناصر الأنماط عن آبائها، وكيف تضيف الأنماط إلى ورقة الأنماط مستفيدًا من فكرة الوراثة بحيث تغيّر تنسيق عدة أجزاء من المستند مرّة واحدة. قد يُحدّد النّمط النّهائي للعنصر في عدّة مواضع، تتفاعل فيما بينها بطريقة مُعقّدة، وهذا التّفاعل المعقّد يُعطي CSS قدراتها المُميّزة، ولكنّه قد يُعقّد الأمور ويجعل تتبّع الأخطاء عمليّة صعبة. تجتمع المصادر الثلاثة الأساسية لمعلومات التنسيق مشكّلة ما نسمّيه تعاقب الأنماط (cascade)، وهذه الأنماط هي: التنسيقات المبدئيّة الّتي يحدّدها المتصفّح للعناصر في لغة الرّماز. التنسيقات الّتي يحدّدها المستخدم الّذي يقرأ المستند. التنسيقات المرتبطة بالمستند الّتي يحدّدها مؤلّفه، والّتي قد تعيّن في ثلاثة مواضع: في ملفّ خارجيّ: وهذا الموضوع الأساسيّ لهذه الدّروس. في تعريف في بداية المستند: للتنسيقات الخاصّة بصفحة واحدة فقط. في عنصر معيّن ضمن متن المستند: وهي الطريقة الأقل سهولة في الصيانة، ويمكن استخدامها على سبيل التّجربة. تُغيّر أنماط المستخدم الأنماط الّتي يعيّنها المتصفّح، ثمّ تغيّر أنماط مؤلّف المستند تلك الّتي عيّنها المستخدم. في هذه السّلسلة أنت مؤلّف المستند، ولن نتعامل إلّا مع هذا النّوع من الأنماط. مثال عندما تقرأ هذا المستند في متصفّح، يأتي جزء من التنسيق الّذي تراه من الإعدادات المبدئيّة لـHTML في المتصفّح. وقد يأتي جزء آخر من الإعدادات المخصّصة للمتصفّح، إذ يمكن تخصيصها في مربع التفضيلات في Firefox مثلًا، أو يمكن تعيينها في ملف userContent.css في ملفّ المتصفّح الشّخصيّ. ويأتي الجزء الأخير من التنسيق من خادوم موقع الأكاديميّة. عندما تفتح المستند الّذي تتدرّب عليه في المتصفّح، تكون العناصر <strong> أعرض خطًّا من بقيّة النّصّ، هذا التنسيق يأتي من إعدادات المتصفّح المبدئيّة. كما أن العناصر نفسها ذات لون أحمر، وهذا التنسيق يأتي من ورقة الأنماط الّتي كتبناها بأنفسنا. ترث عناصر <strong> أيضًا معظم تنسيقها عن عناصر <p> لأنّها أبناؤها، وبالمثل ترث العناصر <p> معظم تنسيق عنصر <body>. يكون للتنسيقات الّتي يحدّدها مؤلّف المستند الأولويّة في تعاقب الأنماط على تلك الّتي يحدّدها القارئ، وتكون الأولويّة الأقل لتنسيقات المتصفّح المبدئيّة. بالنّسبة للتنسيقات الموروثة، يكون للتنسيقات المعرّفة على العقدة ذاتها الأولويّة على تلك الّتي ترثها عن آبائها. هناك قواعد أخرى لهذه الأولويّات، سنتعرّف عليها لاحقًا. تفاصيل أكثر توفّر CSS أيضًا طريقة للقارئ لحجب التنسيق الّذي يحدّده مؤلّف المستند باستخدام الكلمة !important. وهذا يعني أنّه لا يمكن توقّع الشّكل الّذي سيكون عليه المستند لكلّ قارئ. إذا أردت معرفة المزيد عن موضوع التعاقب والوراثة، انظر فقرة Assigning property values, Cascading and inheritance في تعريف CSS. تمرين: استخدام الوراثة حرّر ملفّ CSS الّذي تتدرّب عليه. أضف هذا السّطر بنسخه ولصقه. لا يهمّ إن كان فوق أو تحت السّطر الّذي أضفته من قبل. إلّا أن إضافته فوقه أكثر منطقيّة لأن العنصر <p> أب للعنصر <strong> في مستندك. p {color: blue; text-decoration: underline;} احفظ الملفّ وحدّث متصفّحك لتشاهد تأثير ذلك على المستند. يؤدّي ذلك إلى تسطير النّص في كامل الفقرة، بما في ذلك الحروف الأولى من كلّ كلمة، وهذا يعني أن العناصر <strong> ورثت عن أبيها نمط تسطير النّصّ. ولكّن هذه العناصر ما تزال حمراء اللّون، لأنّ اللون الأحمر هو نمطها الخاص، ولذا يكون له الأولويّة على اللّون الأزرق لأبيها العنصر <p>. قبل <p> <strong>C</strong>ascading <strong>S</strong>tyle <strong>S</strong>heets </p> strong {color:red} بعد <p> <strong>C</strong>ascading <strong>S</strong>tyle <strong>S</strong>heets </p> p {color:blue; text-decoration:underline} strong {color:red} تمرين عدّل ورقة الأنماط بحيث تكون الحروف الأولى فقط مُسطَّرة: شاهد الحل انقل التصريح الذي يُعنى بتسطير النّص من قاعدة <p> إلى <strong>، كما يلي: p {color: blue; } strong {color: orange; text-decoration: underline;} ما التالي؟ سنتعرّف في الدّرس التالي كيف نستهدف العناصر بطريقة أكثر انتقائيّة. ترجمة -وبتصرف- للمقال How CSS works من سلسلة Getting started with CSS على شبكة مطوّري Mozilla.
  9. توفّر 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.