نقدم في هذا المقال مقاربة تطبيقية مبنية على المفاهيم اﻷساسية التي قدمتها المقالات السابقة. وستتعلم كيف تبني دوال مخصصة بنفسك وتطلع على بعض التفاصيل المفيدة عند التعامل مع الدوال أثناء دراستك لها المقال. ننصحك قبل أن تبدأ العمل معنا في هذه السلسلة أن تطلع على:
- أساسيات علوم الحاسب.
- أساسيات 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
اقرأ أيضًا
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.