اذهب إلى المحتوى

ابراهيم الخضور

الأعضاء
  • المساهمات

    164
  • تاريخ الانضمام

  • تاريخ آخر زيارة

آخر الزوار

5154 زيارة للملف الشخصي

إنجازات ابراهيم الخضور

عضو نشيط

عضو نشيط (3/3)

65

السمعة بالموقع

  1. تحدثنا في المقالات السابقة عن اﻷسس والمفاهيم التي يجب استيعابها لتكوين الدوائر اﻹلكترونية والتعامل معها وإجراء بعض القياسات الكهربائية فيها. كما تعرّفنا على عناصر إلكترونية سميناها فعّالة لأنها تزوّد الدوائر بالطاقة أو تستهلك الطاقة لأداء عملها مثل البطاريات والترانزيستورات وأخرى سميناها ساكنة لأنها تبدد الطاقة أو تمررها فقط. ورأينا أن تنفيذ أية دائرة إلكترونية لها وظيفة محددة يمر بمرحلتين أساسيتين: اﻷولى: فهم الوظيفة المطلوبة وتصوّر طريقة تنفيذها. الثانية: اختيار العناصر اﻹلكترونية المناسبة وربطها بالطريقة الصحيحة ﻹنجاز الوظيفة. وقد يخطر لك السؤال التالي: "ماذا لو أردت أن أكرر هذه الوظيفة في عدة أماكن مختلفة من الدائرة؟" كأن احتاج عدة مؤقتات زمنية لمراقبة أشياء مختلفة، هل سأكرر الدائرة الكهربائية نفسها مرات عدة ثم أضيفها إلى الدائرة اﻷساسية أم ماذا؟ الجواب على هذا السؤال هو نعم وليس بالضرورة! نعم أي لا بد في الدائرة اﻹلكترونية من تكرار العناصر التي تؤدي وظيفة ما إن أردت استنساخ هذه الوظيفة أكثر من مرة، وليس بالضرورة لوجود شيء أبسط يحوّل هذه العناصر جميعها إلى عنصر واحد ضمن إطار فيزيائي واحد ندعوه دائرة متكاملة Integrated circuit. ما تحتاجه لإكمال التمارين العملية في هذا المقال إليك قائمة بالعناصر الإلكترونية والتجهيزات اللازمة لإكمال التطبيقات العملية: بطارية جهدها 5 فولط. مقاومات قيمها 1.2، 2.2، 10، 22 كيلو أوم. الدائرة المتكاملة NE555 (واحدة تكفي). الدائرة المتكاملة المنظمة للجهد 7805 (واحدة تكفي). المتحكم الصغري PIC16F84A (اختياري لمجرّد التعرف على شكله وتوزع أرجله وقراءة أرقامها). مؤشرات ضوئية (ليد) تعمل عند جهد 5 فولط أو أقل (ثلاثة تكفي). مكثفات سعتها 47 ميكرو فاراد وأخرى 1 ميكرو فاراد جهدها 16 فولط. مكثفات عدسية 20 نانو فاراد (اختيارية إن أردت توصيل دائرة المتحكم الصغري). هزاز كريستالي تردده 2 ميجا هرتز (اختياري لتوصيل دائرة المعالج الصغري). ديودات من طراز 1N4007 (يكفي اثنان). ترانزستورات قطبية من الطراز 2N2222. لوحة اختبار مثقبة (إن أردت فاﻷمر اختياري). مقياس كهربائي متعدد الوظائف AV multi-meter. الدائرة المتكاملة الدائرة المتكاملة Integrated circuits هي دائرة إلكترونية مخصصة ﻷداء وظيفة واحدة أو عدة وظائف، وتتكون ضمنًا من مجموعة من العناصر اﻷساسية مثل الترانزستورات والمكثفات والمقاومات التي تقوم بالعمل المطلوب. توضع هذه العناصر ضمن غلاف مغلق لا يظهر منه إلى العالم الخارج سوى أرجل معدنية تربط الدائرة المتكاملة بالعالم الخارجي. وقد يخطر في بالنا السؤال التالي: إن كانت الدائرة المتكاملة مكوّنة من نفس العناصر الأساسية التي نستخدمها فما فائدتها إذًا؟ إليك الجواب: حجم أصغر بكثير: تخيل أن الدائرة ستتكون من 12 ترانزيستور و10 مقاومات و3 مكثفات، ما الحجم الذي تشغله هذه العناصر مهما كان تصنيعها جيدًا وطريقة توصيلها احترافية؟ بالتأكيد ستشغل حجمًا لا بأس به. لكن إن صُنّعت ضمن دائرة متكاملة فقد لا تتجاوز أبعادها عدة ملليمترات في كل اتجاه. موثوقية أكبر بكثير: لربما قد لا حظت عند محاولتك تجريب التمارين التطبيقية التي طرحناها في المقالين السابقين صعوبة التوصيلات في بعض اﻷحيان أو هفوات صغيرة تُفقدك أعصابك قبل معرفة المشكلة، فما بالك بالدوائر التي يجب أن تؤدي وظيفتها بكل دقة؟ تضمن طريقة التصنيع المتبعة في الدوائر المتكاملة توصيلات غاية في الدقة وترتيبًا مثاليًا للعناصر إضافة إلى اﻷحجام الصغيرة جدًا لهذه العناصر. التعامل مع أرجل الدائرة دون الحاجة لأية تفاصيل تصميمية: لا حاجة لأن تعرف العناصر التي تتكون منها الدائرة اﻹلكترونية وكيف رُتبت، فما تتعامل معه فقط هي اﻷرجل التي يحدد صانعو الدائرة وظيفة كل منها وكيفية وصلها. ولا تخلو فكرة الدوائر المتكاملة من عيوب تتعلق بعدم القدرة على تصنيع دوائر متكاملة تتعامل مع استطاعات كهربائية كبيرة، وقدرتها المحدودة على التخلص من الحرارة الناتجة عن تشغيلها لصغر حجمها، و حساسيتها العالية للضجيج -وهي إشارات غير مرغوبة تصل إليها عن طريق التغذية أو اﻷجهزة المحيطة-. أنواع الدوائر اﻹلكترونية المتكاملة للدوائر اﻹلكترونية أنواع مختلف وتصنف عادة ضمن ثلاثة فئات واسعة: دوائر متكاملة تماثلية: وتتعامل مع قيم تماثلية تطبيق على أرجل الدخل وتعطي قيمًا تماثلية على أرجل الخرج نذكر منها دوائر منظمات الجهد الكهربائي ودارات قياس درجات الحرارة. دوائر متكاملة رقمية: وتتعامل مع قيم رقمية في دخلها وخرجها، نذكر منها المعالجات المصغّرة Microprocessor في الحواسب. تُبنى هذه الدوائر باستخدام ترانزستورات قطبية فتعرف عندها بعائلة TTL وباستخدام ترانزستورات حقلية MOSFET فتعرف باسم CMOS. دوائر رقمية تشابهية: تتعامل مع قيم رقمية في مداخلها وتعطي قيمًا تماثلية على المخارج أو العكس أو كلاهما (تتعامل مع الرقمي والتماثلي في الدخل والخرج)، نذكر منها الدوائر التي تحول درجات الحرارة مثلًا إلى أرقام وكذلك دوائر المتحكمات الصغرية micro-controller التي سنتحدث عنها في الفقرات القادمة. تغليف الدوائر المتكاملة عندما تُصنع الدوائر المتكاملة تظهر أرجلها إلى العالم الخارجي من حواف غلاف بلاستيكي أسود اللون عادة، وتُكتب عليه معلومات عن الشركة الصانعة وتاريخ الصنع ورقم الدائرة المميز ولواحق تتعلق بطريقة التغليف ومجالات العمل وغيرها وتختلف طريقة الترميز من شركة لأخرى لكن رقم الدائرة يبقى كما هو. أشكال أغلفة الدوائر المتكاملة تكون الأغلفة مستطيلة أو مربعة، وتخرج منها اﻷرجل وفق ترتيب محدد وتباعد محدد، وتصنف إلى: أغلفة من النوع DIP: وتكون مستطيلة تخرج اﻷرجل الطرفين بشكل متناظر. أغلفة من النوع SOP: وتكون مستطيلة أو مربعة، تخرج اﻷرجل من طرفيها وتكون صغيرة على شكل حرف L ومتقاربة من بعضها. أغلفة من النوع QFT: وتكون مربعة وصغيرة الحجم ومسطحة، تخرج اﻷرجل على شكل حرف L من جميع أطرافها. أغلفة من النوع BGA: وتكون مربعة الشكل وليس لها أرجل، بل يكون الخرج والدخل على شكل نقاط نافرة أسفل الدائرة وموزعة على صفوف في كل اﻷطراف. ترقيم أرجل الدوائر المتكاملة لكل رجل من أرجل الدائرة المتكاملة عمل محدد كأرجل تغذية وأرجل تأريض وأرجل دخل وخرج. ولكل رجل أيضًا رقم محدد، ويبدأ الترقيم بالرقم 1 وهي الرجل التي يقع إلى يسار حفرة الدائرية موجودة على سطح الغلاف يليه للأسفل الرقم 2 ثم تتزايد أرقام اﻷرجل بعكس جهة دوران عقارب الساعة. تطبيق عملي: تنظيم الجهد باستخدام الدائرة المتكاملة 7805 نحتاج في كثير من التطبيقات إلى مصدر جهد ثابت لا يتغيّر ودون ضجيج كي يستقر عمل الدائرة اﻹلكترونية. لهذا نستخدم نوع خاص من الدوائر التكاملية التي تُدعى بمنظمات الجهد ومنها الدائرة 7805. تعطي هذه الدائرة في خرجها جهدًا موجبًا مستقرًا قدره 5 فولط وتقدم تيارًا أعظميًا شدته 1.5 أمبير على أن يكون جهد مصدر التغذية الذي نريد تنظيمه أعلى من جهد الخرج بحدود 2 إلى 3 فولط. للدائرة 7805 ثلاثة أرجل مع خلفية معدنية لربطها مع جسم معدني أو مبدد حراري إذا كان التيار المستجر عبرها عاليًا لتخفيض الحرارة الناتجة عن عملها. فإذا أمسكتها بحيث تكون في مواجهتك تكون الرجل اليسارية هي رجل جهد الدخل الذي تريد تنظيمه والوسطى رجل التأريض واليمينة رجل الخرج التي تعطينا 5 فولط. شكّل الدائرة البسيطة التالية: صل رجل الدخل إلى المسرى الموجب للوحة المثقبة ثم صل معه القطب الموجب لمكثفة 1 ميكروفاراد ومهبط الديود. صل الرجل اﻷخرى للمكثفة مع المسرى السالب ومصعد الديود مع رجل الخرج. صل الرجل الوسطى مع المسرى السالب. صل رجل الخرج مع الرجل الطويلة للمؤشر الضوئي وصل رجله اﻷخرى مع رجل مقاومة 2.2 كيلو أوم والرجل اﻷخرى للمقاومة مع المسرى السالب. صل قطبي البطارية 8 فولط إلى المسريين الموجب والسالب للوحة المثقبة. استخدم مقياس اﻵفو لتحديد الجهد بين المسرى السالب و رجل الخرج للدائرة 7805 ماذا تجد؟ الدوائر المتكاملة القابلة للبرمجة تُعرّف عملية البرمجة في اﻹلكترونيات عمومًا بأنها طريقة تحديد وظيفة العنصر اﻹلكتروني والطريقة التي يتواصل فيها مع الدائرة المحيطة به. وكما ذكرنا قبل قليل أن الدوائر اﻹلكترونية المتكاملة قد تشتمل على عدة وظائف وعندها تكون برمجة هذه الدائرة هو تحديد الوظيفة التي نريدها أن تؤديها من بين وظائف عدة. وللبرمجة في عالم اﻹلكترونيات تصنيفان أساسيان: برمجة فيزيائية: نحدد فيها وظيفة الدائرة اﻹلكترونية بتغيير طريقة توصيلها مع الدائرة المحيطة، أي تفرض على الدائرة المتكاملة وظيفة معينة وفقًا لطريقة توصيل أرجلها مع عناصر إلكترونية أخرى محددة. وأغلب الدارات المتكاملة التماثلية متعددة الوظائف تبرمج بهذا الشكل. برمجة بالشيفرة: وفيها تُكتب برمجيات رقمية خاصة خارج هذه الدائرة ثم تنقل إليها، وقد تكون هذه البرمجيات دائمة أي تحمََّل مرة واحدة ولا يمكن تعديلها لاحقًا مثل الدائرة التكاملية التي تُحمّل برمجيات إقلاع الحاسب BIOS، ومن الممكن أيضًا تغيير هذه البرامج وتعديلها في أي وقت كما في الدوائر المتكاملة التي تُدعى المتحكمات الصغرية. تُدعى البرمجيات التي تُحمّل إلى الدوائر المتكاملة "برمجيات قيادة Firmeware" وتكتب باستخدام لغات برمجة منخفضة المستوى عادة، ويمكن استخدام لغات برمجة عالية المستوى مثل C++,C, بايثون. تطبيق عملي: البرمجة الفيزيائية للدائرة المتكاملة 555 تُصنف الدائرة 555 ضمن فئة المؤقتات أو الهزازات التي يتأرجح دخلها بين قيمة عليا (قيمة وصل) هي قيمة جهد تغذية الدائرة وقيم دنيا (قيمة فصل) هي 1.2 فولط وفقًا لطريقتي برمجة فيزيائية: اﻷولى تُدعى الوضع الوحيد الاستقرار وفيه تعمل الدائرة كمؤقت إذ تُبرمج كي يكون الخرج موصولًا لفترة زمنية محددة. الثانية: تُدعى الوضع غير المستقر وفيه يُبرمج الخرج كي يتبدل بين الفصل والوصل خلال أزمة محددة لكل حالة. تتكون الدائرة 555 من ثمانية أرجل، لا حاجة حاليًا لشرح وظيفة كل رجل، وما سنستعرضه هي طريقة برمجة الدائرة كي تعطي الوظيفتين السابقتين. لهذا استخدم العناصر التي أشرنا إليها سابقًا لتشكيل الدائرة التالية: برمجة الوظيفة الأولى: ضع الدائرة 555 لتكون أرجلها ضمن نصفين مختلفين للوحة المثقبة ثم صل الرجل رقم 1 (اﻷرضي) بالمسرى السالب والرجلين 8 (تغذية) والرجل 4 بالمسرى الموجب. صل الرجل رقم 7 بمقاومة R1 قيمتها 22 كيلو أوم ورجلها الثانية بالمسرى الموجب. صل الرجل رقم 2 بالرجل 6 بسلك ثم صلهما بالرجل الموجبة لمكثفة C1 قيمتها 47 ميكروفاراد وصل رجلها السالبة بالمسرى السالب. صل بمقاومة R2 قيمتها 22 كيلو أوم نقطة التقاء المقاومة 22 كيلو أوم والرجل 7 مع نقطة التقاء الرجل 6 والمكثفة. صل الرجل 5 إلى مكثفة 1 ميكروفاراد وصل رجلها السالبة باﻷرضي (بإمكانك تجاهل هذه الحركة حاليًا). صل أخيرًا رجل الخرج رقم 3 من خلال مقاومة 10 كيلو أوم بقاعدة الترانزستور وانتبه إلى أن يكون بعيدًا عن ثقوب الدائرة 555 ثم صل باعثه إلى المسرى السالب من خلال مقاومة 2.2 كيلو أوم وصل مؤشر ضوئي بين مجمّعه والمسرى الموجب. صل بطارية 8 فولط إلى المسريين الموجب والسالب للوحة المثقبة، وراقب ما يحدث. ستلاحظ كيف يضيء وينطفئ المصباح بشكل منتظم وباستمرار طالما أن الدائرة موصولة بالتغذية الكهربائية وتُبرمج فترتي اﻹضاءة والتوقف من خلال تحديد قيم المقاومتين R1 و R2 وسعة المكثفة C1 وفق المعادلتين البسيطتين التاليتين: t(off) = 0.0069xC1xR2 ..............(زمن الفصل بالثانية) t(on)= 0.0069xC1x(R1+R2)..........(زمن التوصيل بالثانية) برمجة الوظيفة الثانية: اتبع نفس الخطوات السابقة لكن لا تصل الرجل 2 بالرجل 6 بل اجعل السلك موصولًا بالرجل 2 وحرًا من الطرف اﻵخر. ضع السلك الموصول بالرجل 2 (رجل القدح) بالمسرى السالب للحظة ثم اخرجه وسترى أن الضوء يضيئ مدة زمنية محددة ثم ينطفئ، وتبرمج هذه المدة من خلال تحديد قيمة المقاومة R1 والمكثفة C1 وفق المعادلة التالية: t= 0.001xR1xC1.......(زمن الوصل بالثانية) المتحكمات الصغرية والدوائر المتكاملة المبرمجة بالشيفرة المتحكمات الصغرية هي دائرة عالية التكامل متعددة الوظائف من النوع الرقمي أو الرقمي-التشابهي المختلط. وهي دوائر قابلة للبرمجة بالشيفرة وبالتالي لابد أن تكون المتحكمات قادرةً على قراءة الشيفرة وتنفيذها. تُعد هذه الدائرة بمثابة حاسوب حقيقي لكنه مصغّر ومحدود اﻹمكانية وينقصه فقط لوحة مفاتيح وشاشة عرض (وفي الواقع يمكن وصل شاشات ولوحات مفاتيح خاصة إليه وبرمجته ليتواصل معهما). يمكن للمتحكمات الصغرية التعامل مع القيم التماثلية التي تأتيه من الوسط الخارجي، مثل قراءة درجات الحرارة عبر وصله بحساسات مناسبة، كما يمكنه التحكم بأجهزة تماثلية مثل التحكم بمحركات التيار المستمر. ولهذا نجد أن المتحكمات الصغرية هي غالبًا الدماغ الذي يقود الروبوتات. وإضافة إلى القيم التماثلية فهو قادر على فهم اﻹشارات الرقمية والمنطقية وقادر على التخاطب الرقمي مع الوسط الخارجي. البنية العامة للمتحكم الصغري يتكون المتحكم الصغري أيًا يكن نوعه أو الشركة المصنعة له من مكوّنات بنيوية أساسية هي: وحدة معالجة مركزية CPU وهي المسؤولة عن تنفيذ العمليات الرياضية والحسابية. وحدة إدارة الذاكرة (الكتابة والقراءة منها) بشقيها ذاكرة الوصول العشوائي RAM التي تُستخدم أثناء تنفيذ الشيفرة وذاكرة القراءة فقط ROM التي تخزن شيفرة البرنامج. وحدة إدارة الدخل والخرج. منافذ دخل وخرج. دوائر توقيت. ساعة داخلية. مبدلات رقمية تماثلية والعكس لتحويل كل منهما إلى اﻷخرى حسب الحاجة. وحدة وحدات قادر على الاتصال مع التجهيزات الخارجية وفق معايير مشتركة بين هذه العناصر (بروتوكولات نقل). لن نهتم في الواقع إلى هذه التفاصيل كثيرًا في بداية مشوارنا لكن لا بد من الانتباه لها عند شراء معالج صغري، إذ نهتم عادة بالنقاط التالية وبما يلائم مشروعنا: حجم ذاكرته. السرعة التي يعمل عندها. عدد بوابات الدخل والخرج وعدد اﻷرجل في كل منها. عدد اﻷرجل التي تقبل دخلًا تماثليًا. عدد المؤقتات ودقتها. عدد العدادات فيه ودقتها. عدد وحدات الاتصال مع تجهيزات الوسط الخارجي وأنواعها (نقل تسلسلي، تفرعي،…). دعم الاتصال مع مع تجهيزات أخرى باستخدام واجهات مثل USB وغيرها. يمكن للمتحكم الصغري أن يستخدم ساعته الداخلية لمزامنة قراءة الشيفرة وتنفيذها أو ساعة خارجية يؤمنها موّلد نبض خارجي وله أنواع كثيرة أشهرها الهزازات الكريستالية Crystal Oscillators التي تعمل عند ترددات مختلفة بما يلائم السرعة القصوى المطلوبة من المتحكم المستخدم. الهيكلية الخارجية للمتحكم يغلّف المتحكم الصغري بأحد طرق تغليف الدوائر التكاملية التي ذكرناها سابقًا ولا يخرج منه إلى الوسط الخارجي سوى اﻷرجل. تُرقم أرجل المتحكم الصغري كما تُرقم أرجل أي دائرة متكاملة أي من الرقم 1 للرجل التي تقع على يسار الحفرة المرجعية على السطح وتتزايد اﻷرقام بعكس دوران عقارب الساعة. البوابات ووظائف اﻷرجل تقسم اﻷرجل كما ذكرنا إلى: أرجل مخصصة لها وظيفة واحدة كأرجل التغذية والتصفير وأرجل الاتصال مع الساعة الخارجية. أرجل عامة للدخل والخرج أرجل عامة للدخل والخرج مع وظائف خاصة. تشكل كل مجموعة من اﻷرجل العامة مايُسمى بوابة Port وتضم كل بوابة ما بين 3 إلى 16 رجل وعادة ما تُصنع أرجل البوابة الواحدة وفق آلية محددة تجعلها متوافقة مع بعضها. ويمكن برمجة كل رجل لتكون دخل أو خرج بغض النظر عن بقية أرجل البوابة، لكن عندما تريد استخدام البوابة ككل فلابد أن تكون كل أرجل هذه البوابة دخل أو كلها خرج. يمكن لبعض اﻷرجل وليس جميعها أن تستقبل قيمًا تماثلية لأنها مبنية ومصممة لهذا الغرض لكن كل اﻷرجل قادرة على فهم القيم الرقمية أو المنطقية. أما الأرجل ذات الوظائف الخاصة، فإنها تؤدي هذه الوظائف عندما نحدد ذلك عن طريق البرنامج. وعندها تؤدي فقط هذه الوظيفة الخاصة ولا يمكن أن تستخدم للدخل أو الخرج العام. ومن هذه الوظائف نجد العدادات وتبادل البيانات مع تجهيزات أخرى. ومن الوظائف الخاصة أيضًا اﻷرجل التي تتصل بجهاز البرمجة وتنقل البرنامج الذي كتبناه من الحاسوب إلى المتحكم. تطبيق عملي: تعرّف على المتحكم PIC16f84A وهو متحكم صغري من إنتاج Microchip يعمل عند جهد 2 إلى 5.5 فولط وسرعة بين 32 كيلو هرتز و20 ميغا هرتز يمكن تحديدها من خلال الساعة الخارجية المتصلة به (هزاز النبضات). لهذا المتحكم بعض الميزات منها: بوابتين A و B تضم البوابة اﻷولى خمسة أرجل مرمّزة من A0 وحتى A4، بينما تضم الثانية ثمان أرجل مرمّزة من B0 وحتى B7. دارة مؤقت/ عداد (حسب برمجتها) مرمّزة بالاسم TMR0 متصلة بالرجل RA4، إذا لهذه الرجل وظيفة عامة (دخل أو خرج) ووظيفة خاصة (عد النبضات الواردة إلى هذه الرجل) ويمكن ضبط الوظيفة المطلوبة برمجيًا. لا يمكنه التعامل مع اﻹشارات التماثلية مباشرة أي لا يحتوي على أرجل مهيأة للتعامل مع القيم التماثلية ويحتاج إلى عنصر خارجي يُدعى محوّل تماثلي رقمي. يدعم الاتصال التسلسلي مع الحاسب وبعض التجهيزات اﻷخرى. ذاكرة برنامج مقدارها 2048 بايت وذاكرة عشوائية للعمل مقدارها 64 بايت. يبرمج باستخدام لغة خاصة به كما يبرمج باستخدام لغة C. لتوصيل المتحكم إلى دائرة إلكترونية اتبع الخطوات التالية: صل الرجل رقم 14 إلى منبع تغذية موجب بين 3 إلى 5 فولط، يمكنك بالطبع استخدام منظم الجهد 7805 الذي تحدثنا عنه في تطبيق عملي سابق، لأنه من الضروري تنظيم الجهد الواصل إلى المتحكم وإزالة أية آثار للضجيج. صل الرجل رقم 5 باﻷرضي (المسرى السالب). صل مهتز كريستالي تردده 2 ميغا هرتز مثلًا بين الرجلين 15 و 16 ثم صل كل رجل للمهتز بالمسرى السالب من خلال مكثف عدسي 20 نانو فاراد. هذا المهتز هو من سيحدد سرعة عمل المتحكم ويضبط توقيت العمل. صل الرجل رقم 4 بالمسرى الموجب. في هذه اللحظة سيدخل المتحكم في مرحلة اﻹقلاع وصولًا إلى مرحلة تنفيذ البرنامج الذي حمّلناه مسبقًا إلى ذاكرته. كتابة برنامج للمتحكم وتحميله لا بد قبل كل شيء من تعلّم لغة برمجة، وخاصة C أو ++C أو بايثون حتى تستطيع التفكير بطريقة برمجية إضافة إلى فهم صياغة الشيفرة. وعليك أن تعرف أن تعاملك في المتحكمات سيكون مع اﻷرجل أو مع وحدات الاتصال. عندما تحدد أحد اﻷرجل على أنه رجل خرج، سيمر تيار له نفس جهد التغذية وشدة أقصاها 25 ميلي أمبير إلى العنصر الذي تريده وذلك في حال أعطيته القيمة المنطقية 1. إن حددت أحد الأرجل على أنها رجل دخل، سيترقب المعالج بشكل مستمر وصول تيار جهده يماثل جهد التغذية إلى هذه الرجل ثم ينفّذ عملًا معينًا إذا حدث ذلك. إن أردت من رجل ذات وظيفة خاصة أن تنفّذ هذه الوظيفة، عليك أن تحدد ذلك في البرنامج. توضع الشيفرة كلها ضمن كتلة يعيد المتحكم تنفيذها باستمرار وينتقل من تعليمة إلى التي تليها بشكل متسلسل. لنحاول أن نكتب برنامجًا بسيطًا للمتحكم PIC16F84A ينتظر ورود إشارة على الرجل RA0 ثم يجعل الأضواء الموصولة مع اﻷرجل RA1, RA2, RA3 تعمل بالتناوب لمرة واحد على أن يكون هناك فاصل زمني بين كل منها مقداره 2 ثانية ثم تنطفئ. إليك البرنامج: #include <16F877A.h> // لاستخدام الميزات الخاصة بالمتحكم المطلوب #use delay(clock=2000000) // اختيار سرعة المعالج بالهرتز ويماثل تردد الهزاز الكريستالي void main() { /* نضع في هذه الكتلة تعليمات برنامج المتحكم الذي يكررهابشكل مستمر طالما أنه في حالة عمل */ if(input_state(pin_a0)){ /*ستُنفَّذ التعليمات التالية RA0 إذا وصل تيار جهد 5 فولط إلى الرجل */ output_high(pin_a1);//ٌ لتمرر تيارًا إلى المؤشر الضوئي RA1 تفعيل الرجل delay_ms(2000);// الانتظار مدة 2000 ميلي ثانية أي ثانيتين output_high(pin_a2);// لتمرر تيارًا إلى المؤشر الضوئي RA2 تفعيل الرجل delay_ms(2000);// الانتظار مدة 2000 ميلي ثانية أي ثانيتين output_high(pin_a3);// لتمرر تيارًا إلى المؤشر الضوئي RA3 تفعيل الرجل delay_ms(2000);// الانتظار مدة 2000 ميلي ثانية أي ثانيتين output_low(pin_a1);//وإطفاء المؤشر الضوئي RA1 قطع التيار عن الرجل output_low(pin_a2);//وإطفاء المؤشر الضوئي RA2 قطع التيار عن الرجل output_low(pin_a3);//وإطفاء المؤشر الضوئي RA3 قطع التيار عن الرجل }; } يُكتب هذا البرنامج ضمن أي محرر نصي ثم يُستخدم برنامج حاسوبي لتحويله إلى شكل يفهمه المتحكم وهو الترميز المنطقي بالأصفار 0 والواحدات 1 وتكون النتيجة ملف له الامتداد hex.. نحتاج بعد ذلك إلى تجهيزة خاصة تُدعى مبرمجة مهمتها نقل الملف السابق من الحاسوب إلى المتحكم، وستجد أنواعًا مختلفة من المبرمجات يخصص كل منها لعائلة أو أكثر من المتحكمات ويأتي مع كل مبرمجة التوصيلات الخاصة مع الحاسوب وبرنامج نقل ملف الشيفرة ودليل الاستعمال. وهذا الموضوع بالطبع خارج نطاق هذا المقال ويتطلب مزيدًا من الشرح والتوضيح. الخلاصة هكذا نكون قد انتهينا من سلسلة هذه المقالات التي تحدّثت عن علم اﻹلكترونيات والدارات الإلكترونية انطلاقًا من المفاهيم اﻷساسية وصولًا إلى المتحكمات القابلة للبرمجة والتي تُعد نواةً للتحكم بالروبوتات والحواسب المصغرة وأجهزة التحكم الصناعي وغيرها الكثير. فإن رأيت أنك مهتم بما قرأت شاركنا رأيك في نقاش الصفحة ودعنا نساعدك في توضيح ما يُشكل عليك فهمه وتوجيهك نحو خطوات قادمة. اقرأ أيضًا المقال السابق: أساسيات في عالم الإلكترونيات: تشكيل الدوائر اﻹلكترونية والعناصر الفعالة برمجة الروبوت: الدليل الشامل تجميع راسبيري باي والتحضير لاستخدامه تصميم وتنفيذ لعبة حسية تفاعلية باستخدام لوحة راسبيري باي بيكو تصميم وتنفيذ آلة موسيقية باستخدام لوحة راسبيري باي بيكو
  2. سنوضح في مقال اليوم طريقة التعامل مع استعلام الوسائط Media Query في CSS والتي توفر طريقة لتطبيق تنسيقات معينة على عناصر HTML عندما تحقق بيئة العرض في جهاز أو متصفح معايير أوشروط محددة، كأن يكون اتساع نافذة العرض أكبر من 480 بكسل. إن هذا النمط من الاستعلام هو المفتاح لتصميم الويب المتجاوب Responsive web design، إذ يساعد فى بناء تخطيطات مختلفة للصفحات وفقًا لاتساع نافذة العرض. كما يمكن استخدام هذه الاستعلامات في معرفة بعض ميزات البيئة التي يعمل ضمنها موقعك كأن تعرف إن كان المستخدم يستعمل شاشة لمس بدلًا من الفأرة. لهذا سنتعلم أولًا طريقة صياغة استعلامات الوسائط، ثم سنتعلم استخدامها عمليًا من خلال مثال تفاعلي يشرح كيفية تحويل تخطيط بسيط إلى تخطيط متجاوب. عليك قبل البدء في قراءة هذا المقال أن: تطلع على أساسيات HTML كما شرحناها في سلسلة المقالات مدخل إلى HTML. تفهم أساسيات عمل CSS. أساسيات استعلامات الوسائط تبدو شيفرة استعلام الوسائط بشكلها الأبسط كالتالي: @media media-type and (media-feature-rule) { /* CSS rules go here */ } وهي تتكون من الأجزاء التالية: نوع واسطة العرض media type والذي يخبر المتصفح بطبيعة واسطة العرض التي كُتبت هذه الشيفرة من أجلها (طابعة، شاشة، ...إلخ.). شرط تطبيق الاستعلام media expression وهي قاعدة أو اختبار لا بد من تحققه حتى تُطبق شيفرة CSS المطلوبة. مجموعة قواعد تنسيق CSS التي تُطبق عند تحقق شرط تطبيق الاستعلام. أنواع وسائط العرض هناك ثلاث قيم لواسطة العرض: all print screen يضبط الاستعلام التالي مثلًا حجم الخط في جسم الصفحة على 12pt عند طباعة الصفحة، لكن هذه القاعدة لن تطبق عند عرض هذه الصفحة ضمن المتصفح: @media print { body { font-size: 12pt; } } ملاحظة1: إن نوع الوسائط في الاستعلامات مفهوم مختلف عن ما يُدعى نوع الوسائط المتعددة أو نوع المحتوى MIME-type وهو سلسلة نصية تُرسل مع الملف المرسل عبر الانترنت لتحديد نوعه أو وصف تنسيقه، على سبيل المثال، يمكن تسمية ملف صوتي audio/ogg، أو ملف صورة image/png). ملاحظة2: توجد أنواع أخرى من وسائط العرض أصّيفت في مواصفات المستوى الثالث من استعلامات الوسائط، لكنها أهملت ويجب تحاشيها. ملاحظة3: نوع الوسائط media type قيمة اختيارية، فإن لم ترغب بتحديد نوع واسطة العرض فلا تفعل وستكون القيمة الافتراضية all أي جميع الوسائط. قواعد تطبيق ميزات استعلام الوسائط بعد تخصيص نوع واسطة العرض يمكنك استهداف إحدى ميزات هذه الواسطة كي تحقق شرطًا أو اختبارًا ما: الاتساع والارتفاع أكثر الميزات استهدافًا للحصول على تصميم متجاوب وأكثرها دعمًا من قبل مختلف المتصفحات هي اتساع نافذة العرض viewport width. وهكذا يمكننا تطبيق مجموعة من قواعد التنسيق إن كان اتساع نافذة العرض أعلى أو أدنى أو يعادل قيمة محددة باستخدام ميزات استعلام الوسائط التالية: min-width و max-width و width. تُستخدم الميزات السابقة في إنشاء تخطيطات تتجاوب مع مختلف أبعاد الشاشات. فلو أردنا مثلًا تغيير لون خط الكتابة في جسم المستند إلى اللون الأحمر عندما يكون اتساع نافذة العرض 600 بكسل تمامًا، سنستخدم الاستعلام التالي: @media screen and (width: 600px) { body { color: red; } } ملاحظة: الق نظرة على هذا المثال على جيت-هاب أو اطلع على الشيفرة المصدرية. يمكن استخدام ميزتي الاتساع والارتفاع كمجالات وعندها تسبقان بالبادئة -min أو -max للإشارة إلى أن القيمة المعطاة هي أدنى أو أعلى قيمة. فإن أردنا في مثالنا السابق أن يكون لون الخط أحمر إن كان اتساع نافذة العرض 600 بكسل أو أضيق فنستخدم الميزة max-width: @media screen and (max-width: 600px) { body { color: blue; } } ملاحظة: الق نظرة على هذا المثال على جيت-هاب أو اطلع على الشيفرة المصدرية. إن استخدام القيم العظمى والصغرى أكثر فائدة عمليًا في التصميم المتجاوب، لهذا قلما تُستخدم الميزتان width أو height وحدهما. ستجد العديد من ميزات وسائط الاستعلام التي يمكن استهدافها على الرغم من محدودية دعم المتصفحات للميزات الأحدث الموضوعة في مواصفات المستويين 4 و 5 من استعلامات الوسائط. ويمكنك الاطلاع على كل ميزة ومدى دعم المتصفحات لها من خلال شبكة مطوري موزيللا. جهة انسياب المحتوى من الميزات المدعومة جيدًا لاستعلامات الوساط نجد الميزة orientation التي تسمح باختيار نمط عرض الصورة إما كصورة عمودية portrait أو أفقية landscape. ولكي نغير لون خط كتابة جسم الصفحة إن كان نمط عرض الجهاز أفقيًا، نستخدم الاستعلام التالي: @media (orientation: landscape) { body { color: rebeccapurple; } } ملاحظة: الق نظرة على هذا المثال على جيت-هاب أو اطلع على الشيفرة المصدرية. تعتمد شاشات حواسيب سطح المكتب نمط العرض الأفقي، وما يعمل جيدًا وفق نمط العرض هذا قد لا يعمل جيدًا على الهاتف المحمول أو الجهاز اللوحي الذي يعمل على النمط العمودي. وبالتالي سيساعدك الاستعلام عن نمط العرض في تبني تخطيط محسّن يخدم نمط العرض في الجهاز المستهدف. استخدام جهاز تأشير pointing device قدّمت مواصفات المستوى 4 لاستعلامات الوسائط الميزة hover التي تساعدك على اختبار قدرة المستخدم على إحداث أثر عند المرور فوق عنصر مما يدل على استخدامه نمطًا من أجهزة التأشير كالفأرة، فلا يمكن إحداث أثر عند المرور فوق عنصر في شاشات اللمس أو عند استخدام لوحة المفاتيح في التنقل بين العناصر. @media (hover: hover) { body { color: rebeccapurple; } } ملاحظة: الق نظرة على هذا المثال على جت-هاب. فإن عرفت أن المستخدم لا يعتمد على جهاز تأشير، بإمكانك عندها تقديم بعض الميزات التفاعلية للصفحة افتراضيًا، بينما يمكن تقديم هذه الميزات لمستخدمي أجهزة التأشير عند مرور المؤشر فوق العنصر. كما تضم مواصفات المستوى الرابع الميزة pointer التي تأخذ واحدة من ثلاث قيم هي none و fine و coarse. تُستخدم القيمة fine لأجهزة تأشير مثل الفأرة أو لوحة التتبع، وتساعد المستخدم على استهداف مساحة ضيقة من الصفحة. أما القيمة coarse فتدل على أن المستخدم يستعمل أصابعه أو يستعمل شاشة لمس. وأخيرًا تشير القيمة none إلى عدم استخدام أجهزة تأشير كحالة استخدام لوحة مفاتيح أو استخدام الأوامر الصوتية. يساعدك استخدام الميزة السابقة في تصميم واجهات مستخدم متجاوبة مع طريقة تفاعل المستخدم مع الشاشة. فبإمكانك مثلًا إنشاء مساحة لمس أوسع لمستخدم يستعمل شاشة لمس. استعلامات وسائط أكثر تعقيدًا قد ترغب أحيانًا بضم أكثر من استعلام أو إنشاء قائمة استعلامات قد يتحقق أيًا منها استخدام عامل الربط المنطقي and يُستخدم العامل and بنفس الطريقة التي استخدمناها سابقًا لربط نوع واسطة العرض مع الميزة. فقد نرغب مثلًا أن نختبر الميزتين min-width و orientation معًا. إذ نريد مثلًا أن يكون لون خط الكتابة أزرق إن كان اتساع نافذة العرض اكبر من 600 بكسل وكان الجهاز يعتمد طريقة العرض الأفقية: @media screen and (min-width: 600px) and (orientation: landscape) { body { color: blue; } } ملاحظة: الق نظرة على هذا المثال على جيت-هاب أو اطلع على الشيفرة المصدرية. استخدام عامل الربط المنطقي "or" ويُستخدم لتطبيق تنسيق معين عند تحقق واحدة من عدة استعلامات على الأقل وعندها نستخدم الفاصلة , للفصل بين هذه الاستعلامات. إذ يعرض المثال التالي خط الكتابة باللون الأزرق إن كانت اتساع نافذة العرض 600 بكسل على الأقل واعتمد الجهاز المستهدف طريقة العرض الأفقية. @media screen and (min-width: 600px), screen and (orientation: landscape) { body { color: blue; } } ملاحظة: الق نظرة على هذا المثال على جيت-هاب أو اطلع على الشيفرة المصدرية. استخدام عامل النفي المنطقي not بإمكانك نفي الاستعلام بالكامل باستخدام العامل not، إذ يعكس هذا العامل معنى الاستعلام تمامًا. لاحظ كيف يكون النص في مثالنا التالي أزرق اللون إن كان نمط العرض عموديًا: @media not all and (orientation: landscape) { body { color: blue; } } ملاحظة: الق نظرة على هذا المثال على جيت-هاب أو اطلع على الشيفرة المصدرية. كيفية اختيار النقاط الحدِّية breakpoints حاول المصممون في بدايات التصميم المتجاوب استهداف شاشات بقياسات محددة، بالاستفادة من قوائم تضم أبعاد شاشات أكثر الهواتف المحمولة والأجهزة اللوحية شعبية، وبالتالي سيكون التصميم ملائمًا تمامًا لنافذة العرض المستهدفة. أما الآن، وبوجود كم هائل من الأجهزة مختلفة الأبعاد، فلا جدوى من هذا النهج. وبدلًا من استهداف قياسات بعينها، ظهرت مقاربة تعتمد على تغيير التصميم أو التخطيط عندما لا يعود هذا التصميم ملائمًا لأبعاد الشاشة التي تعرضه. فقد يغدو السطر في نص ما طويلًا جدًا أو أن يضغط وتظهر أشرطة تمرير تصعب معها القراءة. في هذه الحالات، تساعدك استعلامات الوسائط في تغيير التصميم إلى آخر أفضل يلائم المساحة المتاحة للعرض. وهذا يعني أنك لن تحتاج إلى معرفة القياسات الدقيقة لأبعاد الشاشة المستخدمة، بل يتغير التصميم ضمن مجالات محددة لأبعاد نافذة العرض. تُدعى النقاط التي تُعرّف عندها استعلام الوسائط بنقاط الانتقال أو النقاط الحدية Breakpoints التي تسمح بالانتقال من تخطيط لآخر أو من تنسيق لآخر). يُساعدك نمط التصميم المتجاوب في أدوات مطوري ويب لمتصفح فايرفوكس في تفقد عمل نقاط الانتقال. إذ يمكنك بسهولة تصغير نافشة العرض أو تكبيرها لتتفحص كيفية تحسين التصميم إن أضفت استعلامات وسائط. تطبيق عملي: التصميم المتجاوب وقاعدة "الهاتف المحمول أولًا" يمكنك عمومًا اختيار أحد نهجين في التصميم المتجاوب. فإما أن تبدأ التصميم للحواسيب المكتبية أو الشاشات العريضة ثم تضيف نقاط انتقال يتغير عندها التصميم عند الانتقال إلى شاشات أضيق. أو أن تبدأ تصميمك لأصغر نوافذ العرض ثم تغير التخطيط مع ازدياد اتساع نافذة العرض. يُدعى النهج الأخير بنهج الهاتف المحمول أولًا وهو غالبًا ما يكون النهج الأفضل عمليًا. يُعرض المحتوى في الشاشات الصغيرة عادة ضمن تخطيط عمود واحد بسيط، كما هو الحال في تخطيط الانسياب الاعتيادي normal flow. أي أنك لن تحتاج غالبًا إلى تخطيطات معقدة للأجهزة الصغيرة، وكل ما عليك فعله هو ترتيب الشيفرة المصدرية جيدًا لتحصل على تخطيط واضح مقروء افتراضيًا. سنعمل في التطبيق التالي على توضيح هذا النهج من خلال تخطيط بسيط جدًا، وتذكّر أنه في المواقع الفعلية قد تواجه أشياء أكثر تعقيدًا تحتاج إلى ضبطها من خلال استعلامات الوسائط، لكن النهج سيبقى ذاته. تخطيط بسيط على نهج "الهاتف المحمول أولًا" سننطلق من مستند HTML مع بعض تنسيقات CSS التي تضيف ألونًا لخلفيات الأقسام المختلفة للتخطيط كما يلي. * { box-sizing: border-box; } body { width: 90%; margin: 2em auto; font: 1em/1.3 Arial, Helvetica, sans-serif; } a:link, a:visited { color: #333; } nav ul, aside ul { list-style: none; padding: 0; } nav a:link, nav a:visited { background-color: rgba(207, 232, 220, 0.2); border: 2px solid rgb(79, 185, 227); text-decoration: none; display: block; padding: 10px; color: #333; font-weight: bold; } nav a:hover { background-color: rgba(207, 232, 220, 0.7); } .related { background-color: rgba(79, 185, 227, 0.3); border: 1px solid rgb(79, 185, 227); padding: 10px; } .sidebar { background-color: rgba(207, 232, 220, 0.5); padding: 10px; } article { margin-bottom: 1em; } لم ندخل أية تغييرات على التخطيط من خلال شيفرة التنسيق السابقة، لكننا رتبنا الشيفرة المصدرية بطريقة تجعل المحتوى واضحًا. هذه الخطوة أساسية ومهمة من جهة، وتضمن سهولة قراءة المحتوى من قبل قارئات الشاشة من ناحية أخرى. <body> <div class="wrapper"> <header> <nav> <ul> <li><a href="">About</a></li> <li><a href="">Contact</a></li> <li><a href="">Meet the team</a></li> <li><a href="">Blog</a></li> </ul> </nav> </header> <main> <article> <div class="content"> <h1>Veggies!</h1> <p>…</p> </div> <aside class="related"> <p>…</p> </aside> </article> <aside class="sidebar"> <h2>External vegetable-based links</h2> <ul> <li>…</li> </ul> </aside> </main> <footer><p>&copy;2019</p></footer> </div> </body> يعمل هذا التخطيط البسيط جيدًا على الهاتف المحمول. وبإمكانك استخدام نمط التصميم المتجاوب في أدوات مطوري الويب لترى كيف يعمل بشكل واضح ومرضٍ على شاشة الهاتف المحمول. ملاحظة: اطلع على الخطوة الأولى ضمن متصفحك أو الق نظرة على الشيفرة المصدرية. وإن أردت أن تتابع العمل معنا، نزّل نسخة من الملف step1.html على حاسوبك. ابتداءً من هذه الخطوة، اسحب نافذة العرض في وضع التصميم المتجاوب لتصبح أوسع حتى اللحظة التي ترى فيها أن طول سطر الكتابة أصبح طويلًا، ولدينا متسع من المساحة لعرض المحتوى أفقيًا، هنا سنضع أول استعلام وسائط. سنستخدم واحدة em وتعني أنه إذا زاد المستخدم حجم الخط فإن نقطة الانتقال ستحدث عند طول السطر ذاته لكن ضمن نافذة عرض أوسع. أضف الشيفرة التالية إلى آخر الملف step1.html: @media screen and (min-width: 40em) { article { display: grid; grid-template-columns: 3fr 1fr; column-gap: 20px; } nav ul { display: flex; } nav li { flex: 1; } } يعطينا تنسيق CSS تخطيطًا من عمودين ضمن العنصر <article> الأول يضم محتوى المقال الأساسي والآخر لمعلومات متعلقة بالمحتوى إلى الجانب. كما استخدمنا الصندوق المرن لوضع قائمة التنقل ضمن صف واحد. ملاحظة: اطلع على الخطوة الثانية ضمن متصفحك أو الق نظرة على الشيفرة المصدرية. نتابع الآن العمل ونزيد الاتساع بالمقدار الذي نرى أنه مناسب كي يشكل الشريط الجانبي عمودًا جديدًا. وسنضع ضمن استعلام الوسائط شيفرة تحوّل العنصر الأساسي إلى شبكة من عمودين، وعلينا عندها إزالة margin-bottom من العنصر كي يتحاذى العمودان، كما سنضيف حدًا border أعلى التذييل. إن ما فعلناه عمليًا هو الشيء الذي نحتاجه ليبدو التصميم جيدًا عند كل نقطة انتقال. @media screen and (min-width: 70em) { main { display: grid; grid-template-columns: 3fr 1fr; column-gap: 20px; } article { margin-bottom: 0; } footer { border-top: 1px solid #ccc; margin-top: 2em; } } ملاحظة: اطلع على الخطوة الثالثة ضمن متصفحك أو الق نظرة على الشيفرة المصدرية. لو نظرت إلى المثال الأخير سترى كيف يتجاوب التصميم مع الاتساعات المختلفة للشاشة ابتداءًا من عمود واحد ثم عمودين وثلاثة أعمدة وفقًا للاتساع المتاح. وهذا بالطبع مثال بسيط عن التصميم وفق مبدأ "الهاتف المحمول أولًا". الوسم <meta> الخاص بنافذة العرض إن ألقيت نظرة على الشيفرة المصدرية لصفحة متجاوبة سترى عادة الوسم <meta> ضمن الترويسة كالتالي: <meta name="viewport" content="width=device-width,initial-scale=1" /> وهي طريقة للتحكم بكيفية تصيير متصفحات الهاتف المحمول للمحتوى، لأن متصفحات الهواتف المحمولة لا تكون صادقة تمامًا فيما يخص اتساع نافذة العرض.ولا تُعرض معظم المواقع غير المتجاوية بالشكل الأفضل ضمن نوافذ العرض الضيقة. لهذا تصيير الهواتف الذكية المحتوى وفق نافذة العرض أوسع من نافذة العرض الفعلية للجهاز (عادة 980 بكسل) ومن ثم تقلّص الصفحة بعد تصييرها لتلائم شاشة الجهاز. ويعني هذا أن المواقع المتجاوبة لن تعمل كما هو متوقع إن كان اتساع نافذة العرض التي يتعامل معها الجهاز هي 980 بكسل. فالتخطيط الذي تريده عند النقطة الحدِّية{}media screen and (max-width: 600px)@ مثلًا لن يُصيّر كما هو متوقع. يأتي الحل لهذه المشكلة باستخدام الوسم <meta> الذي يعرف نافذة العرض كما في الشيفرة السابقة والذي يمنع متصفح الهاتف من تصيير المحتوى على أساس اتساع 980 بكسل، بل وفقًا لنافذة العرض الفعلية للجهاز، ويضبط المقياس افتراضيًا ليكون كمقياس الصفحة الأصلي. عندها ستعمل استعلامات الوسائط كما هو متوقع. هل نحتاج فعلًا استعلامات الوسائط؟ تقدم لك تقنيات مثل الصندوق المرنflexbox وتخطيط الشبكة grid والتخطيط متعدد الأعمدة multicol وسيلة لإنشاء صفحات ويب مرنة ومتجاوبة دون الحاجة إلى استعلامات الوسائط. ومن الأفضل التفكير في تصميمك إن كان يحتاج فعلًا إلى هذه الاستعلامات أو لا، فقد ترغب مثلًا بعرض مجموعة من البطاقات اتساعها على الأقل 200 بكسل بقدر ما تتسع له الحاوية، هذا الأمر سهل الإنجاز باستخدام تخطيط الشبكة دون استعلامات وسائط كما يلي: <ul class="grid"> <li> <h2>Card 1</h2> <p>…</p> </li> <li> <h2>Card 2</h2> <p>…</p> </li> <li> <h2>Card 3</h2> <p>…</p> </li> <li> <h2>Card 4</h2> <p>…</p> </li> <li> <h2>Card 5</h2> <p>…</p> </li> </ul> .grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 20px; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } .grid li { border: 1px solid #666; padding: 10px; } ملاحظة: افتح هذا المثال باستخدام المتصفح أو اطلع على الشيفرة المصدرية. إن فتحت المثال في متصفحك، حاول أن تغيير اتساع نافذة المتصفح لترى كيف يتغير عدد الأعمدة في الصفحة. والمثير في هذه الطريقة عدم اعتماد الشبكة على اتساع نافذة العرض بل على مقدار المساحة المتاحة للعنصر أو الحاوية. قد تجد كتابة مقال عن استعلامات الوسائط ثم التوصية باستخدام تقنيات أخرى أمرًا غريبًا، لكن ما ستراه في الواقع التطبيقي هو تخطيطات ويب حديثة مدعومة باستعلامات وسائط للحصول على أفضل النتائج. الخلاصة تعلمنا في هذا المقال مبادئ استعلامات الوسائط وكيفية استخدامها عمليًا في إنشاء تصميمات تعتمد على قاعدة "الهاتف المحمول أولًا". بإمكانك استخدام الأمثلة والشيفرات المصدرية التي عرضناها كنقطة انطلاق وتتمرن بعدها على تطبيق استعلامات الوسائط المختلفة كأن تغير مثلًا حجم قائمة التنقل إن اكتشفت أن الزائر يستخدم جهاز تأشير خشن (غير دقيق) بالاستفادة من الميزة pointer. يمكنك اختبار الاستعلامات أيضًا بإضافة مكونات مختلفة وتحري إن كان إضافة استعلامات وسائط أو استخدام أساليب التخطيط المختلفة كالصندوق المرن أو الشبكات هو الأفضل في جعل تلك المكونات متجاوبة. إذًا لا توجدغالبًا طريقة صحيحة وأخرى خاطئة، وما عليك فعله هو التجريب لتعرف ما هو الأنسب لتصميمك. ترجمة -وبتصرف- للمقال: Beginners guide to media queries اقرأ أيضًا المقال السابق: التصميم المتجاوب لصفحات الويب Responsive Web Design استعلامات الوسائط (Media Queries) في CSS مدخل إلى التصميم المتجاوب والتصميم المتكيف عرض محتوى صفحات الويب بتجاوب على الأجهزة المتعددة
  3. تُعرَّف اﻷحداث أنها أفعال أو ظواهر تحدث في النظام الذي تبرمجه، ويخبرك بها هذا النظام كي تستجيب لها بطريقة مناسبة إن أردت. فلو نقر مثلًا مستخدم زرًا في صفحة ويب، قد ترغب في الاستجابة لهذا الحدث بعرض رسالة معينة. وما نناقشه في هذا المقال هي بعض المفاهيم المهمة المتعلقة باﻷحداث وكيفية عملها في المتصفح والتعامل معها في جافا سكريبت. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على: أساسيات علوم الحاسب. أساسيات HTML. أساسيات عمل CSS أساسيات جافاسكريبت كما شرحناها في سلسلة المقالات السابقة. ما هي اﻷحداث؟ تُعرَّف اﻷحداث events أنها أفعال أو ظواهر تحدث في النظام الذي تبرمجه، ينتج عن النظام (أو يحرّض) إشارة من نوع ما عند وقوع هذا الفعل أو الظاهرة، ويزوّدك بآلية لتحديد اﻹجراءات التي تتُخذ تلقائيًا (تشغيل شيفرة معينة) عند وقوعها. تقع اﻷحداث ضمن نافذة المتصفح وُربط أغلب اﻷحيان بعنصر محدد ضمن النافذة، قد يكون العنصر مفردًا أو مجموعة من العناصر أو صفحة HTML حُمِّلت ضمن النافذة الحالية أو نافذة المتصفح بأكملها. وستجد أنواعًا مختلفة من اﻷحداث التي تقع مثل: اختيار المستخدم عنصرًًا أو النقر عليه أو تحريك مؤشر الفأرة فوقه. اختيار المستخدم مفتاحًا من لوحة المفاتيح. تغيير المستخدم حجم نافذة المتصفح أو إغلاقها. إنهاء تحميل صفحة ويب. تشغيل فيديو أو إيقافه أو انتهائه. وقوع خطأ. إذًا هناك الكثير من اﻷحداث التي يمكن ترصدها. ولكي تستجيب لحدث ما، نربطه بما يُدعى معالج حدث event handler، وهو كتلة من الشيفرة (دالة جافاسكريبت عادة) تُنفَّذ عندما يقع الحدث. وعندما تُعرف كتلة برمجية كهذه كي تعمل استجابة لوقوع حدث ما، نقول أننا سجلنا معالج حدث. وتجدر الملاحظة أن معالج الحدث يُسمى أحيانًا مترصد حدث event listener، وسنتستخدم المصطلحين معًا ويعملان معًا. فالمترصد هو من يكتشف وقوع الحدث والمعالج هو الشيفرة التي تُنفّذ استجابة له. ملاحظة: لا تُعد أحداث الويب جزءًا من بنية جافاسكريبت، بل كجزء من الواجهة البرمجية المدمجة مع المتصفح. مثال: التعامل مع حدث النقر على عنصر لدينا في المثال التالي صفحة HTML تضم زرًا <button> واحدًا: <button>Change color</button> سنعود إليه لاحقًا بعد كتابة شيفرة جافا سكريبت في القسم التالي، لكن ما يهمنا حاليًا هو إضافة معالج حدث "النقر click" إلى الزر وسيتفاعل المتصفح مع هذا الحدث بانتقاء لون عشوائي للصفحة: const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number + 1)); } btn.addEventListener("click", () => { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; }); سيكون خرج المثال كالتالي: See the Pen js-events-1 by Hsoub Academy (@HsoubAcademy) on CodePen. استخدام التابع ()addEventListener رأينا في المثال السابق أن العناصر التي يمكنها إطلاق حدث، تمتلك التابع ()addEventListener وهو اﻵلية التي ننصح بها ﻹضافة معالج حدث. لنلق نظرة أقرب إلى شيفرة المثال السابق: const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number + 1)); } btn.addEventListener("click", () => { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; }); سيحرّض المستخدم عندما ينقر على الزر <button> حدثًا، لذلك عرّفنا دالة ()addEventListener نستدعيها عند وقوع الحدث ونمرر لها معاملين هما: القيمة النصية "click"ونحدد فيها أن الحدث الذي نترصده هو حدث النقر. ويمكن للأزرار أن تطلق العديد من اﻷحداث مثل mouseover عندما يحرّك المستخدم الفأرة فوق الزر أو keydown عندما يضغط على مفتاحًا ويكون تركيز الدخل على الزر. دالة نستدعيها عند وقوع الحدث، وفي حالتنا تولّد هذه الدالة لون RGB عشوائي وتضبط قيمة الخاصية background-color للعنصر <body> على قيمة اللون تلك. ولا بأس أن تفصل دالة الحدث باسم خاص بها كالتالي: const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number + 1)); } function changeBackground() { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; } btn.addEventListener("click", changeBackground); ترصّد اﻷحداث ستجد العديد من اﻷحداث التي يمكن للزر أن يطلقها، ولكي نختبر ذلك، انسخ الملف إلى جهازك وافتحه ضمن المتصفح. يمثل الملف نسخة عن مثال اللون العشوائي السابق. حاول اﻵن تغيير الحدث click إلى القيم المختلفة التالية على التوالي وراقب النتيجة: focus و blur: يتغير لون خلفية الصفحة عندما يتلقى الزر تركيز الدخل أو يفقد. حاول أن تنقل تركيز الدخل إلى الزر باستخدام المفتاح Tab ثم اضغط على المفتاح مجددًا ﻹبعاد تركيز الدخل. تُستخدم هذه اﻷحداث لعرض معلومات عن ملء نموذج بالبيانات عندما ينتقل التركيز إلى حقل نصي أو زر، أو لعرض رسالة خطأ عند ملئ أحد حقول النموذج بقيمة خاطئة. dblclick: يتغير اللون عندما تنقر الزر نقرًا مزدوجًا. mouseover أو mouseout: يتغير لون الخلفة عندما تمرر مؤشر الفأرة فوق الزر أو عندما يبتعد مؤشر الفأرة عن الزر. وبعض اﻷحداث مثل متاح تقريبًا لجميع العناصر، بينما يكون بعضها مخصصًا لحالات محددة. فالحدث play متاح مثلًا لبعض العناصر مثل العنصر <video. إزالة مترصد حدث عندما تضيف مترصد حدث باستخدام الدالة ()addEventListener، بإمكانك إزالته باستخدام التابع removeEventHandler. ستزيل الشيفرة التالية معالج الحدث ()changeBackgroud: btn.removeEventListener("click", changeBackground); كما يزال المعالج بتمرير إشارة إيقاف AbortSignal إلى الدالة ()addEventListener ومن ثم استدعاء التابع ()abort العائد للمتحكم controller الذي يمتلك إشارة اﻹيقاف لاحقًا. const controller = new AbortController(); btn.addEventListener("click", () => { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; }, { signal: controller.signal } // تمرير إشارة إيقاف إلى المعالج ); عندها يمكن إزالة معالج الحدث الذي تنتجه الشيفرة السابقة كالتالي: controller.abort(); // يزيل أي أو كل معالج حدث مرتبط بهذا المتحكم لا حاجة في البرامج الصغيرة والقديمة لإزالة معالجات اﻷحداث غير المستخدمة، لكن في البرامج اﻷضخم واﻷعقد سيزيد ذلك فعالية البرنامج. كما يمكن الاستفادة من فكرة إزالة معالج الحدث في استخدام الزر نفسه مثلًا لأداء إجراءات مختلفة في ظروف مختلفة، وكل ما عليك فعله هو إضافة وإزافى معالج الحدث المطلوب. إضافة أكثر من مترصد لنفس الحدث إن أردت استدعاء الدالة ()addEventListener أكثر من مرة وتزويدها بأكثر من معالج حدث لنفس الحدث، يمكنك استخدام أكثر من معالج كالتالي: myElement.addEventListener("click", functionA); myElement.addEventListener("click", functionB); وهكذا ستُنفَّذ كلا الدالتين في المعالجين السابقين عندما يُنقر الزر. عُد إلى موسوعة حسوب إن أردت الاطلاع على ميزات وخيرات أخرى مفيدة للدالة ()addEventListener. آليات اخرى لاستخدام مترصد الحدث ننصح دومًا باستخدام ()addEventListener لتسجيل معالجات اﻷحداث، فهي الطريقة اﻷقوى وتتلائم جيدًا مع البرامج المعقدة. مع ذلك، هنالك طريقتان إضافيتين لتسجيل معالج الحدث قد تصادفهما وهما استعمال الخاصية الموافقة للحدث أو معالج الحدث السطري inline event handler. خاصيات معالج الحدث للكائنات التي تطلق أحداثًا مثل اﻷزرار خاصيات تبدأ أسماؤها بالسابقة on يليها اسم معالج الحدث، مثل الخاصية onclick. تُدعى هذه الخاصيات بخاصيات معالج الحدث. ولكي تترصد حدثًا، أسند دالة معالج الحدث إلى هذه الخاصية كما في المثال التالي: const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number + 1)); } btn.onclick = () => { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; }; وتستطيع أيضًا إسناد اسم الدالة إلى الخاصية كالتالي إن كانت دالة المعالج مسماة: const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number + 1)); } function bgChange() { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; } btn.onclick = bgChange; ولا يمكن بالطبع إسناد أكثر من معالج حدث إلى حدث ما باستخدام الخاصيات، إذ يمكنك مثلًا استدعاء الدالة (click',handler')addEventListener من قبل عنصر عدة مرات وبتمرير دوال معالجة مختلفة كوسيط ثانِ: element.addEventListener("click", function1); element.addEventListener("click", function2); لكن ذلك مستحيل التنفيذ باستخدام الخاصيات لأن الإسناد الثاني سيلغي اﻷول: element.onclick = function1; element.onclick = function2; معالجات الأحداث السطرية لا تستخدم هذه الطريقة، لكنك قد تصادفها: <button onclick="bgChange()">Press me</button> إليك شيفرة جافاسكريبت function bgChange() { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; document.body.style.backgroundColor = rndCol; } ظهرت هذه الطريقة في مراحل مبكرة وتضمنت استخدام سمات HTML التي تحدد معالج الحدث (المعالجات السطرية inline event handler) كما تعرضه الشيفرة السابقة. وتحمل هذه السمة حرفيًا شيفرة جافاسكريبت التي تريد تنفيذها عند وقوع الحدث. نستدعي في المثال السابق دالة معرّفة ضمن العنصر <script> في نفس الصفحة، كما يمكنك إدراج شيفرة جافاسكريبت مباشرة ضمن السمة كالتالي: <button onclick="alert('Hello, this is my old-fashioned event handler!');"> Press me </button> قد تجد سمات HTML تكافئ العديد من خاصيات معالجات اﻷحداث، لكن لا ينبغي استخدامها لأنها ممارسة عملية سيئة. وقد يبدو استخدام معالج أحداث ضمن السمة سهلًا عند تنفيذ أمر سريع، لكنها ستغدو صعبة اﻹدارة وغير فعّالة. والسبب في ذلك من ناحية أولى أن دمج توصيف الملف HTML مع جافاسكريبت أمر غير عملي لما يسببه صعوبة في قراءة وفهم الصفحات، لهذا ينبغي فصل شيفرة جافاسكريبت في ملف خاص بها وهذا عمليًا أمر جيد ﻹمكانية إدراج نفس الملف في صفحات مختلفة. وحتى لو استخدمت ملفًا واحدًا، لا يُعد استخدام معالجات الأحداث السطرية فكرة جيدة، فقد ينفع الأمر إن كان هناك زر واحد، لكن ماذا لو ضمت الصفحة 100 زر؟ عليك حينها إضافة 100 سمة إلى الملف، وستكون إدارتها وصيانتها كابوسًا. أما عند استخدام جافاسكريبت، ستتمكن من إضافة دالة معالج الحدث إلى كل اﻷزرار في الصفحة مهما كان عددها وباستخدام شيفرة كهذه: const buttons = document.querySelectorAll("button"); for (const button of buttons) { button.addEventListener("click", bgChange); } ومن ناحية أخرى لا تسمح الكثير من إعدادات الخوادم باستخدام شيفرة جافاسكريبت سطرية، لأسباب تتعلق باﻷمان. لهذا لا يجب استخدام سمات HTML المتعلقة بمعالجات اﻷحداث، فهي قديمة واستخدامها عادة سيئة. كائنات الحدث قد تجد ضمن دالة الحث معاملات خاصة تحمل أسماء مثل event أو evt أو e، تُدعى هذه المعاملات كائنات حدث event object، وتمرر تلقائيًا إلى المعالجات لتزويدها بميزات ومعلومات إضافية. لنُعِد على سبيل المثال كتابة مثال اﻷلون العشوائية السابق مع بعض الاختلاف: const btn = document.querySelector("button"); function random(number) { return Math.floor(Math.random() * (number + 1)); } function bgChange(e) { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; e.target.style.backgroundColor = rndCol; console.log(e); } btn.addEventListener("click", bgChange); ملاحظة: يمكنك إيجاد الشيفرة الكاملة لهذا المثال على جت-هب (جرّب الشيفرة مباشرة أيضًا). لاحظ كيف أضفنا هنا كائن أحداث e في الدالة، ثم استخدمنا ضمن الدالة الخاصية target للكائن كالتالي e.target لضبط لون خلفية الصفحة، حيث تشير هذه الخاصية دائمًا إلى العنصر الذي يقع عليه الحدث. لذا نضبط في هذا المثال خلفية لونية عشوائية للزر وليس للصفحة لأن target تستهدف الزر فقط. ملاحظة: بإمكانك استخدام أي اسم تريده لكائن الحدث، لكن عليك استخدام اسم تتذكره عند استخدامه ضمن دالة الحدث. يستخدم المطورون عادة أسماء مثل event أو evt أو e لأنها قصيرة وسهلة التذكر. والأهم أن تحافظ على تناسق التسميات سواء في مشاريعك الشخصية أو المشتركة. خاصيات إضافية لكائن اﻷحداث لبعض كائنات الأحداث خاصيات إضافية تتعلق بالطبيعة الخاصة لكل حدث. إذ يقع الحدث keydown مثلًا عندما يضغط المستخدم على مفتاح، لهذا يضم كائن اﻷحداث الموافق له keyboardEvent الخاصية key التي تعطيك الزر الذي ضغطه المستخدم: const textBox = document.querySelector("#textBox"); const output = document.querySelector("#output"); textBox.addEventListener("keydown", (event) => { output.textContent = `You pressed "${event.key}".`; }); حاول استخدام لوحة المفاتيح لكتابة شيء ما وراقب ما يحدث: See the Pen js-events-2 by Hsoub Academy (@HsoubAcademy) on CodePen. إيقاف السلوك الافتراضي تضطر في بعض المواقف إلى منع الحدث من تنفيذ وظيفته الافتراضية. ومن اﻷمثلة الشائعة عن ذلك حالة نموذج ويب web form مثل نموذج تسجيل مستخدم جديد. فعندما تملأ الحقول وتنقر زر "تسليم submit"، سيكون السلوك الافتراضي هو رفع البيانات إلى صفحة محددة على الخادم لمعالجتها، ويُعاد توجيه المتصفح لعرض رسالة تشير إلى نجاح التسليم ضمن صفحة جديدة أو في نفس الصفحة. وتكمن المشكلة إن لم تُسلم البيانات بشكل صحيح، لهذا عليك كمطوّر منع تسليم البيانات إلى الخادم وإعطاء رسالة خطأ تشير إلى طبيعة الخطأ وما عليك تصحيحه. تتيح بعض المتصفحات ميزة التدقيق التلقائي للبيانات، وطالما أن هذا اﻷمر قد لا يحدث، ننصحك ألا تعتمد عليه بل تنفيذ آلية تحقق خاصة بك. لنلق نظرة على المثال التالي: إليك أولًا ملف htmL بسيط تحتاجه لإدخال الاسم اﻷول واﻷخير للمستخدم: <form> <div> <label for="fname">First name: </label> <input id="fname" type="text" /> </div> <div> <label for="lname">Last name: </label> <input id="lname" type="text" /> </div> <div> <input id="submit" type="submit" /> </div> </form> <p></p> إليك ثانيًا شيفرة جافاسكريبت التي نتحقق فيها من الحدث submit بشكل مبسط (يُطلق هذا الحدث ضمن النموذج <form> عندما يُرسل إلى الخادم) وذلك إن كانت المربعات النصية في النموذج فارغة. فإن كانت كذلك، نستدعي الدالة ()preventDefault العائدة لكائن الحدث ﻹيقاف عملية اﻹرسال ومن ثم نعرض رسالة خطأ في الفقرة النصية أسفل النموذج ﻹبلاغ المستخدم بالخطأ: const form = document.querySelector("form"); const fname = document.getElementById("fname"); const lname = document.getElementById("lname"); const para = document.querySelector("p"); form.addEventListener("submit", (e) => { if (fname.value === "" || lname.value === "") { e.preventDefault(); para.textContent = "You need to fill in both names!"; } }); من الواضح أنها طريقة ضعيفة في التحقق، فهي لن تمنع المستخدم من إدخال فراغات أو أرقام في حقول النموذج، لكنها مناسبة لمثالنا. سيكون الخرج كالتالي: See the Pen js-events-3 by Hsoub Academy (@HsoubAcademy) on CodePen. ملاحظة: يمكنك إيجاد الشيفرة الكاملة لهذا المثال على جت-هب (جرّب الشيفرة مباشرة أيضًا). رفع اﻷحداث يُقصد برفع اﻷحداث bubbling كيفية تعامل المتصفح مع اﻷحداث المستهدفة لعناصر متداخلة. إعداد مترصد لعنصر أب تأمل صفحة ويب لها الهيكلية التالية: <div id="container"> <button>Click me!</button> </div> <pre id="output"></pre> إن الزر هنا داخل العنصر <div> الذي يمثل العنصر اﻷب له. ما الذي سيحدث إن أضفنا معالج حدث نقر إلى العنصر اﻷب ثم نقرنا الزر؟ const output = document.querySelector("#output"); function handleClick(e) { output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`; } const container = document.querySelector("#container"); container.addEventListener("click", handleClick); لاحظ كيف يطلق العنصر اﻷب الحدث عندما ينقر المستخدم الزر: You clicked on a DIV element إن اﻷمر منطقي، فالزر ضمن العنصر <div> وعندما تنقر هذا العنصر فانت تنقر على الزر ضمنًا. مثال عن رفع الحدث ما الذي قد يحدث إن أضفنا مترصد الحدث إلى الزر وليس إلى العنصر اﻷب؟ <body> <div id="container"> <button>Click me!</button> </div> <pre id="output"></pre> </body> لنجرّب إضافة حدث نقر إلى الزر (الموجود ضمن <div> وكلاهما ضمن العنصر <body>? const output = document.querySelector("#output"); function handleClick(e) { output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`; } const container = document.querySelector("#container"); const button = document.querySelector("button"); document.body.addEventListener("click", handleClick); container.addEventListener("click", handleClick); button.addEventListener("click", handleClick); See the Pen js-events-3 by Hsoub Academy (@HsoubAcademy) on CodePen. سترى أن العناصر الثلاث جميعها ستطلق الحدث عندما ينقر المستخدم على الزر: You clicked on a BUTTON element You clicked on a DIV element You clicked on a BODY element في هذه الحالة: يُطلق حدث النقر على الزر أولًا. يليه حدث النقر على العنصر اﻷب (العنصر <div>). يليه حدث النقر على العنصر اﻷب للعنصر <div> (العنصر <div>). نصف ذلك برفع الحدث من العنصر الأعمق إلى الأب اﻷول. يمكن ان يكون هذا السلوك مفيدًا وقد يسبب مشاكل غير متوقعة، سنرى مثالًا عن هذه المشاكل في فقرات لاحقة وسنجد لها حلًا. مثال عن مشغّل فيديو تضم صفحتنا في هذا المثال فيديو أُخفي عمدًا وزر عنوانه "Display vedio". ونريد ان نظهر السلوك التفاعلي التالي: عندما ينقر المستخدم على الزر، يُعرض الصندوق الذي يضم الفيديو، لكنه لا يُشغّل المقطع. عندما ينقر المستخدم على الفيديو، يبدأ العرض. عندما ينقر المستخدم في أي مكان في الصندوق خارج الفيديو يختفي الصندوق. إليك شيفرة HTML: <button>Display video</button> <div class="hidden"> <video> <source src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm" type="video/webm" /> <p> Your browser doesn't support HTML video. Here is a <a href="rabbit320.mp4">link to the video</a> instead. </p> </video> </div> تتضمن الشيفرة: زر <button>. عنصر حاوية <div> له السمة "class="hidden. عنصر <video> ضمن العنصر <div>. أما شيفرة جافاسكريبت فهي كالتالي: const btn = document.querySelector("button"); const box = document.querySelector("div"); const video = document.querySelector("video"); btn.addEventListener("click", () => box.classList.remove("hidden")); video.addEventListener("click", () => video.play()); box.addEventListener("click", () => box.classList.add("hidden")); تضيف الشيفرة ثلاثة مترصدين للحدث 'click': اﻷول للزر <button> الذي يعرض الحاوية التي تضم الفيديو. والثاني للفيديو <video> لكي يُشغّله. والثالث للحاوية <div> لكي يخفي الفيديو. راقب كيف يجري اﻷمر: See the Pen js-events-5 by Hsoub Academy (@HsoubAcademy) on CodePen. سترى عند النقر على الزر كيف يظهر الصندوق والفيديو، لكن عند النقر على الفيديو سيعمل ويختفي الصندوق مجددًا. ولأن الفيديو داخل الحاوية، سيسبب نقره تنفيذ كلا معالجي اﻷحداث وظهور السلوك السابق. إصلاح المشكلة باستخدام الدالة ()stoppropogation قد يسبب رفع اﻷحداث كما رأينا سابقًا بعض المشاكل، لكن بالطبع توجد طريقة لمنع اﻷمر. إذ يُقدّم كائن اﻷحداث Event دالة تُدعى ()stopPropogation والتي تمنع عند استدعائها من داخل معالج الحدث من رفع الحدث إلى عناصر أعلى. ولكي نصلح المشكلة التي ظهرت معنا في المثال السابق، عدّل شيفرة جافاسكريبت كالتالي: const btn = document.querySelector("button"); const box = document.querySelector("div"); const video = document.querySelector("video"); btn.addEventListener("click", () => box.classList.remove("hidden")); video.addEventListener("click", (event) => { event.stopPropagation(); video.play(); }); box.addEventListener("click", () => box.classList.add("hidden")); كل ما فعلناه هنا هو استدعاء الدالة ()stopPropogation العائدة لكائن اﻷحداث داخل معالج الحدث الذي يتعامل مع الحدث 'click' الخاص بالعنصر <video>. سيمنع ذلك الحدث من الارتفاع إلى الصندوق. جرّب أن تنقر على الزر ثم على الفيديو: See the Pen js-events-6 by Hsoub Academy (@HsoubAcademy) on CodePen. التقاط الحدث إن الشكل اﻵخر لانتقال اﻷحداث هو التقاط الحدث event capture. واﻷمر مشابه لرفع الحدث لكن بترتيب معكوس. فبدلًا من اطلاق الحدث أولًا من قبل العنصر اﻷدنى في التسلسل الهرمي ثم ينتقل الحدث صعودًا إلى العنصر اﻷعلى مستوىً، يحدث العكس ويطلق الحدث العنصر اﻷعلى مستوى ويهبط وصولًا إلى العنصر اﻷدنى مستوىً. هذا الخيار معطّل افتراضيًا وعليك أن تمرر الخيار capture إلى الدالة ()addEventListener. يعرض المثال التالي نفس المثال السابق عن رفع اﻷحداث لكن سنستخدم فيه الخيار capture. إليك شيفرة HTML: <body> <div id="container"> <button>Click me!</button> </div> <pre id="output"></pre> </body> وشيفرة جافاسكريت: const output = document.querySelector("#output"); function handleClick(e) { output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`; } const container = document.querySelector("#container"); const button = document.querySelector("button"); document.body.addEventListener("click", handleClick, { capture: true }); container.addEventListener("click", handleClick, { capture: true }); button.addEventListener("click", handleClick); See the Pen js-events-7 by Hsoub Academy (@HsoubAcademy) on CodePen. تُعكس في هذه الحالة الرسائل التي تُعرض عند تنفيذ الشيفرة، حيث يطلق العنصر <body> الحدث أولًا يليه العنصر <div> من ثم الزر <button>: You clicked on a BODY element You clicked on a DIV element You clicked on a BUTTON element لكن لماذا نربك أنفسنا برفع الحدث أو التقاطه؟ يعود اﻷمر إلى الزمن الذي كانت فيه المتصفحات أقل توافقية بكثير مع بعضها، فاستخدم المتصفح نيتسكيب التقاط اﻷحداث واستخدم إنترنت إكسبلورر رفع اﻷحداث. وعندما حاولت منظمة W3C وضع معيار لهذا السلوك لكنها انتهت بإضافتها معًا، وهذا ما تتبناه المتصفحات اﻷحدث. وتستخدم معظم المتصفحات حاليًا رفع الأحداث افتراضيًا، وهذا أمر منطقي في معظم اﻷوقات. تفويض اﻷحداث لقد رأينا في الفقرات السابقة المشكلة التي ولدها رفع الحدث وكيفية إصلاحه. ومع أن رفع اﻷحداث مزعج أحيانًا لكنها قد تكون شديدة الفائدة. فهي تمكّن من استخدام تفويض اﻷحداث event delegation تحديدًا. فلو أردنا تنفيذ شيفرة محددة عندما يتفاعل المستخدم مع أي عنصر ابن ضمن عدد كبير من اﻷبناء، نهيئ مترصد أحداث للعنصر اﻷب ثم نرفع اﻷحداث التي تقع إلى العنصر اﻷب بدلًا من ضبط مترصد حدث لكل عنصر ابن على حدى. لنعد إلى مثالنا الأول التي نغيّر فيها لون خلفية الصفحة عند النقر على الزر، ولنفترض أن الصفحة مقسمة إلى 16 قسمًا ونريد إعطاء كل قسم لونًا عشوائيًا: إليك شيفرة HTML: <div id="container"> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> <div class="tile"></div> </div> إليك شيفرة CSS بسيطة لتحديد موضع وأبعاد اﻷقسام: .tile { height: 100px; width: 25%; float: left; } يمكننا اﻵن باستخدام جافاسكريبت إضافة معالج أحداث لكل قسم، لكن الخيار اﻷبسط والأكثر فعالية هو إعداد معالج حدث نقر للعنصر اﻷب ومن ثم الاعتماد على رفع الحدث للتأكد من تنفيذ معالج الحدث عندما ينقر المستخدم على قسم ما: function random(number) { return Math.floor(Math.random() * number); } function bgChange() { const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`; return rndCol; } const container = document.querySelector("#container"); container.addEventListener("click", (event) => { event.target.style.backgroundColor = bgChange(); }); سيكون الخرج كالتالي: See the Pen js-events-8 by Hsoub Academy (@HsoubAcademy) on CodePen. ملاحظة: نستخدم في هذا المثال الخاصية event.target للحصول على العنصر الذي كان هدفًا للحدث. لكن إذا أردنا الوصول إلى العنصر الذي يعالج الحدث (وهو في حالتنا العنصر اﻷدنى مستوى) يمكن استخدام الخاصية event.currentTarget. ملاحظة: يمكنك إيجاد الشيفرة الكاملة لهذا المثال على جت-هب (جرّب الشيفرة مباشرة أيضًا). اﻷحداث ليست فقط لصفحات الويب لا تخص اﻷحداث صفحات الويب فقط، فلكل لغات البرمجة نموذجًا من نوع ما للتعامل مع اﻷحداث ويختلف تعامل كل نموذج مع هذه النماذج بشكل مختلف عن أسلوب جافاسكريبت. وفي واقع اﻷمر يختلف نموذج جافا سكربت عند التعامل مع أحداث صفحات الويب مع نموذجها عند التعامل مع اﻷحداث في بيئة أخرى. ونجد مثلًا بيئة Node.js وهي بيئة تنفيذية شعبية لجافاسكريبت تساعد المطوّرين على بناء تطبيقات للشبكات وتطبيقات الخادم، أن نموذجها الخاص بالأحداث يعتمد على مترصدي اﻷحداث listeners لترقب وقوع الحدث ومصدري اﻷحداث emitters لبث اﻷحداث دوريًا. قد لا يبدو اﻷمر مختلفًا جدًا، لكن الشيفرة مختلفة تمامًا. إذ تُستخدم دوال مثل ()on لتسجيل مترصد حدث، و ()once لتسجيل مترصد أحداث مرة واحدة ثم إلغاء تسجيله بعد تنفيذه مباشرة. يمكنك الاطلاع على توثيق أحداث الاتصال وفق بروتوكول HTTP لأمثلة أوضح. بإمكانك استخدام جافاسكريبت لبناء إضافات قابلة للعمل في بيئات مختلفة باستخدام تقنية تُدعى موّسعات الويب WebExtension. إن نموذج اﻷحداث مشابه لنموذج أحداث الويب مع اختلاف بسيط، هو أن خاصيات مترصد اﻷحداث تُكتب باستخدام أسلوب سنام الجمل (مثل onMessage بدلًا من onmessage) والحاجة إلى دمجه مع الدالة addListener. لا حاجة حاليًا لاستيعاب أي شيء عن البيئات اﻷخرى، لكننا أردنا توضيح فكرة أن اﻷحداث قد تختلف من بيئة برمجة إلى أخرى. الخلاصة لقد تعلمّت اﻻن ما يجب عليك تعلّمه عن أحداث الويب في هذه المرحلة المبكرة من مسيرتك، وكما ذكرنا سابقًا، لا تُعد اﻷحداث جزءًا بنيويًا من جافاسكريبت بل تُعرّف ضمن الواجهة البرمجية للمتصفح. كما ينبغي أن تدرك أن سياق استخدام جافا سكريبت يتطلب نموذجًا مختلفًا لمعالجة اﻷحداث ابتداءًا بالواجهات البرمجية للويب إلى تقنيات أخرى مثل موسّعات ويب الخاصة بالمتصفحات وجافاسكريبت المخصصة للعمل على الخوادم مثل Node.js. لا نتوقع منك أن تستوعب كل هذه النواحي حاليًا، لكنها تساعدك بالتأكيد على فهم أساسيات اﻷحداث مع تقدّمك في مسيرة تطوير الويب. و إن استعصى عليك شيء لا تتردد في طرح أية أسئلة ضمن نقاش الصفحة أو في قسم الأسئلة والأجوبة في أكاديمية حسوب. ترجمة -وبتصرف- للمقال Introduction to events اقرأ أيضًا المقال السابق: الدوال التي تعيد قيمًا في جافا سكريبت فهم الأحداث في جافاسكربت معالجة الأحداث في جافا سكريبت الأحداث المتعلقة بدورة حياة صفحة HTML وكيفية التحكم بها عبر جافاسكربت
  4. نلقي نظرة في هذا المقال على الصياغة اﻷساسية لكائن جافا سكريبت كما نستذكر بعض الميزات التي ناقشناها سابقًا لنشدد على حقيقة أن العديد من الميزات التي اطلعنا عليها وتعاملنا معها في لغة جافا سكريبت هي في الواقع كائنات، ابتداءً من المميزات البنيوية للغة مثل المصفوفات إلى الواجهات البرمجية للمتصفحات APIs المبنية على أساس جافا سكريبت. وبإمكانك أيضًا بناء كائنات خاصة بك لتغليف مجموعة من الدوال والمتغيرات ضمن حزمة أكثر فعالية تعمل كحاوية بيانات. ولا بد أن تتفهم طبيعة جافا سكريبت القائمة على الكائنات إن أردت التعمق أكثر في تعلم هذه اللغة، لهذا نزوّدك ضمن هذا المقال والمقالات التالية بمعلومات مهمة عن الكائنات البرمجية وصياغتها بشيء من التفصيل ثم ننتقل إلى شرح طريقة بناء كائنات خاصة بك. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على: أساسيات HTML أساسيات عمل CSS أساسيات جافا سكريبت أساسيات الكائنات الكائن object هو مجموعة مترابطة من البيانات أو الوظائف، فهو يتألف عادة من من عدة متغيرات ودوال (تُدعى المتغيرات ضمن الكائن خاصيات properties والدوال methods). وحتى نستوعب مفهوم الكائنات سنعمل على المثال التالي. أنشئ أولًا نسخة من الملف oojs.html على حاسوبك. ويتضمن هذا الملف العنصر <script> الذي سنكتب ضمنه الشيفرة. سنستخدم هذه الصفحة كأساس لاستكشاف الصياغة اﻷساسية للكائن في جافا سكريبت. وعليك أن تفتح طرفية جافا سكريبت الخاصة بأدوات مطوري ويب وتجعلها جاهزة لكتابة التعليمات. وكما هو الحال في الكثير من اﻷشياء في جافا سكريبت، يبدأ إنشاء الكائن بتعريف وتهيئة بعض المتغيرات. لهذا جرّب إدخال السطر التالي تحت السطر الموجود أصلًا في ملف التمرين ثم احفظ التغييرات وأعد تحميل الصفحة: const person = {}; افتح اﻵن طرفية جافا سكريبت ثم اكتب person ضمنها ثم اضغط المفتاح Enter. من المفترض أن تحصل على نتيجة مشابهة للتالي: [object Object] Object { } { } تهانينا! لقد أنشأت للتو كائنًا في جافا سكريبت. لقد أنجز العمل بالفعل، لكن الكائن فارغ كما تلاحظ ولا يمكن أن يفيدنا كثيرًا. لهذا سنعدّل الكائن ضمن شيفرة جافا سكريبت في ملف التمرين كالتالي: const person = { name: ["Bob", "Smith"], age: 32, bio: function () { console.log(`${this.name[0]} ${this.name[1]} is ${this.age} years old.`); }, introduceSelf: function () { console.log(`Hi! I'm ${this.name[0]}.`); }, }; جرّب إدخال بعض التعليمات كما يلي في طرفية جافا سكريبت وذلك بعد حفظ التغييرات وإعادة تحميل الصفحة: person.name; person.name[0]; person.age; person.bio(); // "Bob Smith is 32 years old." person.introduceSelf(); // "Hi! I'm Bob." يضم الكائن بعض البيانات اﻵن كما يحتوي على بعض الوظائف التي يمكن الوصول إليها من خلال صياغة بسيطة واضحة. ما الذي يحدث فعلًا في مثالنا؟ لقد أنشأنا كائنًا مكوّنًا من عدة أعضاء members لكل منها اسم ( مثال name و age) وقيمًا مثل ['Bob, 'Smiths] و 32. يفصل بين كل زوج (اسم/قيمة) فاصلة ,، وبين كل اسم وقيمة نجد نقطتين متعامدتين :. وتتبع صياغة الكائن الشكل التالي دائمًا: const objectName = { member1Name: member1Value, member2Name: member2Value, member3Name: member3Value, }; قد تكون قيمة أعضاء الكائن أي شيء، وفي مثالنا السابق ضم الكائن person أعدادًا ومصفوفة ودالتين. إن أول عضوين كما رأينا يضمان بيانات عن الكائن ويُشار إليهما كخاصيات properties، كما يُشار إلى الدالتين اللتان تسمحان للكائن بتنفيذ بعض العمليات على البيانات بالتوابع أو الدوال التابعة للكائن methods. وعندما يكون عضو الكائن دالة، باﻹمكان استخدام صياغة أبسط من bio:function، ويكفي أن نكتب ()bio كالتالي: const person = { name: ["Bob", "Smith"], age: 32, bio() { console.log(`${this.name[0]} ${this.name[1]} is ${this.age} years old.`); }, introduceSelf() { console.log(`Hi! I'm ${this.name[0]}.`); }, }; وسنستخدم من اﻵن وصاعدًا الصيغة المختصرة في تعريف الدوال. ندعو الكائنات التي تُبنى كما شرحنا سابقًا بالكائنات الحرفية literal object لأننا كتبنا حرفيًا كل أعضائها عند إنشائها. وهي كائنات مختلفة عن تلك التي تُنسخ عن اﻷصناف، والتي سنلقي عليها نظرة لاحقًا. من الشائع أيضًا إنشاء الكائنات كنسخ عن الكائنات الحرفية، وخاصة عندما نريد نقل سلسلة من البيانات المهيكلة المترابطة مثل إرسال طلب إلى خادم لوضع البيانات ضمن قاعدة بيانات. فإرسال كائن واحد أكثر فعالية من إرسال البيانات بشكل مستقل ومن اﻷسهل التعامل معها موازنة بالتعامل مع مصفوفة عندما تريد تحديد كل عنصر باسمه بشكل مستقل. طريقة النقطة Dot notation للوصول إلى أعضاء الكائن لقد وصلنا في مثالنا السابق إلى خاصيات وتوابع الكائن باستخدام العامل . ويسمى هذا الأسلوبالتدوين النقطي أو الاستدعاء النقطي dot notation. حيث يسلك اسم الكائن person سلوك فضاء الأسماء namespace. ولا بد من كتاب اسم الكائن أولًا للوصول إلى أي عضو من أعضاءه ومن ثم تكتب النقطة ومن ثم العضو الذي تريد الوصول إليه، وقد يكون العضو عنصرًا أو مصفوفة أو استدعاء أحد توابع الكائن. person.age; person.bio(); الكائنات والخاصيات على شكل كائنات يمكن للخاصية بحد ذاتها أن تكون كائنًا، جرّب مثلًا أن تغيّر العضو name من الشكل التالي: const person = { name: ["Bob", "Smith"], }; ليصبح بالشكل: const person = { name: { first: "Bob", last: "Smith", }, // … }; وللوصول إلى هذه العناصر لا بد من ربطها بالكائن الرئيسي بكتابة نقطة أخرى. جرّب كتابة الشيفرة التالية في طرفية جافا سكريبت: person.name.first; person.name.last; فإن فعلت ذلك، عليك العودة إلى الشيفرة وتغيير كل شيفرة من الشكل: name[0]; name[1]; إلى name.first; name.last; وإلا لن تعمل التوابع. استخدام طريقة اﻷقواس في الوصول إلى أعضاء الكائن باﻹمكان الوصول إلى أعضاء الكائن باستخدام طريقة اﻷقواس المربعة Bracket notation فبدلًا من استخدام النقطة كما في المثال التالي: person.age; person.name.first; يمكننا استخدام الأقواس كما في الكود التالي: person["age"]; person["name"]["first"]; يبدو اﻷمر مشابهًا للوصول إلى عناصر مصفوفة، هو من ناحية المبدأ اﻷمر ذاته، فبدلًا من الوصول باستخدام دليل المصفوفة index، تستخدم الاسم المرتبط بقيمة العنصر. لهذا السبب تًدعى الكائنات أحيانًا مصفوفات ترابطية associative arrays، فهي ترتبط بالقيم النصية بنفس الطريقة التي ترتبط فيها المصفوفة بدليلها. يُفضّل استخدام طريقة النقطة على طريقة اﻷقواس عمومًا لأنها أكثر وضوحًا وأسهل قراءة. لكن ستجد بعض الحالات التي تستخدم فيها اﻷقواس المربعة مثل إسناد قيمة خاصية على شكل كائن إلى متغيّر، فلن تستطيع في هذه الحالة استخدام النقطة للوصول إلى القيمة، لكن باﻹمكان استخدام الأقواس المربعة. في المثال التالي، يمكن للدالة أن تستخدم الطريقة person[propertyName] للوصول إلى القيمة المخزنة في الخاصية proertyName: const person = { name: ["Bob", "Smith"], age: 32, }; function logProperty(propertyName) { console.log(person[propertyName]); } logProperty("name"); // ["Bob", "Smith"] logProperty("age"); // 32 ضبط قيم أعضاء الكائن كل ما تعلمناه حتى اللحظة هو الحصول على قيمة أعضاء الكائن object members، لكن باﻹمكان أيضًا ضبط قيمة هذه الأعضاء بالتصريح عن العضو الذي تريد ضبطه (باستخدام طريقة النقطة أو اﻷقواس المربعة) كالتالي: person.age = 45; person["name"]["last"] = "Cratchit"; جرّب إدخال التعليمتين التاليتين ضمن طرفية جافا سكريبت، ولاحظ كيف تغيرت القيمة: person.age; person["name"]["last"]; لا يقتصر ضبط قيم أعضاء الكائن على تغيير القيمة الموجودة للخاصيات أو التوابع، بل يمكنك إنشاء عناصر جديدة كليًا. جرّب اﻵن ما يلي في الطرفية: person["eyes"] = "hazel"; person.farewell = function () { console.log("Bye everybody!"); }; اختبر اﻵن العناصر الجديدة: person["eyes"]; person.farewell(); // "Bye everybody!" من إيجابيات استخدام طريقة اﻷقواس المربعة أنه باﻹمكان استخدامها في ضبط قيمة اﻷعضاء ديناميكيًا إضافة إلى تغيير أسماء الأعضاء أيضًا. لنفترض أننا نريد منح المستخدم القدرة على تخزين أنواع مخصصة من القيم في بيانات اﻷشخاص وذلك بكتابة اسم العضو وقيمته ضمن مربعي إدخال نصي منفصلين. باﻹمكان إنجاز اﻷمر كالتالي: const myDataName = nameInput.value; const myDataValue = nameValue.value; نضيف بعدها هذا العضو الجديد إلى الكائن person كالتالي: person[myDataName] = myDataValue; ولاختبار اﻷمر، جرّب إضافة الأسطر التالية إلى شيفرتك، أسفل قوس إغلاق الكائنن person: const myDataName = "height"; const myDataValue = "1.75m"; person[myDataName] = myDataValue; جرّب حفظ التغييرات وإعادة تحميل الصفحة ثم إدخال التالي ضمن مربع اﻹدخال النصي: person.height; إن إضافة خاصية إلى الكائن باستخدام اﻷسلوب السابق لن يكون ممكنًا باستخدام طريقة النقطة والتي تقبل فقط الاسم الحرفي للعضو ولا تقبل قيمة متغير يشير إلى الاسم. لماذا استخدمت الكلمة المحجوزة this لربما قد لاحظت شيئًا غريبًا في أسلوبنا في الشيفرة السابقة، ألق نظرة اﻵن على هذا المثال: introduceSelf() { console.log(`Hi! I'm ${this.name[0]}.`); } لربما تتساءل ماذا فعلت الكلمة this؟ تشير هذه الكلمة المحجوزة إلى الكائن الحالي الذي كُتبت الشيفرة ضمنه، فهي في مثالنا تكافئ الكائن person. لماذا إذًا لا نستخدم person وحسب؟ في الواقع، لا فائدة من استخدام الكلمة this كثيرًا في حال أنشأت كائن حرفي وحيد، لكن إن أنشأت أكثر من كائن حرفي، يساعدك ذلك في استخدام نفس تعريف التابع لكل كائن أنشأته. لنوضح ذلك من خلال المثال التالي: const person1 = { name: "Chris", introduceSelf() { console.log(`Hi! I'm ${this.name}.`); }, }; const person2 = { name: "Deepti", introduceSelf() { console.log(`Hi! I'm ${this.name}.`); }, }; في هذه الحالة، ينتج عن تنفيذ التعليمة ()person1.introduceSelf الخرج التالي "Hi! I'm Chris."، بينما ينتج عن تطبيق نفس التابع على كائن آخر ()person2.introduceSelf من نفس النوع خرج آخر مناسب للكائن "Hi! I'm Deepti". وعلى الرغم من أن الشيفرة نفسها في الحالتين، لكن أهميتها لن تظهر عند كتابة كائنات حرفية يدويًا، بل عندما تبدأ باستخدام الدوال البانية constructors ﻹنشاء أكثر من كائن من تعريف واحد له وهذا ما نناقشه تاليًا. مقدمة إلى الدوال البانية Constructors لا بأس باستخدام الكائنات الحرفية عندما تريد استخدام كائن واحد، لكن إن كان عليك إنشاء أكثر من عنصر سيغدو استخدام العناصر الحرفية غير ملائم. إذ علينا كتابة نفس الشيفرة لكل كائن على حدى، وإن كان علينا تغيير بعض الخاصيات كإضافة الخاصية height، لا بد من تذكرّ تغيير كل الكائنات التي أنشأتها. من الأفضل استخدام شكل أو نموذج للكائن يضم كافة التوابع والخاصيات اللازمة، ومن ثم إنشاء العدد الذي يلزمنا من هذا الكائن وفق هذا الشكل بتعديل قيم الخواص المختلفة. إليك نسخة أولى من الشكل الذي نتحدث عنه وهو على شكل دالة: function createPerson(name) { const obj = {}; obj.name = name; obj.introduceSelf = function () { console.log(`Hi! I'm ${this.name}.`); }; return obj; } تُنشئ الدالة وتعيد كائنًا جديدًا في كل مرة نستدعيها، ويضم هذا الكائن عضوين هما: الخاصية: name. التابع: ()introduceSelf. تأخذ الدالة ()createPersonمعاملًا وحيدًا هو name لضبط قيمة الخاصية name، لكن تبقى قيمة التابع ()introduceSelf نفسها لجميع الكائنات التي تنشأها الدالة. ويُعد هذا اﻷسلوب من أكثر الطرق شيوعًا في إنشاء الكائنات. بإمكانك اﻵن إنشاء العدد الذي تريده من الكائنات، بإعادة استخدام الدالة: const salva = createPerson("Salva"); salva.name; salva.introduceSelf(); // "Hi! I'm Salva." const frankie = createPerson("Frankie"); frankie.name; frankie.introduceSelf(); // "Hi! I'm Frankie." ستعمل الشيفرة السابقة جيدًا لكنها طويلة بعض الشيء. إذ أنشأنا كائنًا فارغًا ثم هيأناه وأعدناه، لكن الطريقة اﻷفضل تقضي باستخدام دالة بانية، وهي دالة نستدعيها باستخدام الكلمة المحجوزة new. وعندما نستدعي دالة بانية فإنها: تنشئ كائنًا جديدًا. تربط this بالكائن الجديد، وستتمكن عندها من اﻹشارة إلى الكائن الجديد من خلالها ضمن شيفرة الدالة البانية. تعيد الكائن الجديد. تبدأ أسماء الدوال البانية عادة بحرف كبير وتسمى باسم نوع الكائن الذي تنشؤه، لهذا سنعيد كتابة مثالنا ليصبح بالشكل التالي: function Person(name) { this.name = name; this.introduceSelf = function () { console.log(`Hi! I'm ${this.name}.`); }; } ولكي نستدعي الدالة ()Person كدالة بانية نستخدم الكلمة new: const salva = new Person("Salva"); salva.name; salva.introduceSelf(); // "Hi! I'm Salva." const frankie = new Person("Frankie"); frankie.name; frankie.introduceSelf(); // "Hi! I'm Frankie." لقد استخدمت الكائنات كثيرًا فيما مضى لربما تساءلت أثناء العمل على الأمثلة السابقة بأن استخدام النقطة كان مألوفًا، والسبب أنك استخدمتها طوال فترة تعلم جافا سكريبت عبر سلسلة مقالتنا. فكل مرة عملنا فيها مع مثال يستخدم واجهة المتصفح البرمجية أو كائنات جافا سكريبت، استخدمنا فيها الكائنات لأنها ميزات بنيت باستخدام الطريقة نفسها التي بنينا فيها الكائنات المخصصة في مثالنا اﻷخير، لكنها بالطبع أكثر تعقيدًا. فعندما تستخدم التابع النص كما في المثال التالي: myString.split(","); فأنت تستخدم التوابع التي يوفرّها الكائن String. وفي كل مرة تنشئ فيها سلسلة نصية في شيفرتك، سيتولد هذا النص تلقائيًا كنسخة عن الكائن String، ويشترك معه بالعدبد من الخاصيات والتوابع. وعندما تحاول الوصول إلى كائن المستند باستخدام شيفرة كالتالي: const myDiv = document.createElement("div"); const myVideo = document.querySelector("video"); فأنت تستخدم في الواقع التوابع التي يقدّمها الكائن أو الواجهة البرمجية Document، وعند كل تحميل لصفحة الويب تُنشئ نسخة جديدة عن هذا الكائن تُدعى document تمثّل هيكلية الصفحة بأكملها ومحتواها وغير ذلك من الميزات مثل عناوين URL. أي باختصار، سيمتلك الكائن الذي أنشأته عدة توابع وخاصيات يشترك فيها مع الكائن الأساسي Document. وهذا الأمر مشابه للكثير من الكائنات والواجهات البرمجية المضمنة في لغة جافا سكريبت مثل المصفوفات Array والمكتبة Math. لاحظ أن الكائنات والواجهات البرمجية الأصلية أو المدمجة في جافا سكريبت لا تنشأ من تلقاء نفسها بل عليك إنشاؤها بنفسك في كل مرة تحتاجها، مثل الواجهة البرمجية للتنبيهات Notifications API التي تسمح للمتصفحات الحديثة بإطلاق تنبيهات، حيث تتطلب هذه الواجهة منك أن تنشئ نسخة جديدة باستخدام الدالة البانية لكل تنبيه تريد إطلاقه. جرّب إدخال السطر التالي إلى طرفية جافا سكريبت: const myNotification = new Notification("Hello!"); الخلاصة لقد أنهينا هذه المقال التي يمهّد لاستخدام الكائنات في جافا سكريبت، ولا بد أنك امتلكت بقراءته فكرة عن عمل الكائنات، بما في ذلك إنشاء كائنات بسيطة. ومن المهم إدراك أهمية الكائنات كبنى لتخزين البيانات والوظائف المترابطة. فلو حاولت تتبع جميع الخاصيات والتوابع في الكائن person الذي بنيناه في مثالنا شكل متغيرات ودوال منفصلة ستجد أنها طريقة غير مجدية ومحبطة، وستزيد مخاطر التضارب بين المتغيرات والدوال التي تمتلك نفس اﻷسماء. إذ تساعد الكائنات في حفظ المعلومات ضمن حاويات خاصة بها لتقليل مثل هذه المخاطر. ترجمة -وبتصرف- للمقال JavaScript object basics اقرأ أيضًا مدخل إلى جافاسكريبت كائنية التوجه (Object-Oriented JavaScript) لغة البرمجة بالكائنات Object-Oriented Programming برمجة الكائنات Objects في جافاسكريبت مختصر البرمجة كائنية التوجه OOP وتطبيقها في بايثون
  5. بعد أن اطلعنا في مقال سابق على أبسط أساسيات النصوص في جافا سكريبت، سننتقل في هذا المقال إلى مناقشة العمليات المهمة التي يمكن تنفيذها على النصوص والتوابع الأصلية التي توفرها جافا سكريبت لتحقيق ذلك مثل إيجاد طول سلسلة نصية وضم أو فصل سلسلة نصية وتبديل محرف بآخر وغيرها. ننصحك قبل المتابعة في قراءة هذا المقال بالاطلاع على بعض المقالات السابقة مثل: أساسيات علوم الحاسب. أساسيات HTML. أساسيات عمل CSS السلاسل النصية والكائنات إن معظم اﻷشياء في جافا سكربت هي كائنات objects، فعندما ننشئ سلسلة نصية كما في المثال التالي: const string = "This is my string"; يصبح المتغير قالبًا لكائن نصي وكنتيجة يمكن تطبيق عدد كبير من الخاصيات والتوابع عليه. وللاطلاع على هذه الخاصيات والتوابع يمكنك مراجعة توثيق موسوعة حسوب للكائن String. لا حاجة طبعًا أن تربك نفسك بهذه التوابع في بداية رحلتك في تعلم البرمجة، لكنك ستستخدم بعضها مرارًا لهذا من الجيد أن تلقي نظرة عليها. إيجاد طول سلسلة نصية بإمكانك إنجاز اﻷمر باستخدام الخاصية length، إليك مثالًا: const browserType = "mozilla"; browserType.length; يُفترض أن يعيد المتصفح القيمة 7 لأن عدد محارف السلسلة "mozilla" هو 7. ولهذا اﻷمر فائدته، وكمثال على ذلك، تصوّر أنك ترد ترتيب سلسلة من اﻷسماء وفقًا لطول هذه اﻷسماء، أو أنك تريد إعلام المستخدم أن النص الذي أدخله في الحقل أطول مما هو مسموح. استخلاص محرف محدد من سلسلة نصية بإمكانك عمومًا إعادة محرف محدد من سلسلة نصية باستدعاء المتغير الذي يضمها وبعده قوسان مربعان []يحويان رقم المحرف الذي تريده، فلو أردت مثلًا إعادة المحرف الأول من سلسلة نصية يمكنك كتابة التالي: browserType[0]; وتذكر أن الفهرسة تبدأ من الصفر وليس من 1. ولكي تعيد آخر محرف من أي سلسلة نصية يمكن استخدام الخاصية length وفق التقنية التالية: browserType[browserType.length - 1]; وبما أن طول السلسة "mozilla" هو 7، سيكون رقم المحرف اﻷخير منها هو 6 لأن العد يبدأ من 0. لهذا استخدمنا في الكود أعلاه الأمر length-1. التحقق من وجود سلسلة نصية ضمن أخرى قد ترغب أحيانًا في إيجاد سلسلة نصية ضمن أخرى أطول، لهذا يمكن أن تستخدم التابع ()includes الذي يأخذ معاملًا واحدًا وهو السلسلة النصية التي تبحث عنها. ويعيد التابع القيمة true إن وجد هذه السلسلة و false إن لم يجدها. const browserType = "mozilla"; if (browserType.includes("zilla")) { console.log("Found zilla!"); } else { console.log("No zilla here!"); } وقد ترغب أيضًا بمعرفة إذا ما بدأت سلسلة نصية أو انتهت بسلسلة محددة، لهذا ستحتاج إلى التابعين ()startsWith و ()endsWith ويأخذ كلا التابعين معاملًا واحدًا هو السلسلة التي تبحث عنها في بداية او نهاية سلسلة أطول: const browserType = "mozilla"; if (browserType.startsWith("zilla")) { console.log("Found zilla!"); } else { console.log("No zilla here!"); } const browserType = "mozilla"; if (browserType.endsWith("zilla")) { console.log("Found zilla!"); } else { console.log("No zilla here!"); } إيجاد موقع سلسلة فرعية ضمن سلسلة أطول نستخدم لهذا الغرض التابع ()indexOf الذي يأخذ معاملين اﻷول هو السلسلة التي تبحث عنها والثاني اختياري ويشير إلى موقع بداية البحث. يعيد التابع موقع أول ظهور للسلسلة النصية، لكن إن لم يجدها يعيد القيمة 1-. const tagline = "MDN - Resources for developers, by developers"; console.log(tagline.indexOf("developers")); // 20 في مثالنا السابق يبدأ البحث من الموقع 0، ولو عددت المحارف بما فيها المسافات الفارغة من البداية فسيكون أول ظهور للسلسلة النصية "developers" في الموقع 20. console.log(tagline.indexOf("x")); // -1 يعيد البحث السابق القيمة 1- لأن المحرف x غير موجود ضمن السلسلة. طالما أنك تعلمت كيفية إيجاد الظهور اﻷول لسلسلة فرعية ضمن سلسلة أطول، فكيف ستجد ظهورات أخرى؟ يمكنك ذلك بتمرير قيمة أعلى من قيمة الظهور السابق للوسيط الثاني للتابع. const firstOccurrence = tagline.indexOf("developers"); const secondOccurrence = tagline.indexOf("developers", firstOccurrence + 1); console.log(firstOccurrence); // 20 console.log(secondOccurrence); // 35 نبلغ التابع في هذه الحالة أن يبدأ البحث عن النص بدءًا من الموقع 21 (firstOccurrence + 1) وأعاد القيمة 35 وهو موقع الظهور الثاني. استخلاص سلسلة نصية فرعية من سلسلة أطول وذلك باستخدام التابع ()slice الذي يُمرر له معاملان هما: موقع بداية الاستخلاص. موقع نهاية الاستخلاص ولا يؤخذ المحرف في آخر موقع للاستخلاص. إليك مثالًا: const browserType = "mozilla"; console.log(browserType.slice(1, 4)); // "ozi" إن المحرف الموجود في الموقع 1 هو "o" وفي الموقع 4 هو "l" لهذا يكون النتيجة هي السلسلة "ozi" التي تبدأ بالمحرف "o" وتنتهي قبل المحرف "l". أما إذا أردت استخلاص جميع المحارف التي تأتي بعد محرف معين، فلا تحدد قيمة للمعامل الثاني، بل مرر فقط موقع المحرف الذي تريد أن تبدأ الاستخلاص عنده. جرّب اﻵن ما يلي: browserType.slice(2); // "zilla" تُعيد الشيفرة السابقة النص "zilla" لأن المحرف في الموقع 2 هو "z" ولم نحدد قيمة للمعامل الثاني فستكون النتيجة جميع المحارف من نقطة بداية الاستخلاص حتى نهاية السلسلة. **ملاحظة للتابع ()slice خيارات أخرى يمكنك الاطلاع عليها في توثيق التابع ضمن موسوعة حسوب. تغيير حالة الحروف يغيّر التابع ()toLowerCase جميع حروف السلسلة إلى حروف صغيرة والتابع ()toUpperCase إلى حروف كبيرة، وهذا مفيد مثلًا إن أردت تسوية حالة جميع الحروف التي يدخلها مستخدم قبل تخزينها في قاعدة بيانات. جرّب أن تدخل اﻷسطر التالية لترى ما يحدث: const radData = "My NaMe Is MuD"; console.log(radData.toLowerCase()); console.log(radData.toUpperCase()); تحديث أجزاء من النص يمكن استبدال سلسلة فرعية من نص بسلسلة أخرى باستخدام التابع ()replace. ولتجريب الأمر نحاول أن نستبدل في المثال التالي السلسلة التي مررناها كمعامل أول للتابع بالسلسلة التي تمثل المعامل الثاني: const browserType = "mozilla"; const updated = browserType.replace("moz", "van"); console.log(updated); // "vanilla" console.log(browserType); // "mozilla" وتجدر الملاحظة أن التابع ()replace مثل العديد من توابع الكائن النصي لا يغير الكائن الذي استدعاه بل يعيد سلسلة نصية جديدة، لكن إن أردت تحديث المتغير اﻷصلي browserType، فعليك تنفيذ الشيفرة التالية مثلًا: let browserType = "mozilla"; browserType = browserType.replace("moz", "van"); console.log(browserType); // "vanilla" كما عليك أن تصرح عن browserType في هذه الحالة باستخدام letوليس const ﻷن الثابت لا يمكن تحديث قيمته. وانتبه إلى أن التابع ()replace يستبدل السلسلة عند أول ظهور فقط، لكن إن أردت استبدال كل حالات الظهور، عليك استخدام التابع ()replaceAll let quote = "To be or not to be"; quote = quote.replaceAll("be", "code"); console.log(quote); // "To code or not to code" تطبيقات عملية سندفعك في هذا القسم إلى بذل جهدك في العمل مع السلاسل النصية. ففي كل تمرين مصفوفة من السلاسل النصية وحلقة تعالج قيم كل سلسلة ومن ثم تعرضها على شكل قائمة نقطية. لا حاجة لفهم المصفوفات والحلقات حاليًا لأننا سنفصلها لاحقًا، وكل ما عليك فعله هو كتابة شيفرة برمجية تعرض السلاسل النصية بالشكل الذي نريده. لكل تطبيق زر إعادة ضبط "Reset" يمكنك استخدامه إن ارتكبت خطأً ليعيد كل شيء إلى ما كان عليه، وزر "Show solution" للاطلاع على الحل إن لم تتمكن من إيجاده. فلترة رسائل المعايدة عليك في هذا التمرين وضع رسائل المعايدة بعيد الميلاد على شكل قائمة، لها ضع الاختبار المناسب في البنية الشرطية ()if واختبر كل سلسلة نصية واطبعها ضمن القائمة إن كانت رسالة عيد ميلاد. See the Pen string -methods1 by Hsoub Academy (@HsoubAcademy) on CodePen. تصحيح حالة بداية الكلمات نقدم في هذا التمرين أسماء مدن في المملكة المتحدة لكن حالة بداية حروف بدايات الكلمات غير صحيحة في بعضها. لهذا عليك تغيير حالة الحروف في كل كلمة إلى حروف صغيرة ما عدا الحروف اﻷولى. إليك أحد الطرق لتنفيذ اﻷمر: حول حالة جميع الحروف في السلسلة النصية الموجودة في المتغير إلى حروف صغيرة وخزنها في متغير جديد. استخلص الحرف اﻷول من السلسلة وخزّنه في متغير آخر. استبدل الحرف اﻷول من المتغير الذي أنشأته في الخطوة 2 بقيمة المتحول الذي أنشأته في الخطوة 2 بعد تحويل قيمته إلى حروف كبيرة. غيّر قيمة المتغير result كي تساوي نتيجة الخطوة 3. ملاحظة وتلميح: ليس من الضروري أن يكون معامل توابع السلاسل النصية نصًا بل قد يكون عددًا أو متغيرًا أو تابعًا آخر. See the Pen string-methods2 by Hsoub Academy (@HsoubAcademy) on CodePen. إنشاء نص جديد من أجزاء قديمة تتكون المصفوفة في هذا التمرين من عدة سلاسل نصية تتضمن معلومات عن محطات القطار شمال إنجلترا. وتمثل السلاسل النصية بيانات تضم رمز المحطة المكوّن من ثلاثة حروف متبوعًا بمجموعة بيانات تفهمها اﻵلة يليها فاصلة منقوطة يليها اسم المحطة المقروء بالنسبة للبشر مثلMAN675847583748sjt567654;Manchester Piccadilly لهذا نريد استخلاص رمز المحطة واسمها ووضعهما في سلسلة جديدة لها الشكل التالي: MAN: Manchester Piccadilly. ننصحك بتجريب الخطوات التالية: استخلص رمز المحطة المكون من ثلاثة حروف وخزنه في متغير جديد. جد موقع الفاصلة المنقوطة. استخدم موقع الفاصلة المنقوطة في استخلاص اسم المحطة المقروء بالنسبة للبشر وخزّنه في متغير آخر. ضم قيمتي آخر متغيرين مع سلسلة من حروف مناسبة لتحصل على الصيغة النهائية. غيّر قيمة المتغير result كي تساوي النتيجة النهائية. See the Pen Untitled by Hsoub Academy (@HsoubAcademy) on CodePen. الخلاصة لا يمكن أن نتغاضى عن أهمية التعامل مع النصوص في البرمجة بشكل عام وفي جافا سكريبت بشكل خاص لأن النصوص تتعامل مع الويب المبني على التخاطب مع البشر. وقد قدمنا في هذا المقال أهم توابع التعامل مع النصوص التي تلزمك حاليًا، والتي ستكون ركيزة تساعدك على فهم المواضيع اﻷكثر تعقيدًا في المستقبل. ترجمة -وبتصرف- للمقال Useful string methods اقرأ أيضًا المقال السابق: أساسيات التعامل مع النصوص في جافا سكريبت الدليل الشامل لتعلم جافا سكريبت السلاسل النصية (strings) في جافاسكربت تصميم النّصوص البرمجيّة: تنظيم JavaScript توابع الأنواع الأولية (primitives methods) في جافاسكربت
  6. يُعد مفهوم التصميم المتجاوب للويب responsive web design واختصارًا RWD نهجًا يسمح للصفحة أن تغيّر تخطيطها ومظهرها لتلائم الاتساعات المختلفة لشاشات الأجهزة والدقات المختلفة لها، وضمان الاستخدام الأمثل للمحتوى. لهذا سنساعدك في هذا المقال على فهم بعض التقنيات التي تحتاجها لتتقن التصميم المتجاوب. ننصحك قبل المتابعة في قراءة هذا المقال أن: تطلع على أساسيات HTML. تفهم أساسيات عمل CSS. تُعد عناصر HTML متجاوبة أساسًا وقابلة للانسياب وفقًا لتوجه نافذة العرض. فلو أنشأت صفحة ويب باستخدام شيفرة HTML فقط دون تنسيقات CSS وغيّرت أبعاد المتصفح، سيغيّر المتصفح عندها انسياب العناصر لتلائم نافذة العرض. قد يبدو الأمر للوهلة الأولى بأن التجاوب الأساسي الذي يقدمه المتصفح هو كل ما نحتاجه، إلا أن النصوص ذات الأسطر الطويلة مثلًا والتي تعرض بأكملها ضمن الشاشات الواسعة قد تكون صعبة القراءة. فإن قللنا اتساع السطر باستخدام تنسيقات CSS بإنشاء أعمدة أو إضافة حشوات حول المحتوى، قد يبدو حينها الموقع منكمشًا بالنسبة لمستخدمي الأجهزة أو المتصفحات قليلة الاتساع. لن تعمل أيضًا فكرة صفحة ويب ثابتة الحجم بتثبيت اتساع الصفحة لأنه سيؤدي إلى ظهور أشرطة التمرير ضمن نافذة عرض الأجهزة قليلة الاتساع ومساحة فارغة مبالغ فيها في الأجهزة التي تتمتع بشاشات واسعة. لهذا ظهر مفهوم التصميم المتجاوب للويب كنهج موجّه للتعامل مع مجموعة واسعة من الأجهزة بمختلف الأبعاد، إذ يسمح هذا النهج بالتكيف التلقائي مع الشاشات سواء عّرض محتوى الصفحة ضمن جهاز لوحي أو جوّال أو تلفاز أو ساعة. والتصميم المتجاوب كما أشرنا هو نهج وليس تقانة منفصلة، يصف مجموعة من الممارسات التطبيقية المستخدمة في بناء تخطيطات لمواقع الويب يسمح لها بالتجاوب مع أي جهاز يعرض محتواها. استخدم مصطلح الويب المتجاوب أول مرة من قبل إيثان ماركوتي عام 2010 في وصف الشبكات الانسيابية fluid grid والصور الانسيابية fluid image واستعلامات الوسائط media query التي تُستخدم في بناء محتوى متجاوب. لقد اقتُرح حينها استخدام الخاصية float للتخطيطات واستخدام استعلامات الوسائط لتحري اتساع شاشة الجهاز ووضع نقاط محددة (تتعلق بالأبعاد المفترضة للأجهزة) يتغير عندها التخطيط. ضُبطت أيضًا الصور الانسيابية كي لا يتجاوز اتساعها اتساع الحاوية باستخدام القاعدة ;max-width: 100%. وهكذا تصغر الصورة عندما يضيق العمود الذي يضمها لكن حجمها لايزيد عن الحجم الأصلي إن زاد اتساع العمود. وبهذا الطريقة تتغير أبعاد الصورة لتتسع إلى المحتوى دون طفحان ودون أن يزداد حجمها عن الحجم الأصلي وتتشوه عند ازدياد حجم الحاوية عن حجم الصورة. إن طرق تخطيط صفحات الويب العصرية باستخدام CSS متجاوبة بطبيعتها، ومنذ بدأت فكرة الويب المتجاوب ظهرت ميزات وأدوات لتسهيل تصميم مواقع الويب المتجاوبة. لهذا سنشير في بقية هذا المقال إلى الميزات المختلفة التي قد ترغب في معرفتها لإنشاء مواقع ويب متجاوبة. استعلامات الوسائط تسمح لك هذه الاستعلامات بتنفيذ اختبارات (كأن تكون شاشة المستخدم أكثر اتساعًا من قيمة محددة أو دقة محددة) وانتقاء تنسيق CSS مناسب للصفحة بما يتلائم مع حاجة المستخدم. يختبر الاستعلام التالي مثلًا إن كانت صفحة الويب معروضة كشاشة وسائط screen media (أي لا يمكن طباعتها كمستند) وإن كان اتساع نافذة العرض على الأقل 80rem. إن قواعد التنسيق الموجودة ضمن المحدد container. ستُطبق فقط إن تحقق الشرطين السابقين: @media screen and (min-width: 80rem) { .container { margin: 1em 2em; } } بإمكانك إضافة عدة استعلامات وسائط في صفحة التنسيقات لتعدّل تخطيطك وفقًا لنتائج تلك الاستعلامات، وبما يتلائم مع المقاسات المختلفة للشاشات. تُدعى النقاط التي تُطبق فيها استعلامات الوسائط ويتغير تخطيط الصفحة بنقاط الانتقال breakpoints. من أكثر المقاربات شيوعًا في استخدام استعلامات الوسائط هي استخدام تخطيط عمود وحيد للشاشات الضيقة (مثل شاشات الجوّال) ثم تبني تخطيط من عدة أعمدة عندما تتحقق من خلال الاستعلامات أن اتساع الشاشة أصبح ملائمًا لذلك. يُعرف تصميم الصفحات لتلائم أجهزة الجوال بمصطلح "الجوّال أولًا mobile first". من الممارسات المفضلة عند استخدام نقاط الانتقال تعريف الأبعاد بصفتها وحدات نسبية relative unites بدلًا من الوحدات المطلقة لكل جهاز. سترى أيضًا عدة مقاربات تنسيق ضمن كتلة الاستعلام منها ربط ملفات تنسيق بصفحة الويب من خلال العنصر <link> وفقًا لأبعاد مختلفة للمتصفح أو استخدم متغيرات مخصصة لضبط بعض الخاصيات وتخزين القيم الملائمة لها عند كل نقطة انتقال. تساعد استعلامات الوسائط في التصميم المتجاوب لكنها ليست ضرورية، إذ يمكن استخدام الشبكات المرنة والوحدات النسبية والقيم العظمى والصغرى للخاصيات دون الحاجة إلى استعلامات الوسائط. تقنيات التخطيطات المتجاوبة تُبنى المواقع المتجاوبة باستخدام الشبكات المرنة، بمعنى أنك لن تحتاج استهداف كل الاتساعات المحتملة للأجهزة بتخطيطات منفصلة لضمان دقة العرض. إذ تسمح لك الشبكات المرنة بتغيير ميزة أو إضافة نقطة انتقال لتغيير التصميم في الحالات التي يُعرض فيها المحتوى بشكل سيء. فلكي تضمن مثلًا أن طول الأسطر في نص لن يزيد إلى الحد الذي يعيق القراءة وذلك عندما تكون الشاشة واسعة، بإمكانك استخدام الأعمدة columns؛ وإن انكمش صندوق النص ليعرض مثلًا كلمتين فقط في السطر عندما تضيق الشاشة بإمكانك وضع نقطة انتقال لتغيير التخطيط. تتمتع عدة تخطيطات مثل التخطيط المتعدد الأعمدة وتخطيط الصندوق المرن وتخطيط الشبكة بقدرتها على التجاوب افتراضيًا. إذ تفترض جميعها أنك تحاول بناء شبكة مرنة وتساعدك على تنفيذ الأمر بأبسط الطرق. تخطيط متعدد الأعمدة تستطيع في هذه الحالة تحديد قيمة للخاصية column-count لتشير إلى العدد الأعظمي للأعمدة التي تريد توزيع المحتوى ضمنها. وعندها يحسب المتصفح عندها الاتساع المناسب لكل عمود وبما يناسب اتساع شاشة العرض. .container { column-count: 3; } بينما لو خصصت قيمة للخاصية column-width ستخصص في هذه الحالة أدنى اتساع للعمود، وسينشئ حينها المتصفح أكبر قدر ممكن من الأعمدة بهذا الاتساع بما يلائم اتساع الحاوية، وإن بقيت مساحة فارغة (بقية مساحة أقل من مساحة عمود) سيقسمها بالتساوي بين تلك الأعمدة. وهكذا سيتغير عدد الأعمدة بتغير المساحة المتوفرة. .container { column-width: 10em; } وكذلك الأمر، بإمكانك استخدام الخاصية المختصرة columns لتزويد المتصفح بأعلى عدد من الأعمدة وأدنى اتساع لكل منها. وهذا ما يضمن مثلًا ألا يصبح طول سطر الكتابة أكبر مما يسمح بتجربة قراءة مقبولة -وذلك عندما يزداد اتساع الشاشة- أو قصيرًا جدًا عندما تضيق الشاشة. الصندوق المرن تتقلص العناصر المرنة في تخطيط الصندوق المرن وتتمدد مغيرة مقدار المساحات المتاحة بين العناصر وفقًا للمساحة الكلية للحاوية المرنة. وبتغيير قيم الخاصيتين flex-grow و flex-shrink بإمكانك تحديد سلوك العناصر عندما تزيد المساحة الفارغة المحيطة بها أو تقل. سيأخذ كل عنصر مرن في مثالنا التالي نفس المساحة ضمن الحاوية المرنة باستخدام القاعدة flex: 1 وقد أشرنا إلى هذا الموضوع بتفصيل أوفى في المقال الذي يتحدث عن تخطيط الصندوق المرن. .container { display: flex; } .item { flex: 1; } ملاحظة: في مثال عن استخدام الصندوق المرن (اطلع على الشيفرة المصدرية)، بنينا تخطيطًا متجاوبًا بسيطًا يتضمن نقاط انتقال إلى الوضع متعدد الأعمدة عندما يزداد شاشة العرض وتقييدًا لأبعاد المحتوى الرئيسي باستخدام الخاصية max-width، إليك هذا المثال (اطلع على الشيفرة المصدرية أيضًا). شبكة CSS تسمح لك الواحدة fr في تخطيط الشبكة توزيع المساحة الفارغة المتاحة بين مسارات الشبكة. سنرى في مثالنا التالي كيف ننشئ شبكة حاوية بثلاث مسارات قياس كل منها 1fr وستكون النتيجة ثلاثة أعمدة يشغل كل منها جزءًا من المساحة المتاحة في الحاوية. يمكنك الاطلاع على تفاصيل أوفى عن استخدام الشبكة في مقال تخطيط صفحات ويب باستخدام خاصيات الشبكة في CSS .container { display: grid; grid-template-columns: 1fr 1fr 1fr; } ملاحظة: إن النسخة المتجاوبة المبنية على تخطيط الشبكة أبسط لأنه بالإمكان تعريف الأعمدة ضمن الصنف wrapper.: ألق نظرة على المثال (يمكنك الاطلاع على الشيفرة المصدرية أيضًا) الصور المتجاوبة لكي تضمن أن حجم الصورة لن يزيد عن حجم الحاوية، يمكنك استخدام المقاربة التالية: img, picture, video { max-width: 100%; } تُطبق هذه القاعدة على الوسائط المتعددة كي لا تطفح خارج الحاوية. ولا بد من إدراك أن استخدام صورة كبيرة الحجم ثم تصغيرها لتلائم الشاشات الضيقة سيهدر حزمة البيانات نظرًا لتزيل صورة أكبر من المطلوب. يساعد استخدام العنصر <picture> مع السمتين srcset و sizes للعنصر <img> في تقديم صور تتلائم مع نوافذ عرض مختلفة ودقات مختلفة. إذ يمكنك مثلًا إضافة صورة مربعة الشكل لأجهزة الجوال ونفس الصورة لكن على شكل مستطيل للحواسب المكتبية. ستتمكن باستخدام العنصر <picture> من تقديم قياسات مختلفة مع تلميحات (على شكل بيانات وصفية توضّح حجم الشاشة ودقة الصورة و الطريقة الأمثل لعرضها) يختار بعدها المتصفح الصورة الأكثر ملائمة لكل جهاز ليضمن المستخدم تنزيل الصورة ذات الحجم الأنسب للجهاز الذي يستخدمه. ومع استخدام مع الخاصية max-width لا حاجة بعد ذلك لاستخدام استعلامات الوسائط لتغيير أبعاد الشاشة، وستتمكن من استهداف نوافذ عرض مختلفة بصور تختلف في نسب أبعادها. كما يمكنك توجيه الصورة فنيًا (وضع رؤية فنية) باستخدام أحجام مختلفة للصورة ذاتها، باقتصاص الصورة أو استخدام أخرى بأبعاد مختلفة. يمكنك الاطلاع على مشكلة الرؤية الفنية ضمن مقال "استخدام الصور المتجاوبة في صفحات الويب" على أكاديمية حسوب. خطوط الكتابة المتجاوبة يُقصد بتجاوب خطوط الكتابة هو تغيير حجم الخط من خلال استعلامات الوسائط أو باستخدام وحدات قياس مرتبطة بنافذة العرض. استخدام استعلامات الوسائط للحصول على خطوط كتابة متجاوبة سنرى في مثالنا التالي عنوانًا من المستوى الأول ضُبط حجم الخط فيه على 4rem، ويعني ذلك أن الحجم سيكون أربعة أضعاف الحجم الأساسي للخط المستخدم. وهذا في الواقع حجم كبير لعنوان من المستوى الأول، ولا نحتاجه سوى في شاشة العرض الواسعة، لهذا أنشأنا أولًا عنوانًا بحجم أصغر، وبعدها استخدمنا استعلامًا يلغي الحجم الصغير ويستبدله بالحجم الأكبر إن كان اتساع الشاشة أكبر من 1200px html { font-size: 1em; } h1 { font-size: 2rem; } @media (min-width: 1200px) { h1 { font-size: 4rem; } } عدّلنا مثال الشبكة المتجاوبة السابق كي يتضمن أيضًا نوعًا متجاوبًا باستخدام الطريقة الموضّحة سابقًا. بإمكانك ملاحظة تبدّل حجم الخط في العنوان عندما يتغير التخطيط إلى تخطيط عمودين. في الهواتف المحمولة سيكون العنوان أصغر حجمًا: في الحواسب المكتبية سنرى الحجم الأكبر للعنوان: وكما رأينا في هذه المقاربة، لم نستخدم استعلامات الوسائط لتغيير تخطيط الصفحة، ويمكن استخدام الأسلوب ذاته في تغيير أي عنصر ليكون أسهل استخدامًا أو جاذبيةّ ضمن شاشات مختلفة الأبعاد. استخدام وحدات قياس نوافذ العرض للحصول على خطوط كتابة متجاوبة يمكن استخدام وحدات نافذة العرض vw في التصميم المتجاوب لخطوط الكتابة دون الحاجة إلى ضبط نقاط انتقال في استعلامات الوسائط. فالقيمة 1vw هي واحد في المئة من اتساع نافذة العرض، وبالتالي أيًا كانت شاشة العرض فستكون أبعاد حجم الكتابة مضبوطةً بالنسبة لها. h1 { font-size: 6vw; } تظهر المشكلة عند تكبير وتصغير النصوص فلن يتمكن من ذلك طالما أن حجم خط الكتابة منسوب إلى حجم نافذة العرض. وبالتالي لا يجب استخدام هذه الوحدات بمفردها. من الحلول المتاحة للمشكلة استخدام الدالة ()calc. إذ يمكنك إضافة القيمة المقدرة بواحدة vw إلى قيمة ثابتة مثل وعندها تحسب الدالة السابقة القيمة الجديدة مع بقاء النص قابلًا للتصغير والتكبير. فالقيمة vw تضاف إلى القيمة الناتجة عن التكبير أو التصغير. h1 { font-size: calc(1.5rem + 3vw); } وهكذا لا نحتاج سوى تحديد حجم الخط سوى مرة واحدة بدلًا من ضبط قيم لكل شاشة عرض باستخدام استعلامات الوسائط. سيزداد حجم النص الآن أو يقل وفقًا لاتساع شاشة العرض. الوسم <meta> الخاص بنافذة العرض إن ألقيت نظرة على الشيفرة المصدرية لصفحة متجاوية سترى عادة الوسم <meta> ضمن الترويسة كالتالي: <meta name="viewport" content="width=device-width,initial-scale=1" /> يجبر هذا الوسم متصفحات الهاتف المحمول أن تضبط اتساع نافذة العرض لتكون نفسها اتساع الجهاز، ومن ثم ضبط حجم الصفحة لتكون 100% من الحجم المحدد لها، وهكذا ستُعرض الصفحة بالشكل الأمثل على هذه الأجهزة. لماذا نحتاج إلى هذا الوسم؟ لأن متصفحات الهواتف المحمولة لا تكون صادقة تمامًا فيما يخص اتساع نافذة العرض. عندما ظهرت الهواتف الذكية، لم تُعرض معظم المواقع بالشكل الأفضل ضمنها. لهذا ضبطت الهواتف الذكية اتساع نافذة العرض على 980 بكسل وصيّرت الصفحة وفقًا لهذا القيمة ومن ثم عرضتها كنسخة مصغّرة عن نسخة الحواسب. وهكذا كان على المستخدمين تكبير وتصغير الصفحة للوصول إلى النقطة التي يريدون، وكان المظهر بالطبع سيئًا. وباستخدام السمة width=device-width تلغى القيمة الافتراضية للهاتف المحمول وتستبدل بالقيمة الحقيقية لنافذة العرض. ودون هذه السمة، قد لا يعمل التصميم المتجاوب الذي يعتمد على استعلامات الوسائط ونقاط الانتقال كما ينبغي ضمن أجهزة الهاتف المحمول، فإن كنت تستهدف مثلًا نقطة انتقال عند الاتساع 480 بكسل أو أقل واعتبر الهاتف أن استاع نافذة عرضه هي 980 بكسل فلن يرى المستخدم أبدًا تأثير نقاط الانتقال. الخلاصة يشير مصطلح التصميم المتجاوب إلى تصميم موقع أو تطبيق يتجاوب مع البيئة التي يُعرض فيها. وتُستخدم في ذلك مجموعة من ميزات CSS و HTML وبعض التقنيات الأخرى التي أصبحت أساسية الآن عند بناء مواقع الويب. فلن تجد حاليًا على الأغلب موقعًا يُعرض على هاتف محمول بنفس تخطيط الحواسب المكتبية لكن بشكل مصغّر أو أن تستخدم أشرطة التمرير الجانبية للوصول إلى مكان ما في الصفحة، لأن تصميم الويب المعاصر قد انتقل كليًا إلى نهج التجاوب. وقد أضحى من السهل أيضًا إنجاز تصاميم متجاوبة بالاستفادة من طرق تخطيط الصفحات التي تعلمناها في مقالات سابقة. فلو كنت حديث العهد بتطوير الويب، ستجد الكثير من الأدوات التي لم تكن موجودة في البدايات. لهذا من الأفضل أن تتحقق من تاريخ أي مادة تعليمية تستخدمها. وعلى الرغم من أهمية بعض المواد القديمة، إلا أن الميزات الجديدة في CSS و HTML تزوّدك بتصاميم أنيقة ومفيدة، أيًا كان الجهاز الذي يستعرض موقعك. ترجمة -وبتصرف- للمقال: Responsive design اقرأ أيضًا المقال السابق: التخطيط متعدد الأعمدة باستخدام CSS أساسيات تصميم الويب المتجاوب فلسفة تصميم الويب المتجاوب استخدام الصور المتجاوبة في صفحات الويب عرض محتوى صفحات الويب بتجاوب على الأجهزة المتعددة مدخل إلى التصميم المتجاوب والتصميم المتكيف
  7. تعرفنا في المقال السابق على بعض اﻷساسيات في علم اﻹلكترونيات مثل الجهد الكهربائي وشدة التيار وتعلمنا استخدام بعض العناصر اﻹلكترونة الساكنة passive component في تكوين بعض الدوائر البسيطة وقياس قيم الجهد والتيار باستخدام المقياس الكهربائي متعدد الوظائف (اﻵفو). نتابع في هذا المقال استعراض مفاهيم أخرى أساسية في تكوين الدوائر الإلكترونية ونلقي الضوء على بعض العناصر اﻹلكترونية التي تُدعى بالعناصر الفعّالة Active Components. ما تحتاجه لإكمال التمارين العملية في هذا المقال إليك قائمة بالعناصر الإلكترونية والتجهيزات اللازمة لإكمال التطبيقات العملية: بطارية جهدها 5 فولط. مقاومات قيمها 1.2، 2.2، 6.8، 10، 22 كيلو أوم مؤشرات ضوئية (ليد) تعمل عند جهد 5 فولط أو أقل (ثلاثة ويفضل من ألوان مختلفة). مكثفة سعتها 470 ميكرو فاراد وأخرى 330 ميكرو فاراد جهدها 16 فولط. ديودات من طراز 1N4007 (يكفي اثنان). ترانزستورات قطبية من الطراز 2N2222. ترانزيستور ذات أثر حقلي من النوع MOSFET وطراز 2N2905A (ثلاثة تكفي). لوحة اختبار مثقبة (إن أردت فاﻷمر اختياري) مقياس كهربائي متعدد الوظائف AV multi-meter. ترتيب العناصر اﻹلكترونية في الدوائر نشرح في هذا القسم طريقة توصيل العناصر اﻹلكترونية والهيكلية اﻷساسية للدوائر بشكل مبسط دون الخوض في التفاصيل لأنها تتطلب معارف رياضية متقدمة. الوصل على التسلسل والوصل على التفرّع وهما طريقتان لوصل العناصر في الدائرة اﻹلكترونية سنشرحهما بشكل مبسط: الوصل على التسلسل عندما نصل طرفي عنصرين معًا، ونترك طرفيهما اﻵخرين كي توصلا مع بقية عناصر الدائرة ندعو هذا الوصل وصلًا تسلسليًا. وقد نصل عنصرين أو أكثر وفق هذه الطريقة فيتكون فرع في الدائرة الكهربائية يمر في عناصره تيار ذو شدة محددة ويهبط الجهد عند طرفي كل عنصر ليكون الجهد الكلي بين طرفي هذه العناصر المتسلسلة هو مجموع هبوطات الجهود. الوصل على التفرع أو التوازي إذ وصلت رجلي عنصر أو طرفي عنصر مع بعضهما ثم وصلت كذلك الطرفين اﻵخرين مع بعضهما فإن هذا الوصل هو وصل على التفرع. وقد نصل عنصرين أو أكثر بهذه الطريقة فتتكون عدة فروع في الدائرة عددها هو عدد هذه العناصر الموصولة على التفرع. يكون هبوط الجهد متماثلًا في الفروع إذ وصل طرفاها إلى منيع التغذية الكهربائي بينما سيتوزع التيار على هذه الفروع حسب طبيعة كل فرع. وصل العناصر على التفرع إلى اليمين وعلى التسلسل إلى اليسار هيكلية الدائرة اﻹلكترونية تتكون الدائرة اﻹلكترونية بأبسط أشكالها من مصدر تغذية كهربائي وعنصر إلكتروني أو أكثر بحيث يخرج التيار الكهربائي من مصدر التغذية ويعود إليه. وعند ترتيب العناصر في الدائرة سواء على التسلسل أو التفرع أو بطريقة مختلطة نميّز فيها الأقسام التالية: العقدة: وهي نقطة التقاء ثلاثة فروع أو أكثر ولها قاعدة مهمة جدًا بخصوص التيارات المارة فيها وتنص أن مجموع شدات التيارات الداخلة إلى عقدة تساوي مجموع شدات التيارات الخارجة منها. أي إذا دخل على عقدة تيار شدته 3 أمبير وتفرّع إلى فرعين سيكون مجموع الشدتين في الفرعين الناتجين هو أيضًا 3 أمبير. الفرع: هو جزء من الدائرة مكون من عنصر واحد أو عدة عناصر موصولة على التسلسل. الحلقة: وهي دائرة فرعية محددة بعقدتين أو أكثر. وصل بعض العناصر على التسلسل والتفرع لكل عنصر إلكتروني وظيفة محددة وبالتالي طريقة ربط محددة في الدارة، وهكذا تبدأ الفروع والحلقات والعقد بالظهور لهيكلة الدائرة وتزداد صعوبة الحسابات الكهربائية. لكننا سنبقي اﻷمور في مقالنا بسيطة قدر اﻹمكان مبتعدين عن أية حسابات رياضية صعبة. وصل العناصر الإلكترونية على التسلسل والتفرع وصل منابع التغذية توصل منابع التغذية الكهربائية على التسلسل والتفرع لزيادة الجهد الكلي في الدائرة أو زيادة شدة التيار الذي يمكن للعناصر استجراره منها. عند وصل منبعي تغذية أو أكثر على التسلسل بوصل القطب الموجب للأولى مع السالب للثاني حصلنا على مصدر تغذية جهده الكلي يساوي مجموع جهدي المنبعين. فلو وصلنا بطاريتين جهد كل منهما 1.5 فولط على التسلسل سنحصل على مصدر تغذية جهده 3 فولط. وعند وصل منبعي تغذية على التفرع بوصل القطبين الموجبين معًا والسالبين معًا بحيث تكون اﻷقطاب المشتركة هي من تغذي الدائرة الكهربائية، سيتمكن مصدر التغذية الجديد من استجرار تيار أكبر لعناصر الدائرة، أو على اﻷقل تغذية الدائرة لفترة أطول. وصل المقاومات اتبع القواعد البسيطة التالية: وصل مقاومات على التسلسل يعطي مقاومة جديدة قيمتها مجموع قيم المقاومات السابقة. فلو كان لديك مقاومات قيمها 2 كيلو أوم فقط وتحتاج إلى مقاومة 6 كيلو أوم، صل عندها ثلاثًا منها على التسلسل. وصل مقاومتين لهما القيمة ذاتها على التفرع يعطي مقاومة قيمته نصف قيمة إحداهما ووصل ثلاثة لها القيمة ذاتها سيعطي مقاومة لها ثُلث قيمة إحداها وهكذا. فلو كان لديك مقاومات قيمها 3 كيلو أوم وتحتاج إلى مقاومة قيمتها 1 كيلو أوم صل ثلاثة منها على التفرع. وصل المكثفات اتبع القواعد البسيطة التالية: وصل مكثفتين لهما القيمة ذاتها على التسلسل يعطي مكثفة سعتها نصف سعة إحداهما ووصل ثلاثة لها السعة ذاتها سيعطي مكثفة لها ثُلث سعة إحداها وهكذا. فلو كان لديك مكثفات قيمها 10 ميكروفاراد وتحتاج إلى مكثفة سعتها 5 ميكروفاراد صل اثنتين منها على التسلسل. وصل مكثفات على التفرع يعطي مكثفة جديدة سعتها مجموع سعات تلك المكثفات. فلو كان لديك مكثفات سعاتها 1 ميكروفاراد فقط وتحتاج إلى مكثفة سعتها 4 فاراد ، صل عندها أربعةً منها على التفرع. وصل الديودات اتبع القواعد البسيطة التالية: توصل الديودات على التسلسل (مهبط>مصعد>مهبط>مصعد) لأسباب عديدة منها ضمان الحماية عند تيارات أعلى ومنها تخفيض الجهد أكثر بين طرفي الوصلة إذ يخفض كل ديود الجهد بحدود 0.6 فولط (وفق مادة تصنيعه). توصل الديودات على التفرع عندما لا تريد أن يؤثر توصيله على شدة التيار الذي يصل العنصر اﻹلكتروني التالي. تتوزع شدات التيار في الفروع الخارجة من عقدة كلًا حسب مقاومته المرجع المشترك (اﻷرضي) هذا المصطلح شائع كثيرًا ومربك كثيرًا، لهذا سنشرح اﻷمر بالبساطة الممكنة دون أية تعريفات مدرسية. تعمل الدوائر اﻹلكترونية بين نقطتين لهما جهد مختلف وتتحرك الشحنات من الجهد اﻷعلى إلى اﻷدنى. لكن عندما تضم الدوائر عددًا كبيرًا من العناصر وقد تضم أيضًا عدة مصادر تغذية نحتاج إلى نقطة مرجعية لنقيس الجهد عند أية نقطة من الدائرة بالنسبة لها تُدعى هذه النقطة بالمرجع المشترك أو اﻷرضي وقد تكون نقطة من الدائرة أو خارجها ونعتبر أن قيمة جهدها هو الصفر . لا تكترث كثيرًا اﻵن لهذا الموضوع، ففي معظم دوائرك التي ستغذيها من مصدر تغذية محدد اعتبر أن اﻷرضي هو القطب السالب لمصدر التغذية وأرح نفسك، وإن رأيت في أحد المراجع رمز المرجع المشترك وأردت تطبيق الدائرة الموجودة، صل اﻷرضي بالقطب السالب. نظرة ثانية إلى العناصر اﻹلكترونية: عناصر إلكترونية فعّالة العناصر الفعّالة Active Components هي عناصر تقدم الطاقة الكهربائية للدائرة أو تستهلك جزءًا من الطاقة لتؤدي وظيفتها أو تعمل على تضخيم اﻹشارات الكهربائية. من اﻷمثلة عنها مصادر التغذية التي تحدثنا عنها في مقالنا السابق وسنتحدث اليوم عن أحد أهم العناصر الفعالة وهو الترانزيستور Transistor. الترانزيستوارت الترانزيستور هو عنصر إلكتروني فعال يُستخدم كمفاتيح إلكترونية يمكن التحكم بها كهربائيًا أو كمضخمات لزيادة قوة اﻹشارة الكهربائية. تُستخدم هذه العناصر بكثرة في الدوائر اﻹلكترونية وهي اﻷساس في تصنيع الكثير الكثير من الدوائر المتكاملة Integrated circuits واختصارًا IC. آلية عمل الترانزستور إن الفكرة اﻷساسية خلف تصنيع الترانزستور هو استخدام تيار كهربائي صغير جدًا أو جهد كهربائي صغير جدًا كي نفتح الطريق أما التيار الكهربائي اﻷساسي للمرور ضمن العنصر المطلوب أو إيقافه. و الترانزيستورات أنواع مختلفة وفقًا لطبيعة تصنيعه وتجميع أحزاءه، ونميّز النوعين الرئيسيين التاليين: الترانزستورات القطبية: وتستخدم تيارًا صغيرًا للتحكم بمرور تيار كهربائي أكبر (التيار الرئيسي) يغذي العنصر المطلوب. يتكون هذا الترانزيستور من غلاف يخرج منه ثلاثة أرجل يُدعى أحدها مجمّع Collector والثاني قاعدة Base والثالث باعث Emitter. تغلق هذه الترانزيستورات بشكل طبيعي الطريق أما التيار الرئيسي لكن بمجرد مرور تيار صغير بين القاعدة والباعث تفتح الطريق أمام التيار الرئيسي ويتناسب عندها شدة التيار الرئيسي المار في العنصر الذي نريد التحكم به طردًا مع شدة التيار المار بين الباعث والقاعدة. ولهذه الترانزيستورات نموذجان، اﻷول هو الترانزيستور NPN ويفتح إن كان جهد القاعدة أكبر من جهد الباعث واﻵخر هو الترانزيستور PNP ويفتح إن كان جهد القاعدة أقل من جهد الباعث. الترانزستورات ذات اﻷثر الحقلي: لا حاجة في هذه الترانزيستورات إلى مرور تيار كهربائي بين أحد الرجلين حتى تعمل بل تحتاج إلى تطبيق جهد بسيط. تتكون هذه الترانزيستورات من ثلاثة أرجل أيضًا هي المصرف Drain ورمزه D واﻵخر بوابة Gate ورمزه G والثالث منبع Source ورمزه S. لهذه الترانزيستورات أنواع وتقنيات تصنيع مختلفة أكثرها فعند تطبيق جهد بسيط على البوابة يمر يفتح الترانزيستور للتيار الرئيسي الطريق كي يمر من المصرف إلى المنبع أو يغلق الطريق أمامه. وهذه هي الميزة الرئيسية الترانزستورات الحقلية عن القطبية فهي قد تكون في الوضع الطبيعي مغلقة أو مفتوحة وعند تطبيق جهد على البوابة تُفتح أو تُغلق الطريق امام التيار الرئيسي. لهذا السبب نجد تصنيفات أخرى له ومن الضروري الانتباه إليها لأن لكل منها فائدته في الدائرة وسنوضحها في الجدول التالي: الترانزيستور من النوع المعزِّز Enhancing الترانزيستور من النوع المبدد Depletion معزز بقناة N: يكون مغلق بشكل طبيعي لكن عند تطبيق جهد موجب صغير على البوابة يفتح مبدد بقناة N: يكون مفتوحًا بشكل طبيعي لكن عند تطبيق جهد سالب صغير على البوابة يُغلق معزِّز بقناة P: يكون مغلق بشكل طبيعي لكن عند تطبيق جهد سالب صغير على البوابة يفتح مبدد بقناة P: يكون مفتوحًا بشكل طبيعي لكن عند تطبيق جهد موجب صغير على البوابة يُغلق إلى اليمين ترانزيستور قطبي وإلى اليسار ترانزستور حقلي MOSFET استخدامات الترانزيستور للترانزستورات تطبيقات عملية كثيرة لكننا سنهتم فقط بعملها كمفاتيح إلكترونية، ولهذا الغرض فإن أكثر التوصيلات شيوعًا تكون على الشكل التالي: يوصل العنصر اﻹلكتروني (سواء مؤشر ضوئي أو غيره) والذي نريد التحكم بمرور التيار ضمنه بين الطرف الموجب لمصدر التغذية والمجمّع أو المصرف بينما يتصل الباعث أو المنبع مع الطرف السالب لمصدر التغذية أو المرجع المشترك (الأرضي). لكن ولأن الترانزيستور وظيفة أخرى لا نحتاجها هنا وهي وظيفة التضخيم، فمن اﻷفضل وصل مقاومة بين الباعث أو المنيع والمرجع المشترك كي نحدد شدة التيار التي يحتاجها العنصر اﻹلكتروني الذي نتحكم به. أما عن كيفية تطبيق الجهد على البوابة أو تمرير تيار التحكم (التيار الصغير) بين القاعدة و الباعث فهذا أمر يعود لك وفقًا لطبيعة الدائرة التي تصممها. تطبيق عملي: دارة تغذية مؤقتة لحفظ معلومات الدائرة في الذواكر ستجد مع تمرسك في تصميم الدوائر اﻹلكترونية أنك تحتاج إلى عناصر إلكترونية خاصة تُدعى الذواكر وتُستخدم لحفظ حالة الدائرة اﻹلكترونية عند إطفاء الدائرة أو عند حدوث خلل في التغذية الرئيسية كأن تحفظ قيمة عداد معين أو تخزّن توقيتًا مهمًا وغيرها. ومن غير المجدي الكتابة إلى الذاكرة في كل لحظة لأنها سترهق الذاكرة وتقصر عمرها الافتراضي الذي يقدر بعدد محدد من عمليات القراءة والكتابة. لهذا تزوّد الدوائر المماثلة بنظام تغذية ثانوي (بطارية ليثيوم دائرية عادةً) يعمل فقط ولفترة قصيرة جدًا عند انقطاع التغذية الرئيسية وذلك لتخزين حالة الدائرة. سنحاول في هذا التمرين تنفيذ مشروع لتحقيق الهدف ذاته. وفيه نحاكي مصدر تغذية رئيسي وآخر ثانوي عن طريق تشكيل مسريين موجبين ومسريين سالبين يمثلان مصدري تغذية منفصلين ثم نستخدم مكثفة تشحن من مصدر التغذية الرئيسي وعند انقطاع التغذية الرئيسية تفرّغ شحنتها مما يؤدي إلى مرور تيار في قاعدة ترانزستور ثنائي القطبية لفترة صغيرة حتى ينتهي تفريغها وخلال فترة التفريغ يمرر الترانزيستور التيار من مصدر التغذية الثانوي إلى مؤشر ضوئي يحاكي الذواكر ليضيء مستغلًا طاقة المنبع الثانوي كما تستغله عناصر الذاكرة لتخزين حالة الدائرة. نحتاج في هذا التطبيق إلى: مكثفة مستقطبة سعتها 330 ميكروفاراد جهدها 16 فولط. ترانزيستور قطبي من لطراز 2N2222. ديود من طراز 1N4007. مؤشران ضوئيان أخضر وأحمر جهد تشغيلهما لا يزيد عن 5 فولط. مقاومتين 2 كيلو أوم وأخرى قيمتها 10 كيلو أوم. منبع تغذية جهده 5 فولط. لوحة اختبار مثقبة. استخدم العناصر السابقة لتشكيل الدائرة التالية: دائرة إلكترونية على لوحة مثقبة تضم مكثف وديود وترانستور وبطارية ومقاومات ومؤشرات ضوئية صل رجل المقاومة 10 كيلو أوم إلى المسرى الموجب اليميني (الذي يمثل مصدر التغذية الرئيسي) والرجل اﻷخرى إلى الرجل اﻷطول للمؤشر الضوئي اﻷخضر ثم صل رجل المؤشر اﻷخرى إلى المسرى السالب. صل الرجل السالبة للمكثفة مع المسرى السالب ثم صل الرجل الموجبة مع مقاومة 2 كيلو أوم ثم صل الرجل اﻷخرى للمقاومة مع قاعدة الترانزيستور حتى تفرّغ المكثفة شحنتها عبر قاعدة الترانزيستور وتسمح له بتمرير التيار من مصدر التغذية الثانوي. صل مهبط الديود مع قاعدة الترانزيستور أيضًا ومصعده مع المسرى الموجب اليميني. إن الغاية من ذلك منع تيار شحن المكثفة من المرور عبر قاعدة الترانزيستور وفتح الترانزيستور فهذا يؤدي إلى تشغيل مصدر الطاقة الثانوي دون مبرر. في هذه الحالة يطبق الديود جهدًا موجبًا على القاعدة يعادل تمامًا جهد شحن المكثف فلن يمر تيار في القاعدة عندها ولن يفتح الترانزيستور. صل باعث الترانزيستور مع رجل مقاومة 2 كيلو أوم وصل الرجل اﻷخرى مع المسرى السالب ونستخدم هذه المقاومة لتحديد شدة التيار التي ستمر بالمؤشر الضوئي اﻷحمر الذي يحاكي الذواكر. صل أخيرًا الرجل الأطول للمؤشر الضوئي اﻷحمر مع المسرى الموجب اليساري (الذي يمثل التغذية الثانوية) والرجل اﻷخرى مع مجمع الترانزيستور، إذ يمر في هذا الفرع التيار الثانوي. صل القطب الموجب للبطارية بسلك مع المسرى الموجب اليميني وبسلك آخر مع المسرى الموجب اليساري ثم صل القطب السالب مع المسرى السالب المشترك (يمثل هنا مرجع مشترك). ستلاحظ أن المؤشر اﻷخضر سيضيء وفي نفس الوقت تُشحن المكثفة، ولن يضيء المؤشر اﻷحمر لأن الترانزستور الذي يتحكم بتيار التغذية الثانوي مغلق. اسحب السلك الذي يصل قطب البطارية الموجب مع المسرى اليميني محاكيًا انقطاع التغذية الرئيسية، عندها سبطفىء المؤشر اﻷخضر ويعمل المؤشر اﻷحمر لفترة حوالي 10 -20 ثانية ثم ينطفئ محاكيًا استخدام التيار الثانوي لفترة معينة كافية للذواكر بإنجاز عملها. هل يمكنك تفسير ما يحدث؟ مدخل إلى الدوائر الإلكترونية التماثلية والرقمية يُعد مفهومي المقدار التماثلي والرقمي أمرًا مهمًا في فهم التطبيقات المتقدمة لعلم اﻹلكترونيات، وقد لا تحتاج إلى التعمق في هذه المفاهيم حاليًا لكن من المفيد إلقاء نظرة عليهما. المقادير التماثلية نقول عن مقدار أنه تماثلي Analogue إذا تغيّرت قيمته تدريجيًا مع الوقت زيادة أو نقصانًا كزيادة شدة اﻹضاءة أو انخفاضها وتغير قيمة المقاومة تدريجيًا من قيمة إلى أخرى وارتفاع حرارة جهاز أو انخفاضها وهكذا. وتتميز هذه المقادير بأن تغيرها تدريجي بين القيمة العليا والدنيا. تُدعى الدوائر اﻹلكترونية التي تعطي خرجًا تماثليًا بالدوائر التماثلية، مثل الدوائر التي تتحكم بشدة اﻹضاءة أو شدة الصوت أو الحرارة. تطبيق عملي: إضاءة متفاوتة سنستفيد في هذا التطبيق من ترانزستورات حقلية نتحكم فيها بالتيار الذي يستجره المؤشر الضوئي بتغيير الجهد الموجب المطبق على بوابة كل منها. لهذا شكل الدائرة البسيطة التالية من ثلاث مقاومات 2 كيلو وواحدة 1 كيلو وثلاث ترانزستورات حقلية كالتي أرنا إليها في بداية الفقرة: دائرة إلكترونية على لوحة مثقية تضم ترانزستورات ومقاومات ومؤشرات ضوئية وبطارية لا تصل بوابة الترانزستور اﻷول (الرجل في المنتصف وحولها نقطة عادة) مع أي شيء وصل منبعه بمقاومة 2 كيلو أوم ومنها إلى المسرى السالب. صل الرجل اﻷطول للمؤشر الضوئي اﻷول مع المسرى الموجب واﻷخرى مع مصرف الترانزيستور. ضع هذه الدارة إلى يمين اللوحة المثقبة. صل بوابة الترانزستور الثاني مع مقاومة 1 كيلو أوم ثم صلها مع منبع التغذية الموجب. صل بعد ذلك منبعه ومصرفه بنفس طريقة الوصل السابقة. ضع هذه الدارة في الوسط. صل بوابة الترانزستور الثالث مع المسرى الموجب مباشرة، ثم صل منبعه ومصرفه كما في الحالتين السابقتين تمامًا. صل قطبي البطارية إلى المساري المناسبة، وراقب ما يحدث؟ هل تستطيع تحديد نوع الترانزستور الحقلي؟ المقادير الرقمية نقول عن مقدار أنه رقمي Digital إذا أخذ إحدى قيمتين فقط عليا ودنيا ولا يكون الانتقال بينهما تدريجيًا بل لحظيًا مثل تشغيل وإطفاء مؤشر ضوئي. تُستخدم القيمة الرقمية للتحقق من حالة شيء ما إن كان موصولًا أو مفصولًا. وتُبنى النظم المنطقية على أساس المقادير المنطقية فلو كانت قيمة الجهد عند نقطة ما 5 فولط مثلًا كانت القيمة المنطقية الموافقة هي 1 وإن كانت أقل من 1 فولط تكون القيمة المنطقية الموافقة 0 وهكذا. تطبيق عملي: بوابة AND منطقية باستخدام الترانزيستورات القطبية بوابة AND (معناها وَ بالعربية) هي عنصر إلكتروني يوصل التيار إلى خرجه إذا طبق على جميع مداخلها إشارة (تيار كهربائي طبعًا) أي حتى يعمل مثلًا المؤشر الضوئي الموصول إلى خرجها لا بد من تطبيق جهد ثابت على كل مداخلها. لتصميم بوابة AND ترانزيستورية ذات مدخلين ومخرج وتعمل كعنصر رقمي، شكّل الدائرة اﻹلكرتونية التالية من ترانزستورين قطبيين ومقاومتين أكبر من 20 كيلو أوم (كي لا نستهلك تيارًا كبيرًا) ومؤشر ضوئي: دائرة إلكترونية على لوحة مثقبة تضم ترانزيستورات ومقاومات ومؤشر ضوئي وبطارية صل مجمع الترانزستور الأول مع المسرى الموجب وصل باعثه مع مجمع الثاني ثم صل باعث الثاني مع الرجل اﻷطول للمؤشر الضوئي ورجله اﻷقصر مع مقاومة 2 كيلو أوم ومنها إلى المسرى السالب. يكون عندها باعث الترانزيستور الثاني هي مخرج البوابة أو رجل الخرج لها. صل قاعدة كل منهما بمقاومة أكبر من 20 كيلو أوم ثم صلهما إلى المسرى الموجب. تمثل القاعدتين مداخل البوابة أو أرجل الدخل. صل البطارية إلى اللوحة، ماذا سيحدث؟ سيعمل الضوء لأن كلا المدخلين متصلان بجهد محدد. افصل اﻵن أي مقاومة منهما أو كلاهما عن المسرى الموجب و ينطفئ المؤشر. ما يحدث أن وصل قاعدة الترانزيستور اﻷول إلى جهد موجب سيمرر التيار من باعثه إلى مجمع الثاني وإن وصلت قاعدة الترانزيستور الثاني أيضًا إلى جهد موجب سيمرر التيار بدوره إلى المؤشر. وسيؤدي فصل أي من القاعدتين إلى عدم مرور التيار إلى المؤشر الضوئي. تهانينا لقد صممت اﻵن ابسط دائرة متكاملة لها ثلاثة أرجل مدخلين ومخرج، هل يمكنك إضافة بوابة دخل إضافية؟ الخلاصة أكملنا في هذا المقال ما بدأناه في المقال السابق من حيث التوسع قليلًا في شرح مفاهيم جديدة في الدوائر اﻹلكترونية والتعرف على الترانزيستورات وهي عناصر فعّالة شديدة الأهمية من خلال عدة تطبيقات عملية مفيدة تمهد لنا الطريق لمفهوم الدارات المتكاملة التي سنناقشها في مقال لاحق. اقرأ أيضًا المقال السابق: أساسيات في عالم الإلكترونيات: التيار والجهد والعناصر الساكنة طريقة عمل الرابط الديناميكي مع المكتبات في معمارية الحاسوب ما هي لوحة أردوينو Arduino؟ تصميم وتنفيذ آلة موسيقية باستخدام لوحة راسبيري باي بيكو
  8. بدأنا في المقال السابق شرح طريقة إنشاء دوال خاصة بك في جافا سكريبت وسنتعلم في مقال اليوم أحد المفاهيم الأساسية حول الدوال وهي إعادة قيم من الدالة. إذ تعيد بعض الدول قيمًا هامة عند اكتمال تنفيذها، بينما لا تعيد دوال أخرى أي شيء. لذلك من المهم فهم القيم التي تعيدها الدوال وكيفية استغلالها وكيفية إعداد الدوال المخصصة التي بنيتها كي تعيد قيمًا مفيدة. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على: أساسيات علوم الحاسب. أساسيات HTML. أساسيات عمل CSS أساسيات جافا سكريبت ما هي القيم المُعادة Return values القيمة المعادة هي ما يحمله معناها تمامًا، أي القيم التي تُعيدها الدوال عندما يكتمل تنفيذها. ومن المؤكد أنك واجهت هذا النوع من القيم مرات عدة لكنك لم تفكر بها صراحة. سنعيد طرح مثال من المقال السابق: const myText = "The weather is cold"; const newString = myText.replace("cold", "warm"); console.log(newString); // Should print "The weather is warm" // the replace() string function takes a string, // replaces one substring with another, and returns // a new string with the replacement made تُستدعى الدالة ()replace للتعامل مع النص myText وتُمرر لها قيمتان: النص الذي نريد إيجاده ('cold'). النص الذي نستبدله به ('warm'). عندما ينتهي تنفيذ الدالة تعيد قيمة جديدة هي نص جديد بعد تنفيذ عملية الاستبدال. وتُخزّن النتيجة في الشيفرة السابقة والتي تتضمن هذه القيمة المعادة في المتغير newString. إن عُدت إلى توثيق الدالة ()replace في موسوعة حسوب ستجد معلومات كافية ومفيدة من المعلومات حول القيم المعادة وسنحاول اﻹشارة عليها ما أمكن في هذا المقال. ولا تعيد بعض الدوال أية قيم (يُيشار في توثيق هذه الدوال عادة إلى القيمة المعادة على الشكل غير محدد undefined أو لا توجد قيمة void). فلا تعيد مثلًا الدالة displayMessage التي بنيناها في المقال السابق أية قيمة عند تنفيذها، بل تعرض فقط صندوق الرسائل على الشاشة. تُستخدم القيم المعادة عمومًا عندما تكون الدالة خطوة متوسطة لحساب شء ما. إذ لا بد من استخدام الدالة لحساب قيمة ما تُستخدم لحساب القيمة النهائية. فبعد أن تحسب الدالة القيمة المطلوبة تعيدها ثم تُخزّن في متغيّر. بعدا يمكنك حساب هذا المتغير في حسابات أخرى. استخدام القيمة المعادة في دوال بنيتها كي تعيد قيمة من دالة مخصصة، استخدم التعليمة return. لقد رأينا ذلك سابقًا في المثال. إذ ترسم الدالة 100 دائرة عشوائية ضمن العنصر <canvas> في ملف HTML: function draw() { ctx.clearRect(0, 0, WIDTH, HEIGHT); for (let i = 0; i < 100; i++) { ctx.beginPath(); ctx.fillStyle = "rgba(255,0,0,0.5)"; ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); ctx.fill(); } } وضمن كل تكرار للحلقة، تُستدعى الدالة ()random لتوليد قيم عشوائية لإحداثيات الدائرة x و y ولنصف القطر على التتالي. تأخذ الدالة ()random معاملًا واحدًا (عدد صحيح) وتعيد عددًا عشوائيًا صحيحًا بين 0 وهذا العدد. وسيبدو اﻷمر كالتالي: function random(number) { return Math.floor(Math.random() * number); } كما يمكن كتابة الدالة كالتالي: function random(number) { const result = Math.floor(Math.random() * number); return result; } لكن بالطبع النسخة اﻷولى أسرع وأصغر. نعيد نتيجة الحسابات Math.floor(Math.random() * number) كل مرة نستدعي فيها الدالة، وتظهر هذه القيمة في مكان استدعاء الدالة ومن ثم تتابع الشيفرة. ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); فلو أعادت الاستدعاءات الثلاث للدالة ()random القيم بالترتيب 500 و 200 و 35 سيكون تنفيذ السطر في الواقع كما لو كان على الشكل: ctx.arc(500, 200, 35, 0, 2 * Math.PI); تُستدعى الدوال ()random في سطر الشيفرة السابق أولًا ومن ثم توضع نتيجة تنفيذها (القيم المعادة) مكانها ثم يُنفّذ السطر. تطبيق عملي: تابع خاص يعيد قيمة نحاول في هذا التطبيق بناء دالة خاصة بنا تعيد قيمة، لهذا اتبع الخطوات التالية: انسخ الملف إلى حاسوبك، وهي صفحة بسيطة تضم عنصر إدخال نصي <input> وفقرة نصية <p>. كما يوجد عنصر <script> لتخزين مرجع إلى كل من العنصرين السابقين في متغيرين. أضف دالة مفيدة ما إلى العنصر <script> تحت ما هو موجود: function squared(num) { return num * num; } function cubed(num) { return num * num * num; } function factorial(num) { if (num < 0) return undefined; if (num === 0) return 1; let x = num - 1; while (x > 1) { num *= x; x--; } return num; } لا غموض في شيفرة الدالتين ()squared و ()cubed اللتان تعيدان مربع ومكعب العدد الذي يُمرر إليهما، أما الدالة ()factorial فتعيد قيمة العاملي ! للعدد الذي يُمرر إليها (العاملي هو جداء تناقصي للعدد حتى الواحد). أضف طريقة لطباعة معلومات عن العدد الذي تدخله في مربع اﻹدخال النصي من خلال معالج الحدث التالي تحت الدوال الموجودة: input.addEventListener("change", () => { const num = parseFloat(input.value); if (isNaN(num)) { para.textContent = "You need to enter a number!"; } else { para.textContent = `${num} squared is ${squared(num)}. `; para.textContent += `${num} cubed is ${cubed(num)}. `; para.textContent += `${num} factorial is ${factorial(num)}. `; } }); احفظ التغييرات على الشيفرة وحمّل الصفحة من جديد في المتصفح. إليك بعض اﻹيضاحات حول معالج الحدث addEventListener في الخطوة الثالثة: بإضافة مترصد للحدث change ستُنفَّذ الدالة غير المسماة (المعامل الثاني لمترصد الحدث) في كل مرة يحدث فيها تغيير على عنصر اﻹدخال النصي، أي في كل مرة نكتب فيه قيمة جديدةً وتُرسل (مثل إدخال قيمة وإبعاد التركيز عن المربع النصي بالضغط على الزر Tab أو Return). تُخزّن القيمة الموجودة في المربع النصيinput عند تنفيذ الدالة غير المسماة في الثابت num. تطبع عبارة if رسالة خطأ إن لم تكن القيمة المدخلة عددًا. إذ تتحقق العبارة الشرطية إذا ما أعادت الدالة isNaN(num) القيمة true. وما تفعله هذه الدالة هو التحقق فيما لو كانت القيمة التي تمرر إليها عددًا أم لا، وتعيد true إن كانت بالفعل عددًا و false إن لم يكن كذلك. إن أعاد الشرط القيمة false، ستكون القيمة عددًا، وتطبع الدالة جملة ضمن الفقرة النصية توضح قيمة مربع ومكعب وعاملي العدد المدخل. إذ تستدعي العبارة الدوال ()squared و ()cubed و ()factorial لحساب القيم الموافقة. ملاحظة: إن كانت هناك أية مشاكل في تنفيذ هذا التمرين، وازن بين ما كتبته وبين النسخة الجاهزة من هذا التمرين على جت-هب (نفّذه مباشرة إن أردت!)، أو اطلب المساعدة. حان دورك اﻵن لكتابة الدالة الخاصة بك في جافا سكريبت نطلب منك اﻵن كتابة دالتين من تأليفك وأضفهما إلى المكتبة. نقترح عليك مثلًا دالة تحسب الجذر التربيعي لعدد وأخرى تحسب الجذر التكعيبي! أو محيط دائرة لها قطر معين! إليك بعض التلميحات المفيدة اﻷخرى عن الدوال: ألق نظرة على أمثلة أخرى لمعالجة اﻷخطاء في دالة. ومن الجيد عمومًا التحقق من قيمة أي معامل ضروري للدالة والتحقق من وجود نوع من القيم الافتراضية التي يأخذها هذا المعامل في حال كانت قيمة هذا المعامل خاطئة فهذا سيقلل احتمال ظهور اﻷخطاء. فكرّ بتأليف مكتبة من الدوال. فعندما تتقدم في مسيرتك البرمجية، سترى أنك تكرر الكثير من اﻷشياء مرات ومرات. لهذا سيفيدك كثيرًا وجود مكتبة خاصة بك من الدوال التي تنفّذ وظائف متنوعة تحتاجها باستمرار. وهكذا ستتمكن من نسخها ولصقها في الشيفرة الجديدة أو تدرجها في صفحة HTML عندما تحتاجها. الخلاصة وهكذا نكون قد أنهينا موضوع الدوال في جافا سكريبت وهي وكما لاحظت أمر شديدة الفائدة لأي مبرمج، وعلى الرغم من وجود الكثير من النقاط الأخرى التي يمكن التحدث عنها بخصوص الداوال لكنها يفترض أن تكون قد أصبحت مفهومة بالنسبة لك. إن وجدت أي شيء غير مفهوم، حاول مراجعة المقال مرة أخرى، ونرحب بأي تساؤل تطرحه في قسم التعليقات أسفل الصفحة. ترجمة -وبتصرف- للمقال Function return values اقرأ أيضًا المقال السابق: إنشاء دوال خاصة بك في جافا سكريبت الدوال Functions في جافاسكريبت الدوال وإعادة استخدام الشيفرة في جافا سكريبت نظرة تفصيلية على الدوال السهمية Arrow functions في جافاسكربت الميزات الجديدة في ES6: نطاق المتغيرات، الدوال السهمية والمعاملات المبدئية
  9. التخطيط متعدد الأعمدة هو أسلوب لترتيب العناصر في صفحات الويب ضمن أعمدة كما تُرتب أعمدة الصحف، وهذا ما سنشرحه في هذا المقال. عليك قبل البدء في قراءة هذا المقال أن: تطلع على أساسيات HTML. تتفهم أساسيات عمل CSS. مثال تمهيدي نختبر في هذا المثال التخطيط المتعدد الأعمدة والذي يشار إليه في الإنجليزية اختصارًا multicol. بإمكانك متابعة العمل معنا بعد تنزيل نسختك من الملف المخصص للتمرين وإضافة شيفرة CSS في الأماكن المناسبة. سترى في نهاية القسم مثالًا عما ينبغي أن تكونه الشيفرة النهائية. تخطيط من ثلاث أعمدة يضم الملف شيفرة HTML بسيطة جدًا مؤلفة من عنصر تغليف <div> يمتلك صنف التنسيق container وضمن عنصر التغليف ستجد عنوانًا وبعض الفقرات. سنحوّل عنصر التنسيق السابق إلى حاوية من ثلاث أعمدة باستخدام واحدة من الخاصيتين column-count أو column-width. إذ تأخذ الخاصية الأولى قيمتها على شكل أعداد وتنشئ أعمدة بمقدار هذه القيمة. فإن أضفت الشفرة التالية إلى تنسيق الصفحة وأعدت تحميلها ستحصل على ثلاثة أعمدة. .container { column-count: 3; } للأعمدة التي تنشئها اتساع مرن وسيعمل المتصفح على تقدير الاتساع الذي يأخذه كل عمود. See the Pen Multiple-column-1 by Hsoub Academy (@HsoubAcademy) on CodePen. ضبط اتسع العمود باستخدام column-width عدّل شيفرة CSS كي تستخدم column-width كما يلي: .container { column-width: 200px; } سيعمل المتصفح في هذه الحالة على إنشاء أكبر عدد من الأعمدة بما يتناسب مع اتساع الحاوية، ثم يقسم المساحة المتبقية على الأعمدة. ويعني ذلك أنك لن تحصل بالضرورة على الاتساع الذي تريده ما لم يكن اتساع الحاوية قابلًا للقسمة على هذا الاتساع. See the Pen Multiple-column-2 by Hsoub Academy (@HsoubAcademy) on CodePen. تنسيق الأعمدة لا يمكن تنسيق الأعمدة التي تنشئها باستخدام خاصيات تعدد الأعمدة بشكل منفصل، فلن تجد طريقة لجعل عمود أكثر اتساع من آخر أو أن تغير لون أو خلفية أحد الأعمدة فقط دون البقية. وعمومًا، لديك طريقتين لتغيير طريقة عرض الأعمدة: column-gap: لتغيير حجم المسافة الفارغة بين عمودين. column-rule: لإضافة فاصل بين عمودين. جرّب أن تغيّر في مثالنا حجم المسافة الفارغة بين الأعمدة باستخدام column-width وإسناد أية قيم تراها مناسبة إذ تقبل هذه الخاصية أية قيم لها واحدة الطول. أضف أيضًا فاصلًا بين الأعمدة باستخدام الخاصية column-rule التي تمثل خاصية مختصرة مشابهة للخاصية border وتضم ثلاثة خاصيات هي column-rule-color و column-rule-style و column-rule-width وتقبل نفس القيم التي تأخذها خاصيات border. .container { column-count: 3; column-gap: 20px; column-rule: 4px dotted rgb(79, 185, 227); } حاول أن تضيف أعمدة بتنسيقات وألوان مختلفة: See the Pen Multiple-column-3 by Hsoub Academy (@HsoubAcademy) on CodePen. من الجدير بالملاحظة هنا أن الفواصل لا تملك اتساعًا مخصصًا بها، بل تستقر في المسافة الفارغة بين الأعمدة التي حددتها باستخدام column-gap. لهذا ستحتاج إلى زيادة أبعاد المسافة الفارغة بين الأعمدة حتى تزيد اتساع الفواصل. الأعمدة المتمددة بالإمكان أن تجعل عنصرًا يمتد على جميع الأعمدة، وفي هذه الحالة ينتقل المحتوى إلى سطر جديد في النقطة التي يظهر فيها العمود الممتد ثم يكمل تحته ضمن مجموعة جديدة من الأعمدة. وحتى يمتد العنصر على جميع الأعمدة يجب أن تضبط قيمة الخاصية column-span على all. ملاحظة: من غير الممكن أن تجعل عنصرًا يمتد على عدد معين من الأعمدة، فإما أن يتمدد على كل الأعمدة all أو أن لا يتمدد أبدًا none. See the Pen Multiple-column-4 by Hsoub Academy (@HsoubAcademy) on CodePen. الأعمدة وتجزئة المحتوى يُجزّأ محتوى التخطيط متعدد الأعمدة، ويسلك أساسًا سلوك محتوى صفحات متعددة الوسائط كما يُلاحظ عند طباعة صفحة ويب. فعندما تحوّل المحتوى إلى حاوية متعددة الأعمدة فأنت تجزئ هذا المحتوى إلى أعمدة، ولكي يحدث ذلك لا بد للمحتوى من الانتقال إلى أسطر جديدة. الصناديق المجزأة يحدث انتقال المحتوى إلى أسطر جديدة أحيانًا في أماكن قد تسيء إلى تجربة القراءة. ولتوضيح الأمر، استخدمنا في المثال التالي تخطيطًا متعدد الأعمدة لتوزيع سلسلة من الصناديق لكلٍ منها عنوان ونص. سيظهر العنوان منفصلًا عن النص إذا حدث التجزئة بينهما. <div class="container"> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> <div class="card"> <h2>I am the heading</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. </p> </div> </div> .container { column-width: 250px; column-gap: 20px; } .card { background-color: rgb(207, 232, 220); border: 2px solid rgb(79, 185, 227); padding: 10px; margin: 0 0 1em 0; } See the Pen Multiple-column-5 by Hsoub Academy (@HsoubAcademy) on CodePen. ضبط الانتقال إلى سطر جديد مع الخاصية break-inside للتحكم بهذا الأمر، يمكننا استخدام خاصيات التجزئة التي تتحكم بانتقال المحتوى إلى سطر جديد في التخطيط متعدد الأعمدة. فلو استخدمنا مثلًا الخاصية break-inside بعد إسناد القيمة avoid لها ضمن المحدد card. الذي ينسّق الحاوية التي تضم العنوان والنص، سيمنع هذا من تجزئة المحتوى ضمن الحاوية. .card { break-inside: avoid; background-color: rgb(207, 232, 220); border: 2px solid rgb(79, 185, 227); padding: 10px; margin: 0 0 1em 0; } إن إضافة هذه الخاصية تُبقي الصندوق كما هو جزءًا واحدًا ولن يتجزأ المحتوى ضمنه بين الأعمدة. See the Pen Multiple-column-6 by Hsoub Academy (@HsoubAcademy) on CodePen. الخلاصة إلى هنا تكون قد وصلت لنهاية هذا المقال الذي تعلمت من خلاله طريقة استخدام الميزات الأساسية للتخطيط متعدد الأعمدة في CSS، وهي أداة مفيدة أخرى يمكنك استعمالها في تنفيذ تصاميم صفحات موقعك الإلكتروني عند اختيار طريقة التخطيط الملائمة لعملك. ترجمة -وبتصرف- للمقال: Multi-column layout اقرأ أيضًا المقال السابق: ضبط تموضع العناصر في صفحات ويب باستخدام CSS مدخل إلى تخطيط صفحات الويب باستخدام CSS مفاهيم أساسية في التعامل مع تخطيط الشبكة Grid Layout نبذة عن الطرق الجديدة في تصميم صفحات CSS تخطيط الصندوق المرن Flexbox في صفحات الويب
  10. نلقي الضوء في هذا المقال على طرق التعامل مع السلاسل النصية Strings، التي تمثل في لغة جافا سكريبت وفي لغات البرمجة عمومً الأجزاء المقتطفة من نص ما، ونناقش ما عليك معرفته بشكل أساسي حول السلاسل النصية مثل إنشائها وتجاوز إشارات التنصيص (استخدامها كما هي دون أية دلالات) وضم أو دمج عدة سلاسل نصية مع بعضها البعض. ننصحك قبل المتابعة في قراءة هذا المقال بالاطلاع على بعض المقالات السابقة مثل: أساسيات علوم الحاسب. أساسيات HTML. أساسيات عمل CSS. قوة الكلمات! الكلمات هي أساس التواصل البشري والويب وسط معرفي مبني أساسًا على النصوص وقد صممت لتعزز التواصل بين البشر وتبادل المعلومات، لهذا من المهم جدًا التحكم بطريقة عرض تلك النصوص. تتيح لك لغة التوصيف HTML بناء هيكل المحتوى النصي وإعطاءه دلالاته بينما تنسّق CSS هذا المحتوى وتعززه ويتمثل دور لغة جافا سكريبت في تقديمها لطرق مختلفة للتعامل مع النصوص واﻷعداد وتقديم ميزات مهمة مثل القدرة على عرض رسائل وعرض نوافذ لإدخال البيانات وترتيب العناصر كما نريد وغيرها الكثير. وما عرضناه من برامج حتى اﻵن في سلسلة مقالاتنا التي بدأناها بالتعرف على لغة جافا سكريبت تتضمن شكلًا من أشكال التعامل مع النصوص. التصريح عن السلاسل النصية قد تجد بداية أن طريقة التعامل مع النصوص في جافا سكريبت تتشابه مع طريقة التعامل مع اﻷعداد تقريبًا، لكن عندما تتعمق أكثر ستلاحظ بعض الاختلافات الواضحة. سنبدأ إذًا بإدخال بعض اﻷسطر في طرفية جافا سكريبت في متصفحك (اضغط "Ctrl" + "Shift" + "k" في فايرفكس): const string = "The revolution will not be televised."; console.log(string); عرّفنا في الأسطر السابقة متغيّرًا وهيأناه بإسناد قيمة نصية له ثم أعدنا هذه القيمة. لاحظ أن الاختلاف الوحيد عند تهيئة متغير نصي هو إحاطة القيمة بإشارتي تنصيص، وإن لم تفعل ذلك سترى رسالة خطأ. جرّب ما يلي: const badString1 = This is a test; const badString2 = 'This is a test; const badString3 = This is a test'; لن تعمل الأسطر السابقة، لأن أي قيمة نصية دون إشارتي تنصيص حولها سيفترضها المتصفح أسماءً لمتغيرات أو خاصيات أو كلمات محجوزة وما شابه. وعندما لا يجد المتصفح ما افترضه سيعرض رسالة خطأ (مثل "missing; before statement" بمعنى "إغفال ; قبل التصريح"). وعندما يرى المتصفح بداية السلسلة النصية لكنه لا يرى نهايتها التي تشير إليها علامة التنصيص الثانية سيعرض رسالة خطأ تشير إلى أنك لم تُنهي السلسلة النصية كما يجب ("unterminated string literal"). فإن واجهتك رسائل خطأ مشابهة لما ذكرناه فعد إلى شيفرتك البرمجية وتحقق من إشارات التنصيص حول السلاسل النصية. const badString = string; console.log(badString); سيعمل هذا المثال فقط إن صرحت بداية عن المتغير string، وسيكون للثابت badString قيمة string نفسها. علامة التنصيص المفردة والمزدوجة والمائلة بإمكانك أن تختار علامة التنصيص المفردة (') أو المزدوجة (") أو المائلة (```) لإحاطة السلسلة النصية. إليك مثالًا: const single = 'Single quotes'; const double = "Double quotes"; const backtick = `Backtick`; console.log(single); console.log(double); console.log(backtick); ولا بد من استخدام نفس إشارة التنصيص في بداية ونهاية السلسلة وإلا سترى رسالة خطأ: const badQuotes = 'This is not allowed!"; وبإمكانك عمومًا استخدام العلامات المزدوجة أو المفردة وفقًا لرغبتك الشخصية فلكلاهما العمل نفسه ومن اﻷفضل من الناحية العملية اختيار أحد اﻷسلوبين واتباعه في كامل مشروعك. وتُدعى السلاسل النصية المعرّفة بعلامة التنصيص المائلة بالقوالب المفسّرة template literals وهي مشابه من الناحية العامة للسلاسل النصية العادية مع بعض الميزات الخاصة: بإمكانك إدراج شيفرة جافا سكريبت ضمنها. بإمكانك التصريح عن القوالب المفسّرة على عدة أسطر. إدراج شيفرة جافا سكريبت ضمن نص بإمكانك تغليف شيفرة جافا سكريبت لعرض نتيجتها ضمن سلسلة نصية ضمن القالب {}$. إليك مثالًا: const name = "Chris"; const greeting = `Hello, ${name}`; console.log(greeting); // "Hello, Chris" استخدم نفس التقنية أيضًا لضم متغيرين معًا: const one = "Hello, "; const two = "how are you?"; const joined = `${one}${two}`; console.log(joined); // "Hello, how are you?" تُدعى عملية ضم السلاسل النصية بهذه الطريقة بتجاوز أو دمج النصوص concatenation سياق عملية التجاور لنلق نظرة على عملية التجاور من خلال المثال التالي: <button>Press me</button> <div id="greeting"></div> const button = document.querySelector("button"); function greet() { const name = prompt("What is your name?"); const greeting = document.querySelector("#greeting"); greeting.textContent = `Hello ${name}, nice to see you!`; } button.addEventListener("click", greet); See the Pen str-in-js by Hsoub Academy (@HsoubAcademy) on CodePen. استخدمنا في الشيفرة السابقة الدالة ()window.prompt التي تطلب من المستخدم اﻹجابة عن سؤال ضمن نافذة منبثقة يعرضها المتصفح، ويُخزّن النص الذي يكتبه ضمن متغيّر وهو name في حالتنا. ونعرض بعد ذلك نصًا يُظهر الاسم وقد أُدرج ضمن رسالة ترحيبية. دمج السلاسل النصية باستخدام "+" يمكن استخدام اﻷسلوب مع القوالب المفسّرة وليس مع السلاسل النصية النمطية، لكن باﻹمكان ضم سلسلتين نمطيتين باستخدام العامل +: const greeting = "Hello"; const name = "Chris"; console.log(greeting + ", " + name); // "Hello, Chris" لكن القوالب المفسرة تسهّل قراءة الشيفرة: const greeting = "Hello"; const name = "Chris"; console.log(`${greeting}, ${name}`); // "Hello, Chris" تضمين عبارات برمجية ضمن السلاسل النصية وذلك باستخدام القوالب المفسّرة كما هو حال المتغيرات وستدرج نتيجة تنفيذ العبارة البرمجية ضمن السلسلة النصية: const song = "Fight the Youth"; const score = 9; const highestScore = 10; const output = `I like the song ${song}. I gave it a score of ${ (score / highestScore) * 100 }%.`; console.log(output); // "I like the song Fight the Youth. I gave it a score of 90%." النص متعدد اﻷسطر تفسّر القوالب المفسّرة محرف الانتقال إلى سطر جديد وبالتالي يمكن استخدامها لكتابة السلسلة النصية على أكثر من سطر واحد لتسهيل قرائتها ولن يُعتبر الانتقال إلى سطر جديد نهاية عبارة برمجية ولن يولد ذلك أية أخطاء: const newline = `One day you finally knew what you had to do, and began,`; console.log(newline); /* One day you finally knew what you had to do, and began, */ ولتنفيذ الفكرة نفسها باستخدام السلاسل النصية النمطية لا بد من استخدام محرف الانتقال إلى سطر جديد (n\) ضمن السلسلة النصية وفي المكان الذي ينبغي الانتقال يه إلى السطر الجديد. إليك مثالًا: const newline = "One day you finally knew\nwhat you had to do, and began,"; console.log(newline); /* One day you finally knew what you had to do, and began, */ تضمين إشارة التنصيص ضمن سلسلة نصية طالما أننا نستخدم إشارات التنصيص لتحديد بداية ونهاية سلسلة نصية، فما الذي سنفعله إن احتجنا إلى وضع إشارة التنصيص ضمن نص أي أن تكون جزءًا من السلسلة النصية؟ نعرف طبعًا أنه أمر غير ممكن بالطريقة النمطية التالية: const badQuotes = "She said "I think so!""; ومن إحدى الطرق المتبعة لحل المشكلة استخدام نوع من علامات التنصيص ضمن السلسلة وآخر لتحديد بدايتها ونهايتها كالتالي: const goodQuotes1 = 'She said "I think so!"'; const goodQuotes2 = `She said "I'm not going in there!"`; أما الخيار اﻵخر فهو تجاوز escape إشارة التنصيص ضمن النص ويقصد بذلك إهمال وظيفتها كبداية أو نهاية السلسلة واعتبارها محرفًا عاديًا أي اعتبارها كنص وليس جزءًا من الشيفرة. لتنفيذ ذلك في جافا سكريبت نضع شرطة مائلة عكسية \ قبل المحرف الذي نريد تجاوزه. إليك مثالًا: const bigmouth = 'I\'ve got no right to take my place…'; console.log(bigmouth); بإمكانك استخدام نفس التقنية ﻹضافة محارف خاصة أخرى إلى النص. اﻷعداد مقابل السلاسل النصية ما الذي سيحدث إن حاولت ضم عدد إلى سلسلة نصية؟ لنجرّب ذلك: const name = "Front "; const number = 242; console.log(`${name}${number}`); // "Front 242" قد نتوقع ظهور رسالة خطأ لكن ذلك لا يحدث! في هذه الحالة يحوّل المتصفح اﻷعداد إلى نص تلقائيًا ومن ثم يضمها إلى النص. فإن كانت لديك متغير عددي تريد تحويل قيمته إلى نص أو نصي تريد تحويل قيمته إلى عدد، ستتمكن من ذلك باستخدام الدالتين String و Number. تحوّل الدالة ()Number القيمة التي تمرر إليها إلى عدد إن كان ذلك ممكنًا، جرّب ذلك: const myString = "123"; const myNum = Number(myString); console.log(typeof myNum); // number تحوّل الدالة ()Stringالقيمة التي تمرر إليها إلى نص، جرّب ذلك: const myNum2 = 123; const myString2 = String(myNum2); console.log(typeof myString2); // string ستجد أن هاتان الدالتان غاية في الأهمية في بعض المواضع، فعندما يُدخل المستخدم عددًا في حقل نصي على سبيل المثال، سيعامل العدد معاملة السلسلة النصية. لكن إن أردت استخدامه كعدد ﻹضافته إلى عدد آخر، لا بد من تمريره إلى الدالة ()Number لتتولى أمر تحويله إلى عدد. الخلاصة قدمنا في هذا المقال الأساسيات البسيطة للتعامل مع النصوص في جافا سكريبت وسنتابع في مقال قادم العمل شرح المزيد من التوابع الأصلية المضمنة في لغة جافا سكريبت والمخصصة للتعامل مع النصوص. ترجمة -وبتصرف- للمقال Handling text-strings in JavaScript اقرأ أيضًا المقال السابق: العمليات الرياضية على اﻷعداد في جافا سكريبت السلاسل النصية (strings) في جافاسكربت تصميم النّصوص البرمجيّة: تنظيم JavaScript توابع الأنواع الأولية (primitives methods) في جافاسكربت
  11. آخر ما يلزمنا ﻹكمال اللعبة ثنائية الأبعاد "تفادي الزواحف" التي بدأنا العمل عليها في مقال سابق هو بناء واجهة المستخدم user interface المخصصة عرض أشياء مهمة مثل النتيجة أو عبارة "انتهت اللعبة" وزر ﻹعادة اللعب. لهذا سننشىء في مقال اليوم مشهدًا جديدًا ثم نضيف عقدة من النوع CanvasLayer (واجهة مستخدم) باسم HUD وهي اختصار للكلمات "Heads-up display" بمعنى "شاشة المقدمة" والتي تعرض معلومات عن اللعبة وتظهر على شكل طبقة فوق نافذة عرض اللعبة. إنشاء واجهة اللعبة تسمح لك العقدة CanvasLayer في محرك الألعاب جودو GODOT برسم عناصر واجهة المستخدم على طبقة فوق بقية مشاهد اللعبة، وبالتالي لن تغطيها أية عناصر أخرى كاللاعب أو اﻷعداء. في لعبتنا الحالة، نحتاج لأن تعرض الواجهة HUD المعلومات التالية: النتيجة وتغيّرها ScoreTimer. رسالة مثل "انتهت اللعبة" أو "استعد!". زر البداية "ابدأ" لكي تبدأ اللعب. إن الصنف اﻷساسي لهذه العقدة هو Control، وسنحتاج في واجهتنا لنوعين من عناصر التحكم Control هما عنوان Label وزر Button، لهذا عليك إنشاء ثلاث عقد أبناء للعقدة HUD كالتالي: عنوان Label باسم ScoreLabel. عنوان Label باسم Message. زر Button باسم StartButton. مؤقت Timer باسم MessageTimer. انقر على العنوان ScoreLabel ثم اكتب رقمًا في الحقل Text ضمن الفاحص، وكما تلاحظ، فإن الخط المستخدم افتراضيًا للعقدة Control صغير وغير مناسب، لذلك سنستخدم خطًا موجودًا ضمن المجلد "font" يُدعى "Xolonium-Regular.ttf" كالتالي: في نافذة الفاحص وتحت اللوحة انقر على Theme Overridesثم Fonts ثم Font ثم اختر "تحميل" واختر الملف "Xolonium-Regular.ttf": زد حجم الخط إلى 64 في الحقل "Font Size" ثم كرر نفس العملية على العنوان اﻵخر وعلى الزر في المشهد. ملاحظة: للعقدة Control موقع وأبعاد لكنها تمتلك أيضًا ما يُعرف بالمربط Anchor الذي يحدد نقطة اﻷصل، وهي النقطة المرجعية لحواف العقدة. رتب العقد كما في لقطة الشاشة التالية، وبإمكانك سحب العقد إلى المكان الذي تريده يدويًا أو استخدم المربط لضبط الموقع بدقة أكبر: العنوان ScoreLabel أضف النص 0 اضبط المحاذاة اﻷفقية Horizontal Alignment والعمودية Vertical Alignment على Center. اختر القيمة Center Top لضبط المربط (الخاصية Anchor Preset). الرسالة Message أضف النص "تفادي الزواحف". اضبط المحاذاة اﻷفقية Horizontal Alignment والعمودية Vertical Alignment على Center. اضبط قيمة "نمط الالتفاف التلقائي Autowrap Mode" على Word وإلا سيبقى النص على نفس السطر. اضبط قيمة الخاصية Size X الموجودة على المسار Control>Layout>Transform على القيمة 480 اختر القيمة Center لضبط المربط (الخاصية Anchor Preset). الزر StartButton أضف النص "ابدأ". اضبط قيمة الخاصية Size X الموجودة على المسار Control>Layout>Transform على القيمة 200 والخاصية Size Y على القيمة 100. اختر القيمة Center Bottom لضبط المربط (الخاصية Anchor Preset). ا ضبط قيمة الخاصية Position Y الموجودة على المسار Control>Layout>Transform على القيمة 580. وأخيرًا، اضبط الخاصية Wait Time في المؤقت MessageTimer على 2، والخاصية One Shot على "فعّال ON" ثم أضف السكربت التالي إلى HUD: extends CanvasLayer # Notifies `Main` node that the button has been pressed signal start_game نريد اﻵن عرض رسالة مؤقتة مثل " استعد!" لهذا سنضيف الشيفرة التالية: func show_message(text): $Message.text = text $Message.show() $MessageTimer.start() علينا أيضًا معالجة الحالة التي يخسر فيها اللاعب، لهذا ستعرض الشيفرة التالية رسالة "انتهت اللعبة" لمدة ثانيتين ثم تعود إلى الشاشة الرئيسية وتعرض بعد توقف صغير الزر "ابدأ": func show_game_over(): show_message("Game Over") # Wait until the MessageTimer has counted down. await $MessageTimer.timeout $Message.text = "Dodge the\nCreeps!" $Message.show() # Make a one-shot timer and wait for it to finish. await get_tree().create_timer(1.0).timeout $StartButton.show() تُستدعى الدالة اﻷخيرة عندما يخسر اللاعب. ملاحظة: إن أردت أن توقف اللعبة لفترة وجيزة، بإمكانك استخدام الدالة ()create_timer العائدة لشجرة المشاهد بدلًا من استخدام عقدة مؤقت. وهذه الدالة مفيدة جدًا في إضافة تأخير زمني في الحالات المشابهة لحالتنا التي نرغب فيها الانتظار قليلًا قبل عرض زر "إبدأ". أضف الشيفرة التالية اﻵن لتحديث النتيجة: func update_score(score): $ScoreLabel.text = str(score) صل اﻹشارة ()timeout العائدة للمؤقت MessageTimer واﻹشارة ()pressed العائدة للزر StartButton ثم عدل الشيفرة لتصبح كالتالي: func _on_start_button_pressed(): $StartButton.hide() start_game.emit() func _on_message_timer_timeout(): $Message.hide() ربط المشهد HUD بالمشهد الرئيسي Main بعد أن انتهينا من إنشاء المشهد HUD سنعود إلى المشهد الرئيسي Main. انشئ نسخة من المشهد HUDضمن المشهد الرئيسي كما نسخنا مشهد اللاعب سابقًا. ويجب أن تبدو شجرة المشاهد كالتالي حتى يكون كل شيء في مكانه الصحيح: علينا اﻵن وصل وظائف المشهد HUD إلى السكربت الرئيسي، ويتطلب ذلك بعد اﻹضافات إلى المشهد الرئيسي. صل اﻹشارة start_game للمشهد HUD إلى الدالة ()new_game في المشهد الرئيسي بالنقر على نسخة HUD في المشهد الرئيسي ثم الانتقال إلى "عقدة" في الشريط الجانبي واختيار اﻹشارة start_game ثم النقر عليها نقرًا مزدوجًا لتظهر نافذة "قم بوصل اﻹشارة إلى الدالة" ثم النقر على زر "Pick" في أسفلها واختيار الدالة ()new_game. تأكد من وجود اﻷيقونة الخضراء إلى جوار ()func new_game في السكربت الرئيسي، ولا تنس إزالة الاستدعاء ()new_game من الدالة ()ready_ ﻷننا لا نريد أن تبدأ اللعبة تلقائيًا. عدّل الشيفرة الموجودة ضمن الدالة ()new_game لتعرض الرسالة "استعد!": $HUD.update_score(score) $HUD.show_message("Get Ready") كما عليك استدعاء دالة HUD الموافقة للدالة ()game_over في السكربت الرئيسي: $HUD.show_game_over() أضف أخيرًا الشيفرة التالية إلى الدالة ()on_score_timer_timeout_ كي يبقى عداد النتيجة متزامنًا مع التغيرات: $HUD.update_score(score) أصبحت اﻵن جاهزًا للعب! انقر على زر تشغيل المشهد، وإذا طُلب منك اختيار المشهد اﻷساسي اختر main.tscn. إزالة الزواحف القديمة عندما تنتهي اللعبة وتحاول اللعب مجددًا ستبقى الزواحف من اللعبة القديمة موجودة على الشاشة ومن اﻷفضل أن تختفي جميعها قبل البدء بلعبة جديدة. إذًا لابد من طريقة ﻹخبار الزواحف بتدمير نفسها، وذلك باستخدام الميزة "المجموعات group". اختر المشهد ثم اختر العقدة الرئيسية وانقر على نافذة "عقدة" إلى جوار الفاحص وهو نفس المكان الذي تجد فيه اﻹشارات. انقر على العنوان "مجموعات" ثم اكتب اسمًا للمجموعة الجديدة وليكن "mobs" ثم انقر "أضف" وستظهر المجموعة الجديدة تحت الصندوق النصي: أضف السطر التالي إلى الدالة ()new_game في السكربت الرئيسي: get_tree().call_group("mobs", "queue_free") تستدعي الدالة ()call_group تابعًا محددًا (المعامل الثاني لها) باسمه وتطبقه على كل عناصر المجموعة المختارة (المعامل الأول)، وفي حالتنا يحذف كل زاحف نفسه. وضع اللمسات اﻷخيرة على اللعبة اكتملت اللعبة حاليًا من ناحية الوظيفة، وما سنفعله تاليًا هو بعض اﻹضافات لتحسين المظهر العام لها. الخلفية قد يجد البعض أن الخلفية الرمادية غير جذابة لذا دعونا نغير اللون. ومن الطرق المتبعة نجد العقدة ColorRect التي يجب وضعها تحت العقدة Main مباشرة كي تُرسم خلف جميع العقد. ولهذا العقدة خاصية واحدة هي Color. اختر اللون الذي تريده ثم انقر على Layout>Anchor Preset واختر "على كامل المستطيل"، كما يمكنك تنفيذ العملية من خلال شريط اﻷدوات أعلى نافذة العرض. بإمكانك أيضًا استخدام صورة في الخلفية إن أردت لكنك ستحتاج إلى عقدة من نوع TextureRect. إضافة تأثيرات صوتية للعبة مقاطع الصوت والموسيقى من أكثر العوامل التي تزيد من جاذبية تصميم الألعاب الإلكترونية، لهذا وضعنا في المجلد "art" الخاص بلعبتنا ملفين صوتيين الأول هو "House In a Forest Loop.ogg" لموسيقى الخلفية واﻵخر "gameover.wav" لخسارة اللاعب. وعلينا اﻵن إضافة عقدتين من النوع AudioStreamPlayer كأبناء للعقدة Main وتسميتهما باسم Music و DeathSound. انقر بعد ذلك على الخاصية Stream لكل منهما ثم "تحميل" واختر المقطع الصوتي الموافق. تُدرج المقاطع الصوتية تلقائيًا وتكون الخاصية Loop غير مفعلة لها بصورة افتراضية. فإن أردت أن تشغل الموسيقى دون توقف، فانقر على السهم المجاور لاسم الملف الصوتي في الخاصية stream ثم اختر "اجعله فريدًا" وانقر بعدها على المربع الذي يضم اسم العقدة الصوتية أعلى حاوية الفاحص واختر "stream" ثم فعّل قيمة الخاصية Loop. ولتشغيل الموسيقى أضف التابع ()Music.play$ إلى الدالة ()new_game والتابع ()Music.stop$ إلى الدالة ()game_over ثم أضف أخيرًا التابع ()DeathSound.play$ إلى الدالة ()game_over. اختصارات لوحة المفاتيح طالما أن التحكم باللعبة سيكون عن طريق لوحة المفاتيح، فمن الملائم جدًا أن نبدأ اللعبة بالضغط على أحد مفاتيحها. يمكن إنجاز اﻷمر بالاستفادة من الخاصية "Shortcut" للزر Button. لهذا سننشئ إجراء دخل يربط مفتاحًا بالزر "Start". انقر على مشروع>إعدادات الشروع ثم انقر على النافذة الفرعية "خريطة اﻹدخال" في النافذة التي تظهر. انشئ بعد ذلك وبنفس الطريقة التي أنشأت بها سابقًا إجراءات الحركة اﻷربعة إجراءًا جديدًا باسم start_game واربطه بالمفتاح Enter. وإن أردت أيضًا ربط أزرار أي أداة تحكم أخرى باﻹجراءات السابقة، تأكد من توصيل هذه اﻷداة ثم انقر اﻷيقونة "+" الموجودة إلى يمين كل إجراء ثم اضغط زر اﻷداة الذي تريد ربطه بهذا اﻹجراء. عد إلى الواجه HUD وانقر على الزر StartButton ثم ابحث عن الخاصية "Shortcut" ضمن "الفاحص" ثم انشئ اختصارًا جديدًا بالنقر على مربع النص المجاور واختيار "جديدة Shortcut" ثم النقر على الاختصار الجديد وفتح "Events" وإضافة حدث جديد بالنقر على "Array[InputEvent]". أنشئ حدث جديدة InputEventAction باسم start_game: وهكذا عندما يظهر زر "ابدأ" يمكن النقر عليه أو الضغط على المفتاح "Enter" لتبدأ اللعب! الخلاصة لقد انتهيت من تصميم أولى ألعابك ثنائية البعد وقد تعلمت إنشاء الشخصيات التي تتحكم بها والزواحف التي تتكاثر لتملأ الشاشة واستطعت حساب النتيجة وأنجزت طريقة لتبدأ اللعبة وتنهيها وتستخدم واجهة لها وأضفت مقاطع صوتية. تهانينا! لا زال هناك الكثير لتتعلمه بالطبع لتكون مطور ألعاب إلكترونية محترف، لكن خذ الآن قسطًا من الراحة واستمتع بإنجازك! ترجمة -وبتصرف- للمقالين: Heads_up display و Finishing up اقرأ أيضًا المقال السابق: بناء لعبة ثنائية البعد عبر محرك الألعاب Godot - الجزء الثالث: إنشاء المشهد الرئيسي في اللعبة تعرف على أشهر لغات برمجة الألعاب كيف تصبح مبرمج ألعاب فيديو ناجح دليلك الشامل إلى بناء كاميرا خاصة بشاشات اللمس في محرّك اﻷلعاب جودو
  12. لربما قادك الفضول يومًا ما إلى فك مقبض لعبة بلاي ستيشن لغاية ما أو حاولت فك جهاز التحكم عن بعد لشاشة العرض في المنزل لتجد الخلل فيه بعد أن جرّبت طريقة "اﻹصلاح بالضرب المتكرر"ولم تفلح! في كلتا الحالتين ستجد لوحة خضراء اللون غالبًا تنتظم عليها قطع مختلفة اﻷحجام واﻷشكال وتنتظم وفق ترتيب محدد تصل بينها خطوط ناعمة محفورة ضمن جسم اللوحة. إنها الدائرة اﻹلكترونية التي تعطي للجهاز وظيفته. وتحتاج معظم التجهيزات الكهربائية واﻹلكترونية إلى هذه الدوائر اﻹلكترونية لتنظيم تغذيتها بالطاقة الكهربائية والربط بين أجزائها المختلفة ونقل اﻹشارات فيما بينها لأداء الوظيفة المطلوبة. إن الغاية اﻷساسية من الدوائر اﻹلكترونية هو التحكم بجريان التيار الكهربائي ﻹنجاز عمل مفيد أو إرسال نبضات كهربائية (تُدعى إشارات) أو استقبالها. ويُعد علم اﻹلكترونيات أساسًا للكثير من العلوم اﻷخرى مثل الاتصالات وعلوم الحاسب إضافة إلى دوره المحوري في تطوير مختلف أنظمة التحليل والقياس والمراقبة. سيكون علم اﻹلكترونيات محور مقالنا الذي نحاول فيه توضيح الكثير من المفاهيم اﻷساسية من خلال أمثلة تطبيقية بسيطة مبتعدين قدر اﻹمكان عن التفاصيل المربكة والحسابات الرياضية. ما تحتاجه لإكمال التمارين العملية في هذا المقال إليك قائمة بالعناصر الإلكترونية والتجهيزات اللازمة لإكمال التطبيقات العملية: بطارية جهدها 5 فولط. مقاومات قيمها 1.2، 2.2، 6.8، 10 كيلو أوم مؤشرات ضوئية (ليد) تعمل عند جهد 5 فولط أو أقل (ثلاثة ويفضل من ألوان مختلفة). لوحة اختبار مثقبة (إن أردت فاﻷمر اختياري) مقياس كهربائي متعدد الوظائف AV multi-meter. مكثفة سعتها 470 ميكرو فاراد. ديودات من طراز 1N4007 (يكفي اثنان). مفاهيم أساسية في اﻹلكترونيات نغطي في هذه الفقرة بعض أساسيات الكهرباء الضرورية لفهم عمل مختلف العناصر اﻹلكترونية واختيار المناسب منها لدوائرك. الشحنات الكهربائية: حركتها وطاقتها تحمل الطاقة الكهربائية جسيمات دقيقة دُعيت سابقًا بالشحنات charges قبل أن تُكتشف طبيعتها الفعلية وهي اﻹلكترونات (ومن هنا جاءت التسمية علم اﻹلكترونيات). تستمد الشحنات الكهربائية طاقتها من عنصر في الدائرة اﻹلكترونية يُدعى الموّلد أو المنبع الذي يدفع هذه الشحنات إلى الحركة وينقل الطاقة الكهربائية إلى بقية عناصر الدائرة لتؤدي عملًا مفيدًا يستهلك جزءًا من الطاقة ويعود الجزء الباقي إليه فتكتمل الدائرة. تخيّل الأمر كما لو أن الشحنة الكهربائية هي سيارة مخصصة لنقل وجبات غذائية من المطبخ إلى نقاط العمل المختلفة في معمل ما. حيث تستهلك كل نقطة عمل كمية من الوجبات اللازمة للعمال فيها وتعود السيارات إلى المطبخ مع ما تبقى من وجبات. ولربما سمعت أن هنالك شحنات سالبة وأخرى موجبة، ولأن الموضوع معقد إلى حد ما، دعونا نتفق على أن الشحنة التي تحمل كامل طاقتها موجبة لأنها تساهم في تنفيذ اﻷعمال والشحنة التي استهلكت طاقتها وعادت إلى منبع الطاقة سالبة لأنه تستهلك طاقة المنبع. وهكذا تكون وظيفة المنبع تزويد الشحنات بالطاقة ثم تحريكها لنقل هذا الطاقة إلى النقاط المختلفة من الدائرة. مصادر التغذية الكهربائية المستخدمة في الدوائر اﻹلكترونية يُستخدم في الدوائر اﻹلكترونية نوعان من التيار الكهربائي اﻷول يُدعى تيارًا مستمرًا Direct Current ويرمز له اختصارًا DC واﻵخر هو التيار المتناوب Alternating Current ويرمز له اختصارًا بالرمز AC. يختلف كل من النوعين عن اﻵخر بطريقة توليدهما وانتقالهما في الدوائر لكننا سنتعامل غالبًا مع التيار المستمر في الدوائر اﻹلكترونية، وإن كان ولابد من استخدام المتناوب، ستجد في الدائرة اﻹلكترونية دائرة فرعية لتحويله إلى تيار مستمر أو تزوّد التجهيزة بمحوّل كهربائي خارجي يحوّل التيار المتناوب إلى مستمر ولربما عرفته سابقًا باسم "شاحن charger" عندما تصل الهاتف المحمول به لتشحنه! فالشاحن في الواقع هو محوّل كهربائي لتحويل التيار المنزلي المتناوب إلى مستمر. نحصل على التيار المستمر لتغذية دوائرنا الكهربائية من مصدرين أساسيين: البطاريات: ولها أنواع وأشكال مختلفة وتتراوح جهودها بين 1.5 فولط و 24 فولط (سنتحدث عن الجهد لاحقًا). ومنها ما هو قابل لإعادة الشحن بعد استهلاك طاقتها مثل بطاريات الهواتف المحمولة ومنها ما يستخدم لمرة واحدة مثل بعض بطاريات الألعاب لكن البطاريات القابلة للشحن بدأت تحل محلها تدريجيًا. للبطارية قطبان اﻷول موجب وتجد بجواره الرمز (+) أو يكون أحمر اللون، واﻵخر سالب وتجد بجواره الرمز (-) أو يكون أسود اللون. المحولات: ويستخدمها المحترفون أو الهواة المتمرسون إذ تتصل بتيار المنزل المتناوب وتحوّله إلى تيار مستمر قابل للضبط على القيم المطلوبة وتتميز هذه المحولات باستقرار عملها. وللمحولات مدخلين لتوصيلها مع التيار المتناوب، وتجد بجوارهما رموزًا مثل (~) أو (L) أو (N)، أو قد يأتي مع كابل لوصله مباشرة بمأخذ التيار المتناوب. وله أيضًا مخرجين للتيار المستمر أو أكثر أحدهما موجب واﻵخر سالب. تنبيه: يُرجى الحذر عند استخدام مصادر الطاقة الكهربائية وخاصة عند استخدام المحولات والبطاريات ذات الجهود المرتفعة. ويمنع اﻷطفال من التعامل معها إلا بوجود اﻷهل أو مدرّب مختص. الجهد الكهربائي وشدة التيار الجهد الكهربائي ببساطة هو الفرق بين طاقة الشحنات قبل دخولها إلى العنصر اﻹلكتروني وبعد خروجها ويحدد مصدر التغذية أعلى قيمة لطاقة الشحنات ويُقاس بواحدة الفولط volt ويرمز لها اختصارًا v. وتحتاج العناصر إلى مقدار معين من الطاقة حتى تعمل وإذا زاد مقدار هذه الطاقة أكثر من الحدود المسموحة ستُخرّب العنصر. لهذا تجد في ورقة مواصفات أية عنصر مجال الجهد الكهربائي الذي يعمل عنده. فالمؤشرات الضوئية تعمل عادة عند جهد يتراوح بين 3.5 إلى 5 فولط، وقد تجد أنواعًا تعمل عند جهد أعلى أو أقل لهذا نستخدم ما يناسب الجهد الأعظمي في الدائرة وهو جهد مصدر التغذية. فلو استخدمت بطارية توّلد طاقة مقدارها 5 فولط سيكون هذا الجهد هو أعلى جهد يمكن قياسه في الدائرة وبالتالي عليك استخدام عناصر إلكترونية قيمة جهودها أقل أو تساوي 5 فولط. أما شدة التيار الكهربائي فتمثل كمية الشحنات التي تمر في العنصر الكهربائي وكلما احتاج العنصر إلى كمية أكثر من الشحنات المحمّلة بالطاقة زادت شدة التيار التي يستجرها من مصدر التغذية والعكس صحيح. تقدر شدة التيار الكهربائي الذي يستجره العنصر بواحد اﻷمبير Amper ويرمز له اختصارًا A. يختلف استجرار العناصر للتيار الكهربائي وفقًا لطبيعة عملها فالمؤشر الضوئي مثلًا قد يحتاج إلى 100 ميلي أمبير (أي عُشر الأمبير). ويحاول مصدر التغذية عمومًا تزويدك بشدة التيار التي تحتاجها لكن إلى حد معّين يتعلق بطريقة تصميمه وقد تُذكر شدة التيار العظمى التي يقدمها المنبع أحيانًا وقد لا تذكر، لكن بشكل عام إن كان جهد تشغيل العنصر أقل من جهد مصدر التغذية، سيتدبر مصدر التغذية شدة التيار التي يحتاجها العنصر. تطبيق عملي: استخدام مقياس اﻵفو متعدد الوظائف AV mutit-meter يستخدم المقياس الكهربائي متعدد الوظائف لقياس الجهد الكهربائي بين طرفي العناصر اﻹلكترونية لمعرفة استهلاكها من الطاقة، كما يستخدم لقياس شدة التيار الكهربائي في أحد فروع الدائرة إضافة إلى العديد من القياسات اﻷخرى التي نتكلم عنها تباعًا. من أكثر المقاييس شيوعًا في وقتنا الراهن نجد المقاييس اﻹلكترونية التي تقيس قيمة الجهد أو شدة التيار وتعرضه رقميًا على شاشة الجهاز. يتكون المقياس بأبسط أشكاله من كابلين في نهاية كل منهما مسبر على شكل إبرة ومفتاح قابل للدوران ننقله إلى مجال القياس ونوع القيمة التي نقيسها. فإن أردت أن تقيس جهد التيار المستمر الذي نتوقعه بين 0 إلى 10 فولط، نحرّك المفتاح ليصل إلى مجال قياس الجهد المستمر (قد يكون له لون معين وتجد إلى جواره الرمز ⎓) ثم نحدد مجال القياس من 0-10 ونشغل المقياس. ونضع بعد ذلك نهايتي المسبرين على طرفي العنصر ونقرأ القيمة الظاهرة. جرّب أن تشكل الدائرة البسيطة التالية: دائرة إلكترونية على لوحة اختبار مثقبة تضم مقاومة وبطارية ومؤشر ضوئي نحتاج إلى بطارية جهدها 5 فولط وعنصر مقاومة بقيمة 5 أوم ومؤشر ضوئي يعمل عند جهد 5 فولط ومقياس آفو، أسلاك نحاسية مغلّفة ﻹجراء التوصيلات قطرها 0.5 ميلي متر ولوحة اختبار مثقبة. صل القطب الموجب للبطارية بسلك ثم اغرس نهايته اﻷخر في إحد المجاري الأفقية للوحة المثقبة وافعل اﻷمر ذاته مع القطب السالب وانتبه إلى عدم توصيلهما إلى نفس المجرى. صل بعد ذلك أحد أرجل عنصر المقاومة إلى المجرى الموجب والرجل اﻷخرى إلى أحد المجاري العمودية ثم صل الرجل الأطول للمؤشر الضوئي إلى نفس مجرى المقاومة وجله اﻷقصر إلى مجرى عمودي جديد ثم صل المجرى الجديد بسلك إلى المجرى السالب. سترى عندها أن المؤشر أصدر ضوءًا. قياس الجهد بين طرفي المؤشر الضوئي صل الكبل اﻷسود إن لم يكن موصولًا إلى المقياس بالمأخذ اﻷسود وستجد إلى جواره عادة الكلمة "COM"، ثم صل الكابل الأحمر بالمأخذ اﻷحمر وقد تجد إلى جواره الرمز (V). حرّك مفتاح الوظائف حتى يصل إلى مجال قياس الجهد المستمر وهو المجال المعلّم بالرمز (⎓). اختر المجال 10 أو 20 فولط (أي أنك تريد القياس في المجال بين 0 و 10 فولط أو 0 إلى 20 فولط وفقًا لنوع المقياس الذي تستخدمه). اضغط زر تشغيل المقياس. تظهر عادة على الشاشة القيمة 0.00 ويكون المقياس جاهزًا للعمل. ولقياس الجهد بين طرفي المؤشر ضع مسبري المقياس على رجلي المؤشر مباشرة أو ضمن المجريين الخاصيين بهما في اللوحة المثقبة واقرأ نتيجة المقياس بواحدة الفولط. قياس شدة التيار الذي يمر في الدائرة بدل مأخذ الكابل اﻷحمر إلى مأخذ قياس شدة التيار وتجد إلى جواره الرمز (A) أو (mA) وقد تجد مأخذين أحدهما أحمر اللون واﻵخر أسود، اختر المأخذ إن وجد. حرك مفتاح الوظائف إلى حتى يصل مجال قياس شدة التيار المستمر وهو المجال المعلّم بالرمز ثم اختر المجال (10 mA). اضغط زر تشغيل المقياس لقياس شدة التيار نستخدم أسلوبًا مختلفًا عن قياس الجهد ندعوه الوصل على التسلسل، لهذا عليك فصل رجل اﻷقصر للمؤشر الضوئي عن المجرى السالب ثم وصله بالمسبر اﻷحمر الموجب للمقياس ثم وصل المسبر الأسود السالب للمقياس مع القطب السالب، أي نوصل المقياس وكأنه جزء من تسلسل الدائرة. اقرأ النتيجة اﻵن بواحدة الميلي أمبير مقياس متعدد الوظائف يقيس إلى اليمين الجهد وإلى اليسار شدة التيار نظرة أولى إلى العناصر اﻹلكترونية اﻷساسية: العناصر الساكنة العناصر الساكنة Passive components هي عناصر مهمتها الفعلية استغلال التيار الكهربائي بتحويله إلى ضوء أو حرارة أو تبديده بكل بساطة أو إيقاف جريانه. فيما يلي شرحًا مبسطًا لبعض العناصر اﻹلكترونية الساكنة شيوعًا ومبررات استخدامها المقاومات المقاومة resistor هو عنصر تعيق تدفق الشحنات الكهربائية مسببة انخفاضًا في شدة التيار الكهربائي الذي يصلها. وللمقاومات انواع كثيرة تتعلق بطريقة تصنيعها، وتقاس قيمتها بوحدة اﻷوم Ohm. للمقاومة رجلان تواصلانها مع الدائرة، ولا فرق أين ستل كل رجل وأكثرها شيوعًا في عالم الهواة هي المقاومات السيراميكية التي تظهر على شكل قطعة منفوخة الطرفين وعليها خطوط ملونة تدلك وفق ترتيبها على قيمة هذه المقاومة. لكن إن لم ترد تعلّم قراءة هذه الخطوط حاليًا فاستعن بمقياس آفو. مقاومة سيراميكية في الأعلى ورمزها في المخططات الإلكترونية في الأسفل استخدامات عنصر المقاومة إن الاستخدام اﻷساسي للمقاومة هو تحديد شدة التيار الذي تريده أن يمر في فرع من فروع الدائرة. فلو عدنا إلى تطبيقنا العملي السابق الذي وصلنا فيه الدائرة التي التي تنير المؤشر الضوئي نلاحظ أننا استخدمنا مقاومة قياسها 5 كيلو أوم وذلك لجعل التيار الذي يمر في الدائرة (باعتبارها فرع واحد أو حلقة واحدة) هي 100 ميلي أمبير كي يتناسب مع التيار الذي يحتاجه المؤشر الضوئي لأن أية الشدة الزائدة للتيار ستؤدي إلى تخريب هذا العنصر. تطبيق عملي: مقاومات مختلفة وإضاءة مختلفة استخدم نفس منيع التيار الكهربائي الذي استخدمناه في المثال السابق ونفس اللوحة المثقبة (إن قررت استخدام واحدة) ثم ركب الدائرة البسيطة التالية المكونة من ثلاث مقاومات مختلفة وثلاث مؤشرات ضوئية: مخطط دائرة إلكترونية لتشغيل مؤشرات ضوئية بمستويات إضاءة مختلفة صل أولًا أحد أرجل المقاومة 1 كيلو أوم بالمسرى الموجب للوحة المثقبة ثم الرجل اﻷخرى بالرجل الطويلة للمؤشر الضوئي اﻷول والرجل اﻷقصر له بالمسرى السالب. كرر نفس الخطوات مع المقاومة 6.8 والمؤشر الضوئي الثاني ثم المقاومة 10 كيلو أوم والمؤشر الثالث. صل بعد ذلك القطب الموجب للبطارية مع المسرى الموجب والقطب السالب مع المسرى السالب. راقب ما يحدث وسجل النتائج في مذكرتك. تمرين إضافي: جرّب أن تستخدم مقياس اﻵفو لقياس هبوط الجهد وشدة التيار عند كل مقاومة بنفس أسلوب القياس الذي تعلمناه سابقًا. هل يمكنك ربط قيمة الجهد وشدة التيار وقيمة المقاومة مع بعضها البعض؟ المكثفات المكثفات Capacitors هي عناصر إلكترونية مهتمها التخزين المؤقت للشحنات الكهربائية. للمكثفات أشكال وأنواع عديدة ولكل منها استخداماته الخاصة، لكن أكثر ما قد تصادفه كهاوٍ ستجد المكثفات الكهرليتية اﻷسطوانية الشكل والمكثف السيراميكي عدسي الشكل (على شكل حبة العدس). مكثفتان سيراميكية عدسية إلى اليمين وكهرليتية مستقطبة إلى اليسار في الأعلى ورمز المكثفة في المخططات الإلكترونية في الأسفل للمكثفة سعة معينة لتخزين الشحنات الكهربائية وتقاس هذه السعة بوحدة الفاراد Farad ولأنها واحد كبيرة سترى أن الوحدات اﻷكثر استخدامًا هي الميكروفاراد (وهو جزء من مليون من الفاراد) والنانو فاراد (وهو جزء من بليون من الفاراد). تكتب قيمة السعة على جسم المكثفة اﻷسطوانية مباشرة وتعطى على شكل رموز على على العدسية.إضافة إلى ذلك لا بد من الانتباه إلى جهد الشن للمكثف ويكتب على غلافها مباشرة ولا يجب أبدًا وصلها إلى جهد أعلى من الجهد الاسمي المحدد لها. تتميز المكثفات الكهرليتية بأنها مستقطبة أي يجب وصل الرجل ذات القطبية الموجبة مع المسرى الموجب والرجل ذات القطبية السالبة مع المسرى السالب. نميّز الرجل السالب للمكثفة بوجود خط أبيض عريض طولي على جانب جسم المكثفة وبداخله إشارة (-). عند وصل رجلي المكثفة إلى مصدر تغذية كهربائي تبدأ بتجميع الشحنات خلال فترة زمنية محدد تتعلق بسعة المكثفة وجهد مصدر التغذية، لهذا يرتفع الجهد بين طرفيها وصولًا إلى جهد الشحن (جهد مصدر التغذية). تحتفظ المكثفة بشحنتها طالما لا تتصل بعناصر إلكترونية تستنزف شحنتها، لكن عند ربطها مع مقاومة مثلًا أو مؤشر ضوئي ونظرًا لكونها تمثل منبع تغذية ضعيف جدًا تستهلك تلك العناصر طاقتها (الشحنة المختزنة فيها) تدريجيًا ونقول أن المكثفة عندها في مرحلة تفريغ الشحنة. أين تستخدم المكثفات؟ تمنع المكثفات مرور التيار الكهربائي في دوائر التيار المستمر أو في فرع منها وذلك عندما تصل إلى كامل شحنتها. لكنها في المقابل لا تمنع مرور التيار المتناوب لطبيعتها الخاصة. لذلك ستجد أن استخدامها بالنسبة لك كهاوٍ أو مبتدئ ينحصر في عدة أعمال فقط: تزويد المفاتيح اﻹلكترونية (مثل الترانزستورات التي نتكلم عنها لاحقًا) بتارات أو جهود صغيرة خلال فترة وجيزة ومحسوبة كي تعمل هذه المفاتيح خلال هذه الفترة الصغيرة. لهذا اﻷمر عدد كبير جدًا من التطبيقات العملية. تنعيم التيار المستمر الناتج عن محوّلات تحويل التيار المتناوب إلى تيار مستمر. ترشيح الضجيج الناتج عن مصادر التغذية وخاصة المحوّلات، فالضجيج يشبه في طبيعته التيار المتناوب لهذا نستخدم المكثفة في تمريرها خارج الدائرة. تطبيق عملي: مراقبة تفريغ المكثفة استخدم المكثفة والمقاومتين والمؤشر الضوئي لتشكل الدائرة البسيطة التالية، واستخدم أسلاك التوصيل إن أردت: لوحة اختبار مثقبة المسرى السالب في الخط الأفقي الأول والموجب في الثاني مع مكثفة ومقاومة ومؤشر ضوئي وبطارية صل الرجل الأولى للمقاومة 2 كيلو أوم مع المسرى الموجب للوحة المثقبة ثم صل الرجل الثانية مع الرجل اﻷطول للمؤشر الضوئي. صل الرجل الثانية للمؤشر الضوئي. صل الرجل الأولى للمقاومة 10 كيلو أوم إلى الرجل الموجبة للمكثفة والرجل الثانية للمقاومة إلى المسرى الموجب. صل الرجل السالبة للمكثفة مع المسرى السالب. صل بعد ذلك القطب الموجب للبطارية بسلك مع المسرى الموجب والقطب السالب للبطارية مع المسرى السالب وراقب كيف يضيء الموشر مباشرة. اسحب السلك القادم من البطارية من المسرى الموجب، ماذا تلاحظ؟ عند تزويد الدائرة بالتغذية الكهربائية يضيء المؤشر الضوئي وتبدأ المكثفة بالشحن حتى تمتلئ، وبمجرد فصل القطب الموجب للتغذية عن الدائرة تفرّغ المكثفة شحنتها في الدائرة، لهذا لا ينطفئ المؤشر مباشرة بل ببطئ حتى تنفذ شحنة المكثفة. ثنائي المساري (الديود) ثنائي المسار اﻹلكتروني أو الديود diode وهو الاسم اﻷكثر شيوعًا هو عنصر إلكتروني ذو طبيعة خاصة يمرر التيار الكهربائي باتجاه واحد فقط ومن النقطة ذات الجهد اﻷعلى إلى النقطة ذات الجهد اﻷقل ولا يمرر التيار بشكل معاكس. صورة واقعية لديود في الأعلى وتمثيله في المخططات الإلكترونية في الأسفل ومن الميزات المهمة التي ينبغي الانتباه إليها عند استخدام الديود هو الجهد اﻷعظمي الذي يمكن تطبيقه بين طرفية فلا يجب أن تتجاوز قيمة الجعد القيمة العظمى المسموحة فقد يتعرض للاحتراق أو الانفجار. تُدعى رجل الديود التي توصل إلى النقطة اﻷكثر إيجابية بالمصعد Anode والرجل التي توصل إلى النقطة اﻷقل سلبية مهبطًا cathode، وبإمكانك تمييز المهبط من الخط اﻷبيض المجاور له على جسم الديود. ويشبه الدود في شكله شكل المقاومة لكنه أسود اللون دون انتفاخات في طرفيه. أين يُستخدم الديود للديود وظيفة واحدة هو منع التيار الكهربائي من المرور في أحد فروع الدائرة، ولهذه الوظيفة تطبيقات عملية كثيرة مثل: الحماية من عكس القطبية أي وصل القطب الموجب لمنبع التغذية بالخطأ إلى المسرى السالب للدائرة. تخفيض الجهد في أحد فروع الدائرة فكل ديود يخفض الجهد بحدود 0.6 فولط تقريبًا. تطبيقات خاصة بالتيار المتناوب وهي خارج إطار هذا المقال. تطبيق عملي: منع مرور التيار الكهربائي استخدم المقاومتين والديودين والمؤشرين الضوئيين لتنفيذ الدائرة البسيطة التالية: لوحة اختبار مثقبة تضم ديود ومؤشر ضوئي ومقاومة وبطارية صل مصعد الديود مع المسرى الموجب والمهبط مع طرف المقاومة، ثم صل طرفها اﻵخر مع الرجل اﻷطول للمؤشر الضوئي والرجل اﻷقصر مع المسرى السالب. صل مهبط الديود مع المسرى الموجب والمصعد من طرف المقاومة، ثم صل طرفها اﻵخر مع الرجل اﻷطول للمؤشر الضوئي والرجل اﻷقصر مع المسرى السالب. صل البطارية إلى مساري الدائرة، ولاحظ كيف يضيء أحد المؤشرين ولا يضيء اﻵخر، هل يمكنك تفسير ذلك؟ الخلاصة تعرفنا في هذا المقال على بعض أساسيات علم الكهرباء وألقينا نظرة علمية وعملية على بعض العناصر اﻷساسية الهامة في تكوين الدوائر اﻹلكترونية. سنتابع في الجزء الثاني من هذا المقال التعرف على أمور هامة في تكوين الدوائر اﻹكترونية ونتعرف على مزيد من العناصر المهمة. اقرأ أيضًا المقال السابق: دليلك الشامل إلى تعلم أساسيات التحكم وقيادة اﻵلات برمجة الروبوت: الدليل الشامل تجميع راسبيري باي والتحضير لاستخدامه تصميم وتنفيذ لعبة حسية تفاعلية باستخدام لوحة راسبيري باي بيكو تصميم وتنفيذ آلة موسيقية باستخدام لوحة راسبيري باي بيكو
  13. نقدم في هذا المقال مقاربة تطبيقية مبنية على المفاهيم اﻷساسية التي قدمتها المقالات السابقة. وستتعلم كيف تبني دوال مخصصة بنفسك وتطلع على بعض التفاصيل المفيدة عند التعامل مع الدوال أثناء دراستك لها المقال. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على: أساسيات علوم الحاسب. أساسيات HTML. أساسيات عمل CSS أساسيات جافا سكريبت كما شرحناها في سلسلة المقالات السابقة. تطبيق عملي: بناء دالة سنبني في هذا التمرين دالة باسم ()displaymessage مهمتها عرض مربع رسالة على صفحة ويب، وستعمل كبديل خاص بك عن الدالة المدمجة مع المتصفح ()alert.تحدثنا عن عمل هذه الدالة سابقًا لكننا سنعيدها لتتذكر بعض التفاصيل. لهذا اكتب الشيفرة التالية في طرفية جافا سكريبت في متصفحك: alert("This is a message"); تقبل الدالة alert وسيطًا واحدًا هو النص الذي تريد عرضه ضمن صندوق الرسالة، وبتغييرك هذا النص تتغير الرسالة ضمن الصندوق. لكن هذه الدالة محدودة القدرات، إذ ستتمكن من تغيير النص المعروض بسهولة لكن من الصعب تغيير أشياء أخرى كاللون واﻷيقونة وغيرها من التفاصيل. لهذا سنبني دالة أكثر متعة. ملاحظة: ينبغي أن تعمل الشيفرة ضمن جميع المتصفحات الحديثة، لكن قد يبدو التنسيق غريبًا قليلًا في المتصفحات اﻷقدم. لهذا ننصحك بتنفيذ هذا التمرين في متصفحات حديثة مثل فايرفوكس وأوبرا وكروم. الدالة اﻷساسية لنبدأ بتشكيل دالة أساسية مع التقيد بنفس قواعد التسمية المتبعة عند تسمية المتغيرات، فلا مشكلة في ذلك طالما أن الدوال يتبعها قوسان وبالتالي يمكن تمييزها عن المتغيرات. أنشئ نسخة خاصة بك من ملف HTM الخاص بالتمرين وستجده بسيطًا يحتوي جسمه على زر واحد ويضم أيضًا تنسيقات CSS أساسية لتنسيق صندوق الرسالة، كما ستجد العنصر <script> الذي يضم شيفرة جافا سكريبت الخاصة بالتمرين أضف الشيفرة التالية ضمن العنصر <script>: function displayMessage() { ... } تبدأ الشيفرة بالكلمة المفتاحية function والتي تعني أننا نعرّف تابعًا يليها الاسم الذي نريد تسمية الدالة به يليه زوج من الأقواس وزوج من اﻷقواس المعقوصة. ونضع أية معاملات نريد نعطيها للدالة داخل القوسين العاديين، بينما نضع الشيفرة التي تنفذها الدالة بين القوسين المعقوصين. أضف أخيرًا الشيفرة التالية ضمن القوسين المعقوصين: const body = document.body; const panel = document.createElement("div"); panel.setAttribute("class", "msgBox"); body.appendChild(panel); const msg = document.createElement("p"); msg.textContent = "This is a message box"; panel.appendChild(msg); const closeBtn = document.createElement("button"); closeBtn.textContent = "x"; panel.appendChild(closeBtn); closeBtn.addEventListener("click", () => panel.parentNode.removeChild(panel), ); يختار السطر الأول من الشيفرة العنصر <body> باستخدام الواجهة البرمجية لشجرة DOM للحصول على الخاصية body للكائن document الذي يمثل مستند HTML بالكامل ثم يسند قيمته لثابت يُدعى body: const body = document.body; يستخدم القسم الثاني أحد دوال الواجهة البرمجية ()document.createElement ﻹنشاء عنصر <div> ثم يخزّن مرجعًا إليه ضمن ثابت يُدعى panel. سيمثّل هذا العنصر الحاوية الخارجية لصندوق الرسائل. نستخدم بعد ذلك دالة أخرى ()Element.setAtrtribute لضبط السمة class العائدة للوحة صندوق الرسائل على msgbox كي يسهل تنسيق العنصر. فلو ألقيت نظرة على تنسيقات الصفحة ستجد أنها تحتوي على الصنف msgbox. لتنسيق صندوق الرسائل ومحتواه. نستدعي أخيرًا الدالة ()Node.appendChild للثابت body الذي عرَفناه سابقًا والتي تضع عنصرًا ضمن آخر كابن له. وخصصنا العنصر <div> ليكون ابنًا للعنصر <body> والسبب في ذلك ألا يظهر العنصر الذي ننشئه في مكانه الافتراضي في الصفحة بل نريد وضعه في مكان نخصصه له. const panel = document.createElement("div"); panel.setAttribute("class", "msgBox"); body.appendChild(panel); نستخدم تاليًا الدالتين ()createElement و ()appendChilde اللتان رأينا عملهما سابقًا في إنشاء عنصري فقرة نصية <p> والحاقهما في الصفحة كابنين للعنصر <div>. وبعدها نستخدم الخاصية Node.textContent والتي تمثل المحتوى النصي للفقرة لوضع الرسالة المطلوبة ضمن الفقرة النصية وإشارة "x" كعنوان للزر لتعكس وظيفته وهي إغلاق صندوق الرسائل. const msg = document.createElement("p"); msg.textContent = "This is a message box"; panel.appendChild(msg); const closeBtn = document.createElement("button"); closeBtn.textContent = "x"; panel.appendChild(closeBtn); ثم نستدعي في النهاية الدالة ()addEveentListener ﻹضافة دالة (دالة سهمية غير مسماة) تُستدعى عندما ينقر المستخدم على الزر ومهمتها حذف العنصر الذي يمثل صندوق الرسائل بأكمله من الصفحة. يُمرر للتابع ()addEveentListener الذي يمكن أن يستخدمه أي عنصر في الصفحة دالة أخرى واسم الحدث الذي ينبغي ترصده وهو في حالتنا "click"، أي ستُنفّذ الدالة عندما ينقر المستخدم على الزر ( سنتحدث بتفصيل أكثر عن اﻷحداث في مقال "مدخل إلى اﻹحداث في جافا سكريبت. أما الدالة التي نستخدمها عند وقوع الحدث فتضم دالة أخرى من دوال الواجهة البرمجية لشجرة المستند DOM وهي ()Node.removeChild التي تزيل ابنًا محددًا من أبناء العنصر وهو في حالتنا العنصر <div>: closeBtn.addEventListener("click", () => panel.parentNode.removeChild(panel)); تعرض الشيفرة السابقة طريقة إنشاء عناصر HTML برمجيًا وستضيف شيفرتنا السابقة إلى الصفحة مايلي: <div class="msgBox"> <p>This is a message box</p> <button>x</button> </div> لا تقلق إن لم تتذكر تمامًا كيف تعمل الشيفرة السابقة، فكل ما نهتم له اﻵن هو هيكلية الدالة التي أنشأناها واستخدامها. استدعاء الدالة عرفّنا اﻵن الدالة التي نريدها ضمن العنصر <script> بالشكل الصحيح، لكنها لن تفعل شيئًا بنفسها. جرّب أن تضيف السطر التالي تحت الدالة في الشيفرة: displayMessage(); يستدعي هذا السطر الدالة وينفذها مباشرة. فعندما تحفظ التغييرات وتعيد تحميل الصفحة، يعرض المتصفح الشيفرة في الصفحة مباشرة ولمرة واحدة، لأننا استدعيناها مرة واحدة. افتح أدوات مطوري ويب في نتصفح وانتقل إلى طرفية جافا سكريبت واكتب السطر السابق مجددًا وسترى كيف تظهر الرسالة مجددًا! حققنا إذا ما نريده وهي دالة يمكن استخدامها بشكل متكرر في أي وقت نشاء. لكن لربما من اﻷفضل استخدامها كاستجابة لحدث ما أو إجراء ما، وهذا ما يحدث في التطبيقات الواقعية، فصندوق الرسائل يظهر مثلًا كاستجابة لوجود بيانات جديدة أو وقوع خطأ ما، أو تنبيه لفعل ما كأن يحاول المستخدم حذف ملفه مثلًا فتكون الرسالة على الشكل "هل أنت متأكد من ذلك؟"، أو عندما يضيف المستخدم بنجاح جهة اتصال جديدة وهكذا. أما في مثالنا، سنعرض الرسالة عندما ينقر المستخدم على الزر. احذف السطر اﻷخير الذي أضفته إلى الشيفرة. ما سنفعله تاليًا هو اختيار الزر ثم حفظ مرجع إليه ضمن ثابت، لهذا أَضف الشيفرة التالية أعلى تعريف الدالة: const btn = document.querySelector("button"); أضف السطر التالي بعد السطر السابق: btn.addEventListener("click", displayMessage); وعلى غرار ما فعلناه للتعامل مع حدث النقر على زر اﻹغلاق closeBtn نستدعي في هذا السطر الشيفرة كاستجابة لحدث النقر على الزر، لكن بدلًا من استدعاء دالة غير مسماة سنستدعي الدالة التي أنشأناها ()displayMessage باسمها. احفظ التغييرات وأعد تحميل الصفحة، سترى اﻵن الرسالة فقط عندما تنقر على الزر. قد تتسائل لماذا لم نضع القوسين بعد اسم الدالة عندما نراها كمعامل لدالة ترصد الأحداث؟ السبب هو أننا لا نريد تنفيذ الدالة دون النقر على الزر. فلو غيرت الشيفرة لتصبح على الشكل: btn.addEventListener("click", displayMessage()); ثم حفظت التغيرات وأعدت تحميل الصفحة، ستظهر الرسالة مباشرة دون النقر على الزر. تُدعى اﻷقواس أحيانًا وفق هذا السياق "عامل تنفيذ الدالة function invocation operator"، وتسُستخدم عندما تريد تنفيذ الدالة مباشرة ضمن نطاق العمل الحالي. بالمقابل، لا تُنفّذ الشيفرة داخل الدالة غير المسماة مباشرة، لأنها ضمن نطاق الدالة التي تترصد الحدث. تراجع عن التغيرات السابقة إن جربت الفكرة السابقة قبل المتابعة. تحسين الدوال باستخدام المعاملات لا زالت الدالة بشكلها الحالي غير مفيدة، فلا نريد عرض نفس الرسالة دائمًا، لهذا سنحاول تحسين الدالة بإضافة معاملات تسمح لنا باستدعائها وفق عدة خيارات: عدّل بداية السطر اﻷول من الدالة ليصبح كالتالي: function displayMessage(msgText, msgType) { عندما نستدعي الدالة اﻵن، يمكننا تزويدها بمتغيرين ضمن القوسين لتحديد الرسالة التي تعرضها في صندوق الرسائل ونوع هذه الرسالة. للاستفادة من المعامل اﻷول، عدّل السطر التالي: msg.textContent = "This is a message box"; ليصبح بالشكل: msg.textContent = msgText; عليك اﻵن تعديل استدعاء الدالة لتضم نص الرسالة الجديد، لهذا عدّل السطر التالي: btn.addEventListener("click", displayMessage); ليصبح بالشكل: btn.addEventListener("click", () => displayMessage("Woo, this is a different message!"), ); إن أردنا أن نخصص معاملات ضمن دالة نستدعيها ضمن قوسي دالة أخرى، لا يمكننا استدعائها مباشرة، ولا بد من وضعها ضمن دالة غير مسماة، وبالتالي لن تكون ضمن مجال رؤية الدالة المستدعية مباشرة زلن تُستدعى مباشرة. وهكذا لن تُستدعى الدالة حتى ينقر المستخدم على الزر. أعد تحميل الصفحة مجددًا وسترى أنها لا تزال تعمل جيدًا، ما عدا أنك تستطيع تغيير الرسالة الموجودة ضمن المعامل لتعرض رسالة مختلفة في صندوق الرسائل. معامل أكثر تعقيدًا بالنسبة للمعامل اﻵخر، سيتطلب اﻷمر عملًا أكثر. إذ سنجعل صندوق الرسائل يعرض أيقونة مختلفة وخلفية ذات لون مختلف وفقًا لقيمة هذا المعامل (msgType). حمّل اولاً اﻷيقونات اللازمة لهذا التمرين (أيقونة التحذير وأيقونة المحادثة) ثم خزنهما في المجلد "icons". ابحث عن تنسيقات CSS داخل الملف لأننا سنجري بعض التغييرات لعرض اﻷيقونات، ثم عدّل اتساع صندوق الرسائل من width: 200px إلى width: 242px. أضف الشيفرة التالية داخل القاعدة {} msgBox p.: padding-left: 82px; background-position: 25px center; background-repeat: no-repeat; سنضيف اﻵن بعض الشيفرة إلى الدالة ()displayMessage لعرض اﻷيقونات بالشكل المطلوب. لهذا ضع الشيفرة التالية داخل القوسين المعقوصين للدالة: if (msgType === "warning") { msg.style.backgroundImage = "url(icons/warning.png)"; panel.style.backgroundColor = "red"; } else if (msgType === "chat") { msg.style.backgroundImage = "url(icons/chat.png)"; panel.style.backgroundColor = "aqua"; } else { msg.style.paddingLeft = "20px"; } إن كانت قيمة العامل msgBox هي warning ستُعرض أيقونة التحذير وتصبح لون خلفية صندوق الرسائل أحمر، وإن كانت قيمته chat ستُعرض أيقونة المحادثة ويصبح لون الخلفية أزرق مائي. إما إن لم تُضبط قيمة المعامل msgType أو أسندت إليه قيمة غير محددة، ستُنفَّذ الشيفرة داخل {}else وستأخذ الفقرة النصية الحاشية الافتراضية ولن تظهر اﻷيقونة ولن يُضبط لون الخلفية، وبهذا يكون هذا المعامل اختياريًا. لنجرّب اﻵن الشكل المعدّل للدالة ()displayMessage ونغيّر طريقة الاستدعاء من الشكل: displayMessage("Woo, this is a different message!"); لتصبح كالتالي: displayMessage("Your inbox is almost full — delete some mails", "warning"); displayMessage("Brian: Hi there, how are you today?", "chat"); لاحظ فائدة المعاملات في تحسين طريقة عمل الدوال. ملاحظة: إن لم تعمل الشيفرة أو واجهتك المشاكل، بإمكانك موازنة شيفرتك مع الشيفرة الجاهزة على جت-هب (أو تجريها مباشرة) أو طرح أية أسئلة في قسم التعليقات أسفل المقال أو في قسم الأسئلة والأجوبة في أكاديمية حسوب. الخلاصة حاولنا في هذا المقال السير بك تدريجيًا في بناء دالة مخصصة يمكن بقليل من العمل اﻹضافي أن تكون جاهزة للاستخدام في تطبيقات واقعية، ويبقى علينا مناقشة موضوع أساسي آخر يتعلق بالقيم التي يمكن للدوال أن تعيدها، وسنرى ذلك في مقالات قادمة. ترجمة -وبتصرف- للمقال: Build your own function اقرأ أيضًا المقال السابق:الدوال وإعادة استخدام الشيفرة في جافا سكريبت الدوال Functions في جافاسكريبت الدوال العليا في جافاسكريبت تعلم لغة جافا سكريبت من الصفر حتى الاحتراف
  14. تسمح لنا فكرة ضبط موقع العناصر بلغة CSS بإخراج عنصر من التخطيط الاعتيادي للمستند وتغيير سلوكه، كأن نقرر بأن يظهر فوق عنصر آخر أو يبقى دائمًا في نفس المكان ضمن نافذة عرض المتصفح. لهذا نشرح في هذا المقال القيم المختلفة للخاصية position وكيفية استخدامها. ملاحظة: يمكنك أن تنجز تمارين المقال على حاسوبك الشخصي، لهذا حاول أن تحضر نسخة من الملف 0_basic-flow.html من مستودع جيت-هاب (حمّل الشيفرة المصدرية أيضًا) واستخدامه كنقطة انطلاق. مدخل إلى تموضع العناصر يسمح لك تحديد مواضع العناصر في صفحة الويب في الحصول على نتائج مثيرة بتجاوز تنسيق الانسياب الاعتيادي. فماذا لو أردت أن تغيّر قليلًا موقع بعض الصناديق عن موقعها الافتراضي في الانسياب الاعتيادي لتمنح المستخدم تجربة خاصة مثلًا؟ سيكون تموضع العناصر الأداة المثالية لك في هذه الحالة. أو تخيّل أنك تريد أن تنشئ كائنًا في واجهة صفحتك يعوم فوق أجزاء أخرى أو أن يبقى دائمًا في مكانه ضمن نافذة المتصفح بصرف النظر عن تمرير المحتوى. سيساعدك توضيع العناصر أيضًا في إنجاز الأمر. توجد أنواع مختلفة لضبط مواضع العناصر، ولتحديد طريقة الضبط التي نحتاجها، سنستخدم الخاصية position ونوضح لك تاليًا خيارات مختلفة لاستخدامها. التموضع الساكن Static وهو التموضع الافتراضي لأي عنصر، ويعني "ضع العنصر في موقعه الطبيعي ضمن الانسياب الاعتيادي". ولكي ترى ذلك (وتحضّر الملف الذي ستتمرن عليه في الأقسام اللاحقة). أضف أولًا الصنف positioned إلى الفقرة النصية <p> الثانية: <p class="positioned">…</p> أضف الآن القاعدة التالية في نهاية شيفرة CSS: .positioned { position: static; background: yellow; } لن تجد عندما تحفظ التغيّرات وتعيد تحميل الصفحة أي اختلاف سوى لون الخلفية الجديد للفقرة النصية الثانية. وهذا بالفعل ما سيحدث فالتموضع الساكن هو التموضع الافتراضي للعنصر. التموضع النسبي Relative وهو أول التموضعات التي سنناقشها، ويشبه كثيرًا التموضع الساكن باستثناء أنه بمجرد أنك وضّعت العنصر في مكانه ضمن الانسياب الاعتيادي، بإمكانك عندها تعديل موقعه النهائي بما في ذلك وضعه فوق عناصر أخرى في الصفحة. لتوضيح الأمر، غيّر التصريح positioned في شيفرتك إلى: position: relative; لن تجد أي شيئ قد تغيّر أيضًا في هذه المرحلة إن حفظت التغيّرات وأعدت تحميل الصفحة، لكن كيف سنغير الموقع النهائي للعنصر؟ سنحتاج إلى استخدام الخاصيات top و bottom و left و right والتي سنشرحها تاليًا. الخاصيات top و bottom و left و right تستخدم هذه الخاصيات مع الخاصية position لتحديد المكان الذي تريد وضع العنصر فيه بدقة. لتجريب الأمر أضف إلى التصريح positioned. الشيفرة التالية: top: 30px; left: 30px; ملاحظة: يمكن أن تأخذ هذه الخاصيات قيمًا بأية واحدات مثل البكسل و mm و rem و %. إن حفظت لتغيرات الآن وأعدت تحميل الصفحة ستكون النتيجة كالتالي: See the Pen positioning-css1 by Hsoub Academy (@HsoubAcademy) on CodePen. لقد توضح الأمر قليلًا، أليس كذلك؟ لكن لا أعتقد أنك توقعت النتيجة. لماذا تحرّكت الفقرة نحو الأسفل واليمين مع أننا حددنا قيم الخاصيتين top و left. عليك أن تتخيل الموضوع كما لو كانت هناك قوة تدفع الفقرة من الجانبين السابقين (أعلى ويسار) وبالتالي ستنقل الفقرة نحو اليمين والأسفل. فلو كان ;top: 30px فيبدو الأمر كقوة تدفع صندوق الفقرة النصية من الأعلى نحو الأسفل وتحركه مقدار 30 بكسل. التموضع المطلق Absolute يأتي التموضع المطلق بنتائج مختلفة جدًا. ضبط الوضع المطلق غيّر قيمة الخاصية position كالتالي: position: absolute; لو حاولت حفظ التغيير وإعادة تحميل الصفحة ستجد النتيجة التالية: See the Pen positioning-css2 by Hsoub Academy (@HsoubAcademy) on CodePen. لاحظ بداية أن المكان المحجوز سابقًا للفقرة النصية الثانية في الانسياب الاعتيادي لم يعد موجودًا، وظهرت الفقرة النصية الثالثة بعد الأولى مباشرة. هذا الأمر صحيح نوعًا ما، فالعنصر الذي يأخذ توضعًا مطلقًا لن يظهر ضمن الانسياب الاعتيادي للعناصر، بل يتوضع ضمن طبقة خاصة به منفصلة عن الطبقة التي تضم عناصر الانسياب الاعتيادي. ولهذا الأمر فائدته، إذ يعني أنه بإمكاننا إنشاء واجهة مستخدم مستقلة لا تتداخل مع التخطيط الذي يضم بقية عناصر الصفحة. وكمثال عن هذه الواجهات نجد الصناديق المنبثقة ولوحات التحكم واللوحات القابلة للطي وعناصر واجهة المستخدم التي يمكن جرها وإفلاتها في أي مكان في الصفحة وغيرها. ونلاحظ ثانيًا أن موضع العنصر قد تغيّر، لأن سلوك الخاصيات top و bottom و left و right قد تغيّر مع التموضع المطلق. فبدلًا من توضيع العنصر بناء على موقعه بالنسبة إلى تخطيط الانسياب الاعتيادي، ستحدد تلك الخاصيات بعد صندوق العنصر عن حواف العنصر الحاوي. أي كأننا نقول في مثالنا أن صندوق الفقرة النصية ذات التموضع المطلق ستبتعد 30 بكسل عن الحافة العليا للعنصر الحاوي و 30 بكسل عن الحافة اليسرى له (إن العنصر الحاوي في حالتنا هي الكتلة الحاوية الأساسية initial containing block). ملاحظة: يمكنك استخدام top و bottom و left و right لإعادة تحديد أبعاد العناصر. جرّب مثلًا القيم التالية: ;top: 0 و ;bottom: 0 و;left: 0 و ; right: 0 و ;margin: 0 على العنصر الذي تحدد موضعه وراقب ما الذي سيحدث! أعد كل شيء إلى حاله عندما تنتهي. ملاحظة: تؤثر الهوامش على نوع العنصر، لكن لا تؤثر به خاصيات الهوامش المنقبضة Margin collapsing. سياق تموضع العناصر من هو العنصر الحاوي لعنصر ذو توضّع مطلق؟ يعتمد هذا الأمر كثيرًا على قيمة الخاصية position للعنصر الأب للعنصر المطلق. فإن لم يكن للعنصر عنصر أب قد حُددت قيمة الخاصية position له صراحةً فسيأخذ العنصر الأب التموضع الساكن. وتكون النتيجة أن يُحتوى العنصر المطلق ضمن الكتلة الحاوية الأساسية. للحاوية الأساسية أبعاد نافذة العرض وهي أيضًا الكتلة التي تحتوي العنصر <html> . وبعبارة أخرى، سيُعرض العنصر المطلق خارج حدود العنصر الأب ويتوضع بالنسبة إلى نافذة العرض. يقع العنصر المطلق ضمن العنصر <body> في شيفرة HTML المصدرية، لكن ستجده في التخطيط النهائي بعيدًا مسافة 30 بكسل عن الحد الأعلى للصفحة. بإمكاننا تغيير سياق توضع العنصر بمعنى كيفية توضعه المطلق وبالنسبة لأية عناصر. ننجز ذلك بضبط قيمة الخاصية position لأحد العناصر الآباء، أي العناصر التي يقع ضمنها العنصر ذو التموضع المطلق (إذ لا يمكن ضبط موقع عنصر بالنسبة إلى عنصر آخر إذا لم يكن ضمن هذا الأخير). لترى التأثير الذي نتحدث عنه، أضف التصريح التالي إلى القاعدة body: position: relative; من المفترض أن تحصل على النتيجة التالية: See the Pen positioning-css3 by Hsoub Academy (@HsoubAcademy) on CodePen. ضُبط موقع العنصر الآن بالنسبة إلى العنصر <body>. الخاصية z-index ما تقدمه فكرة التموضع المطلقة أمر ممتع، لكن هناك ميزة أخرى لم نذكرها بعد. فقد يبرز سؤال مهم عندما تتراكب العناصر فوق بعضها يتعلق بالعنصر الذي سيظهر فوق الجميع. ففي مثالنا حتى الآن، لدينا عنصر واحد قد غيّر موضعه وقد ظهر أعلى جميع العناصر الأخرى لأنها غير موضّعة، فما الذي سيحدث إذًا عندما نحدد موضع أكثر من عنصر؟ أضف شيفرة CSS التالية لتوضّع الفقرة النصية الأولى توضّعًا مطلقًا أيضًا: p:nth-of-type(1) { position: absolute; background: lime; top: 10px; right: 30px; } سترى الفقرة الأولى بعد تطبيق التغييرات الجديدة وقد ظهرت باللون الأخضر الفاتح وانتُزعت من الانسياب الاعتيادي للعناصر ثم وضعت في موقع أعلى من مكانها السابق. لاحظ أيضًا كيف حُشرت تحت الفقرة النصية التي وضّعناها سابقًا حيث تراكبت الفقرتين فوق بعضهما. ولأن الفقرة النصية الثانية (التي تمتلك الصنف positioned. ) قد ظهرت ثانيًا في ترتيب العناصر في الشيفرة المصدرية، فالعناصر الموّضعه التي ترتيبها متأخر عن العناصر الموّضعة الأخرى في الشيفرة المصدرية تربح أولوية الظهور في الأعلى. لكن هل يمكن تغيير الأمر؟ نعم باستخدام الخاصية z-index والتي تُعرف باسم "مؤشر العلو". وهي قيمة مرجعية للمحور الثالث Z الذي نفترض أنه يتجه نحو المستخدم عموديًا على الشاشة. وقد تتذكر من مقالات سابقة كيف استخدمنا المحور الأفقي (المحور X) والمحور العمودي (المحور Y) لتحديد إحداثيات أشياء مثل موقع صور الخلفية وتأثيرات الظل. فمن أجل اللغات التي تكتب من اليسار إلى اليمين، يمثل الإحداثي (0,0) الزاوية العليا اليسرى للصفحة أو العنصر ضمن حاويته. ويتحرك منها الإحداثي X نحو اليمين والإحداثي Y نحو الأسفل. للصفحات أيضًا محور ثالث هو المحور Z وهو كما ذكرنا محور تخيلي ينطلق من سطح الشاشة نحو المستخدم. وتؤثر قيمة محور العلو z-index على موقع العنصر الموّضع على هذا المحور، وكلما كانت قيمة هذه الخاصية أعلى لعنصر ظهر فوق العنصر ذو القيمة الأقل. ولكل العناصر القيمة الافتراضية للخاصية z-index وهي عمليًا القيمة 0. يسمح باستخدام القيم السالبة والتي تجعل العنصر ينزل نحو الأسفل. ولكي تغير ترتيب العناصر المتراكبة، أضف التصريح التالي إلى القاعدة p:nth-of-type(1) : z-index: 1; سترى الآن الفقرة ذات اللون الأخضر الفاتح في الأعلى: See the Pen positioning-css4 by Hsoub Academy (@HsoubAcademy) on CodePen. يجدر الانتباه إلى أن الخاصية z-index تقبل فقط قيمًا بلا وحدات، فلا يمكنك تخصيص قيمة مثل 23px. ودائمًا تأتي القيم الأكبر فوق القيم الأصغر، ولك حرية تخصيص هذه القيم بأي قيم تريدها، فاستخدام قيمتين مثل 2 و 3 يماثل استخدام القيمتين 300 و400. التموضع الثابت Fixed لنلق نظرة الآن على التموضع الثابت للعناصر، والذي يعمل تمامًا مثل التموضع المطلق مع اختلاف جوهري واحد. إذ يثبّت التموضع المطلق موقع العنصر بالنسبة إلى أقرب عنصر أب ضبطت خاصية التموضع له (والكتلة الحاوية الأساسية في حال لا يوجد عنصر سلف مضبوط الموقع)، بينما يثبت التموضع الثابت موقع العنصر بالنسبة إلى الجزء المرئي من نافذة العرض، باستثناء حالة واحدة تحدث إن كان أحد العناصر الأسلاف كتلة حاوية ثابتة نظرًا لتطبيق قيمة للخاصية transform مختلفة عن القيمة الافتراضية none. ويعني ذلك أنه بإمكانك إنشاء عناصر واجهة مستخدم ثابتة في مكانها مثل قوائم التنقل التي تُبقى مرئية دائمًا مهما قمت بتمرير محتوى الصفحة للأسفل. لنعمل سوية على المثال التالي كي تتوضح الصورة. احذف بداية القاعدتين (p:nth-of-type(1 و positioned. من شيفرة CSS. عدّل بعد ذلك القاعدة body واحذف التصريح ;position: relative ثم اجعل الارتفاع ثابتًا كالتالي: body { width: 500px; height: 1400px; margin: 0 auto; } سيُمنح الآن العنصر <h1> موضعًا ثابتًا ;position: fixed ونضبط هذا الموقع ليكون أعلى نافذة العرض بإضافة الشيفرة التالية: h1 { position: fixed; top: 0; width: 500px; margin-top: 0; background: white; padding: 10px; } لا بد من استخدام التصريح ;top: 0 ليبقى العنصر أعلى الشاشة، كما منحنا العنوان اتساعًا يماثل اتساع محتوى العمود وخلفية بيضاء وبعض الهوامش والحشوات كي يظهر المحتوى تحته. عند حفظ التغيّرات وإعادة تحميل الصفحة، سترى أن موقع العنوان سيقى ثابتًا، ويظهر المحتوى وكأنه يظهر ويختفي تحته عن تمريره. لكن تجدر الملاحظة أن بعض المحتوى قد اقتُطع تحت العنوان ولم يعد ظاهرًا، ذلك أن العنوان قد انتزع من الانسياب الاعتيادي وارتفع جزء من المحتوى ليحل مكانه. تُحل هذه المشكلة بدفع الفقرة النصية إلى الأسفل بضبط الهامش العلوي لها مثلًا: p:nth-of-type(1) { margin-top: 60px; } سترى النتيجة كالتالي: See the Pen positioning-css5 by Hsoub Academy (@HsoubAcademy) on CodePen. التموضع اللاصق Sticky هنالك قيمة أخرى للخاصية position هي position: sticky، وهي أحدث من القيم الأخرى نوعًا ما. وهي في الواقع خيار هجين بين الوضعين النسبي والثابت. تسمح هذه القيمة للعنصر بالتصرف وكأنه موضّع نسبيًا حتى تُمرر الصفحة إلى حد معين (مثل 10 بكسل عن أعلى نافذة العرض) ليصبح بعدها ثابتًا. مثال بسيط على Sticky يمكن استخدام الوضع اللاصق مثلًا في إنشاء قوائم تنقل يمكن تمريرها إلى حد معين ومن ثم تبقى في أعلى نافذة العرض. .positioned { position: sticky; top: 30px; left: 30px; } See the Pen positioning-css6 by Hsoub Academy (@HsoubAcademy) on CodePen. فهرس قابل للتمرير من الاستخدامات الشائعة والمهمة للوضع اللاصق هو إنشاء فهرس قابل للتمرير تبقى فيه العناوين ملتصقة بأعلى الصفحة عندما تصل إليها. ولكتابة شيفرة مثال كهذا جرّب ما يلي: <h1>Sticky positioning</h1> <dl> <dt>A</dt> <dd>Apple</dd> <dd>Ant</dd> <dd>Altimeter</dd> <dd>Airplane</dd> <dt>B</dt> <dd>Bird</dd> <dd>Buzzard</dd> <dd>Bee</dd> <dd>Banana</dd> <dd>Beanstalk</dd> <dt>C</dt> <dd>Calculator</dd> <dd>Cane</dd> <dd>Camera</dd> <dd>Camel</dd> <dt>D</dt> <dd>Duck</dd> <dd>Dime</dd> <dd>Dipstick</dd> <dd>Drone</dd> <dt>E</dt> <dd>Egg</dd> <dd>Elephant</dd> <dd>Egret</dd> </dl> تبدو شيفرة CSS قريبة من التالي: تتحرك العناصر <dt> في الانسياب الاعتيادي مع المحتوى عند تمريره، لكن بإضافة الخاصية position: sticky إلى هذه العناصر بالإضافة إلى الخاصية top ستعمل المتصفحات الحديثة على إبقاء العناوين في أعلى نافذة العرض عندما تبلغ هذا الموقع. سيستبدل كل عنوان لاحق العنوان السابق عندما يصل إليه وهكذا. dt { background-color: black; color: white; padding: 10px; position: sticky; top: 0; left: 0; margin: 1em 0; } See the Pen positioning-css7 by Hsoub Academy (@HsoubAcademy) on CodePen. لاحظ كيف تبقى العناصر اللاصقة لاصقةً بالنسبة إلى أقرب عنصر يمتلك آلية تحدد طريقة تمرير محتواه أي بعبارة أخرى له قيمة مخصصة للخاصية position. الخلاصة تعرّفنا في هذا المقال على الأوضاع المختلفة التي يمكن أن يأخذها العنصر وجرّبنا الكثير من الأوضاع، مع ذلك لا تعد هذه الطريقة مناسبًة لتخطيط الصفحات في الويب الحديث بل لها حالات استخدام مخصصة مفيدة كما رأينا. ترجمة -وبتصرف- للمقال: Positioning اقرأ أيضًا المقال السابق: الخاصية float: تعويم عناصر الصفحة في CSS التحكم في تخطيط الصفحة وضبط محاذاة العناصر في CSS أساسيّات التَمَوْضُع على صفحات الويب (CSS Positioning 101) مدخل إلى تَموضُع الخلفيّة Background Positioning في CSS مدخل إلى تخطيط صفحات الويب باستخدام CSS
  15. بدأنا في مقال سابق بإنشاء لعبة إلكترونية باستخدام محرك الألعاب جودو، وحان الوقت اﻵن لضم كل شيء معًا وإنشاء مشهد كامل للعبتنا، لهذا سنبدأ في مقال اليوم باستكمال العمل على اللعبة وإنشاء مشهدها الأساسي وإعداده بالطريقة المناسبة. إنشاء عقدة المشهد الرئيسي للعبة لإنشاء مشهد جديد في محرك ألعاب جودو علينا إنشاء عقدة اسمها Main من النوع Node ولا حاجة أن تكون من النوع Node2D لأنها مجرد حاوية لمنطق اللعبة ولن تحتاج فعلًا إلى وظائف هذا النوع من العقد. انقر على زر إنشاء نسخة (أيقونة السلسلة في نافذة المشهد) ثم اختر المشهد "Player.tscn". أضف بعد ذلك العقد التالية كأبناء للعقدة Main وفق اﻷسماء التالية: مؤقت Timer باسم MobTimer للتحكم بمعدل تكاثر الزواحف، واضبط الخاصية Wait Time له على 0.5. مؤقت Timer باسم ScoreTimer لزيادة النتيجة كل ثانية، واضبط الخاصية Wait Time له على 1. مؤقت Timer باسم StartTimer لإضافة تأخير بسيط قبل بدء اللعبة، واضبط الخاصية Wait Time له على 2. عقدة من النوع Marker2D اسمها StartPosition لتحديد موقع البداية بالنسبة للاعب. إضافة إلى ذلك، اضبط الخاصية One Shot للمؤقت StartTimer على "فعّال On" و الخاصية Position للعقدة StartPosition على القيمة التالية(450, 240). تكاثر الأعداء نستخدم المشهد الرئيسي Main في تكاثر الأعداء ونريدهم أن يظهروا في أماكن عشوائية على حواف الشاشة، لهذا أضف عقدة من النوع Path2D باسم MobPath كابن للعقدة الرئيسية. سترى عدة أزرار إضافية في أعلى المحرر عند اختيار اﻷيقونة Path2D: اختر الزر الموجود في المنتصف "إضافة عقدة (في مساحة خالية)" ثم ارسم مسارًا بالنقر ضمن المحرر في النقاط التي يعرضها الشكل التالي. ولكي يكون تحديد النقاط دقيقًا فعّل الخيارين "استخدام المحاذاة للشبكة Use Grid Snap" و "استخدم المحاذاة الذكية Use Smart Snap"، وستجدهما إلى يمين أيقونة "القفل" على شكل مغناطيس بجوار عدة نقاط وآخر بجوار شبكة كما توضح الصورة التالية: ملاحظة مهمة: ارسم المنحني باتجاه عقارب الساعة وإلا ستتكاثر الزواحف إلى الخارج بدلًا من الداخل. بعد تحديد أربع نقاط، انقر على أيقونة "إغلاق المنحني" وسيكتمل هذا المنحني. أضف بعد الانتهاء من رسم المنحني العقدة PathFollow2D كابن للعقدة MobPath وسمها MobSpawnLocation. ستدور هذه العقدة وتتبع المسار عندما تتحرك وبالتالي يمكن استخدامها لاختيار مواقع واتجاهات عشوائية على طول المسار. سيبدو المشهد الرئيسي اﻵن كما يلي: السكربت الرئيسي أضف سكربت (نص برمجي) إلى المشهد Main ثم أضف العبارة export var mob_scene: PackedScene@ التي تسمح لنا باختيار مشهد اﻷعداء الذي نريد صنع نسخة عنه: extends Node @export var mob_scene: PackedScene var score انقر على العقدة Main وستجد الخاصية Mob Scene ضمن الفاحص في لوحة "متغيرات السكربت"، وﻹسناد قيمة إلى هذه الخاصية يمكنك اتباع إحدى الطريقتين التاليتين: اسحب المشهد من حاوية نظام الملفات وأفلته ضمن الخاصية Mob Scene. انقر على زر السهم المجاور للخاصية Mob Scene وانقر "تحميل" ثم اختر mob.tscn. اختر نسخة العقدة Player الموجودة ضمن العقدة Main ثم انقر على حاوية "عقدة" إلى جوار "الفاحص" في الشريط الجانبي لترى قائمة تضم جميع اﻹشارات للعقدة Player. جد اﻹشارة hit وانقر عليها نقرة مزدوجة (أو انقر عليها بالزر الأيمن واختر "توصيل"). ستفتح هذه العملية نافذة جديدة نريد فيها إنشاء دالة جديدة ندعوها game_over تعالج ما نريد فعله عند انتهاء اللعبة. اكتب "game_over" في المربع النصي "الدالة المتلقية Receiver Method" أسفل النافذة ثم انقر زر "وصل Connect". وما سيحدث اﻵن أن اﻹشارة hit التي بثها اللاعب Player سيعالجها السكربت اﻷساسي "Main". أضف اﻵن الشيفرة التالية إلى الدالة الجديدة، وأضف أيضًَا الدالة new_game التي تحضّر كل شيء عند بداية اللعبة: func game_over(): $ScoreTimer.stop() $MobTimer.stop() func new_game(): score = 0 $Player.start($StartPosition.position) $StartTimer.start() صل اﻵن اﻹشارة ()timeout العائدة إلى كل عقدة مؤقت (StartTimer و ScoreTimer و MobTimer) إلى السكربت الرئيسي. وسيشغل المؤقت StartTimer المؤقتين الآخرين ويزيد المؤقت ScoreTimer النتيجة بمقدار 1. func _on_score_timer_timeout(): score += 1 func _on_start_timer_timeout(): $MobTimer.start() $ScoreTimer.start() سننشئ ضمن الدالة نسخة عن العدو (الزواحف)، لهذا، سنختار مكانًا عشوائيًا للبدء على المسار Path2D ونضبط حركة العدو. تدور العقدة تلقائيًا عندما تلحق بالمسار، لهذا سنستفيد منها في اختيار جهة حركة الزاحف وموقعه. وعندما تتكاثر الزواحف سنختار قيمة عشوائية لسرعة حركتها بين 150 و 250. وانتبه إلى أن إضافة نسخة جديدة إلى المشهد تكون من خلال التعليمة add_child: func _on_mob_timer_timeout(): # mob scene أنشئ نسخة من مشهد الزاحف var mob = mob_scene.instantiate() # Path2D اختر مكانًا عشوائيًا على المسار. var mob_spawn_location = get_node("MobPath/MobSpawnLocation") mob_spawn_location.progress_ratio = randf() # اجعل اتجاه الزاحف عمودًا على اتجاه المسار var direction = mob_spawn_location.rotation + PI / 2 # اختر موقعًا عشوائيًًًًًًًًًا للزاحف mob.position = mob_spawn_location.position # أضف بعض العشوائية إلى المسار direction += randf_range(-PI / 4, PI / 4) mob.rotation = direction # اختر سرعة الزاحف var velocity = Vector2(randf_range(150.0, 250.0), 0.0) mob.linear_velocity = velocity.rotated(direction) # إجعل الزواحف تتكاثر بإضافتها إلى الشاشةالرئيسية add_child(mob) ملاحظة هامة: قد تتساءل لماذا نستخدم العدد PI في الدوال التي تتعامل مع الزوايا؟ لأن جودو يستخدم الراديان لقياس الزوايا. تمثّل PI نصف دوره كما يمكن استعمال TAU التي تمثّل دورة كاملة. لكن إن كنت تفضّل العمل مع الدرجات ستحتاج إلى الدالتين ()rad_to_deg و ()deg_to_rad للتحويل بين الدرجات والراديان. اختبار المشهد نختبر اﻵن إذا كانت كل شيء على ما يرام حتى اللحظة، لهذا استدعي الدالة new_game ضمن الدالة ()ready_: func _ready(): new_game() لنجعل أيضًا المشهد Main المشهد الرئيسي في اللعبة، وهو المشهد الذي يعمل تلقائيًا. انقر على زر التشغيل واختر main.tscn عندما يُطلب ذلك. من المفترض أن تكون قادرًا على تحريك اللاعب في جميع الاتجاهات وترى الزواحف تتحرك وتتكاثر، وسترى كيف يختفي اللاعب عندما يصطدم بالعدو. عندما تتأكد أن كل شيء يعمل جيدًا أزل الدالة new_game من الدالة ()ready_. الخلاصة تعلمنا في مقال اليوم كيف ننشئ المشهد الأساسي للعتبنا الإلكترونية وسنكتفي في هذا المقال بهذه المرحلة، ومع ذلك لا تزال اللعبة غير مكتملة وتنقصها بعض اللمسات النهائية وإنشاء واجهة مناسبة للعبة، لذا سنشرح خطوات تعزيز اللعبة بواجهة تتضمن تأثيرات صوتية واختصارات لوحة المفاتيح وغيرها من الخيارات وهذا ما سنراه في المقال التالي من هذه السلسلة. ترجمة -وبتصرف- للمقال: The main game scene اقرأ أيضًا المقال السابق: بناء لعبة ثنائية البعد عبر محرك الألعاب Godot - الجزء الثاني: إنشاء مشاهد اللعبة وبرمجتها إعداد محرك الألعاب جودو Godot للعمل مع قاعدة البيانات SQLite مدخل إلى محرك الألعاب جودو Godot مطور الألعاب: من هو وما هي مهامه
×
×
  • أضف...