تصميم المواقع

تعلم جافاسكريبت للمبتدئين

جافاسكريبت تمنح الصفحة سلوكا: الاستجابة لما يفعله الزائر، وتغيير المحتوى دون إعادة تحميل، وجلب بيانات من الخادم. هيكل الصفحة عمل HTML ومظهرها عمل CSS؛ وجافاسكريبت لا تلزم إلا حيث يجب أن تفعل الصفحة شيئا.

  • الدرس 4 من 12
  • مبتدئ
  • مجاني، دون تسجيل

اللغات الثلاث التي تدير الصفحة معا

لكل منها مهمة واحدة، ولا تقوم إحداها بمهمة الأخرى.

  • HTML، البنية

    يقول ما كل قطعة: عنوان وفقرة وزر ونموذج. والمتصفح وقارئ الشاشة والزاحف يقرؤون هذا.

  • CSS، المظهر

    اللون والتباعد والحجم والتخطيط. ويرسم الحالات أيضا: hover وfocus ومفتوح ومغلق.

  • جافاسكريبت، السلوك

    ما يحدث بعد فتح الصفحة: الاستجابة للمستخدم وتغيير المحتوى ومحادثة الخادم.

صفحة تعمل

وزنها ليس متساويا. فالصفحة بلا جافاسكريبت تعمل، وبلا CSS تُقرأ، أما بلا HTML فلا وجود لها أصلا.

آخر مراجعة: تُراجع الحقائق وأسماء الأدوات في هذا الدرس مقابل مصادرها في هذا التاريخ.

لماذا نستعمل جافاسكريبت أصلا؟

لما يحدث بعد أن تُفتح الصفحة. جافاسكريبت هي اللغة الوحيدة التي ينفذها كل متصفح أصلا، ومهمتها أن تحيي الصفحة التي بناها HTML ولونها CSS.

الشكل في أعلى الصفحة ثلاثة تروس، وهو يبين هذا التقسيم. فـHTML يقول هذا عنوان وذاك زر، وCSS يقول ما لون الزر، وجافاسكريبت تقول ماذا يحدث حين يضغطه أحد.

وهناك أربع مهام لا تقدر عليها إلا جافاسكريبت: الاستجابة لما يفعله الزائر بعد تحميل الصفحة، وتغيير شيء موجود على الشاشة الآن، ومحادثة الخادم دون إعادة تحميل الصفحة، وحفظ شيء في المتصفح نفسه إلى المرة القادمة. وكل ما عدا ذلك مما تظنه محتاجا إلى جافاسكريبت يستحق فحصا ثانيا؛ والقسم السادس من هذا الدرس يعود إليه بقائمة محددة.

وهناك مهمة ليست مهمتها ويخلط فيها المبتدئون كثيرا: جافاسكريبت التي تعمل في المتصفح ليست برنامج خادم. فحفظ طلب شراء وإرسال بريد وفحص كلمة مرور، كلها تحدث على الخادم. وشفرة المتصفح لا تفعل غير إرسال الطلب.

أين نكتب الشفرة وكيف نربطها بالصفحة؟

في ملف منفصل بامتداد .js، وتربطه بالصفحة بسطر واحد في head:

<script src="app.js" defer></script>

وكلمة defer أهم ما تتعلمه في هذا القسم. تعني: نزّل الملف أثناء قراءة HTML، لكن أجّل تنفيذه حتى تُبنى الصفحة كاملة. وبدونها تعمل الشفرة الجالسة في head قبل وجود العناصر، فتعيد كل محاولة للعثور على زر null. وهذا أشيع «لماذا لا يعمل» عند المبتدئين، وجوابه كلمة واحدة.

وأداتك الثانية هي كونسول المتصفح. افتحه بـF12 وأبقه مفتوحا: كل خطأ في جافاسكريبت يُطبع هناك برقم سطره، وconsole.log يريك أي شيء تطلبه. وما لم تفتح الكونسول فأنت تبرمج في الظلام.

const title = document.querySelector("h1");
console.log(title.textContent);

أما المتغيرات فاكتب const إلا إن كنت تعرف أن القيمة ستتغير، فحينها let. وكلمة var بقية من حقبة سابقة من جافاسكريبت ولا سبب لكتابتها في شفرة جديدة.

ما DOM ولماذا يبدأ كل شيء منه؟

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

والعثور على عنصر يحتاج دالة واحدة، وواحدة تكفي. فـdocument.querySelector يأخذ محددات CSS نفسها:

const btn  = document.querySelector(".btn");
const rows = document.querySelectorAll(".row");

وبعد أن تجده، أمامك ثلاث مهام يومية. تغيّر النص بـtextContent، وتضيف الأصناف وتحذفها بـclassList، وتضبط الخصائص بـsetAttribute.

btn.textContent = "تم الحفظ";
btn.classList.add("is-done");

وبينها قرار يستحق أن تتعلمه صحيحا من اليوم الأول. فـtextContent يعامل ما تعطيه نصا صرفا، أما innerHTML فيعامله ترميزا وينفذه. وإن كان النص الذي تدرجه قادما من مستخدم، فقد سلّمته القدرة على كتابة وسوم في صفحتك. والقاعدة بسيطة: ما لم تكن تبني HTML فعلا فاستعمل textContent.

وعادة تبقي العمل نظيفا: بدل تغيير الألوان والأحجام من جافاسكريبت، أضف صنفا ودع CSS يرسم المظهر. جافاسكريبت تغيّر الحالة، وCSS يعرض تلك الحالة.

الأحداث: حين يفعل الزائر شيئا

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

btn.addEventListener("click", function () {
  console.log("someone pressed it");
});

وهذا مثال كامل يعمل فعلا ولا يمكن في HTML وCSS: عداد حروف تحت حقل نصي.

<label for="msg">نص الرسالة</label>
<textarea id="msg" maxlength="200"></textarea>
<p id="left">200</p>
const box  = document.querySelector("#msg");
const left = document.querySelector("#left");

box.addEventListener("input", function () {
  left.textContent = 200 - box.value.length;
});

خمسة أسطر، وفيها نقاط عدة. اخترنا حدث input لا keyup، لأن keyup يسمع لوحة المفاتيح وحدها ويفوته اللصق بالفأرة أو من الهاتف. وvalue هو المحتوى الحالي للحقل وlength طوله. وmaxlength على الوسم نفسه هو ما يحدّ فعلا؛ وجافاسكريبت تعرض الرقم لا أكثر.

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

form.addEventListener("submit", function (event) {
  event.preventDefault();
});

والشكل التالي يمر بهذه الدورة خطوة خطوة. والمهم فيه الخطوة الأخيرة: أنت تغيّر DOM، وإعادة رسم الصفحة عمل المتصفح لا عملك.

من نقرة الزائر إلى التغير على الشاشة

أنت تكتب الخطوة الثالثة وحدها. والباقي عمل المتصفح.

  1. 1

    الزائر يفعل شيئا

    نقرة أو كتابة أو إرسال نموذج أو حتى تمرير.

  2. 2

    المتصفح يصنع الحدث

    كائن بكل التفاصيل: أين وعلى أي عنصر وبأي مفتاح.

  3. 3

    دالتك تعمل

    الدالة التي سجلتها بـaddEventListener.

  4. 4

    يتغير DOM

    نص أو صنف أو خاصية. والملف على القرص لا يُمس.

  5. 5

    المتصفح يعيد الرسم

    هذه الخطوة لا تكتبها ولا تحتاج إلى كتابتها.

إن حذفت عنصرا وأعدت بناءه فقد ذهب مستمعه معه. وهذا أشيع سبب لتوقف زر عن العمل بعد تحديث.

fetch: جلب البيانات دون إعادة تحميل الصفحة

حتى هنا كان كل شيء يحدث داخل الصفحة نفسها. وfetch هو حيث تحادث الصفحة الخارج: تنادي عنوانا، فيجيب الخادم، فتضع الجواب على الصفحة. دون إعادة تحميل.

async function loadPrice() {
  const res  = await fetch("/api/price.json");
  const data = await res.json();
  document.querySelector("#price").textContent = data.toman;
}

وكلمة await تعني انتظر الجواب ثم نفّذ السطر التالي، ولا معنى لها إلا داخل دالة موسومة بـasync. وهنا أول موضع تصير فيه جافاسكريبت أصعب فعلا، لأن العمل لم يعد سطرا بعد سطر. وإن وصلت إلى هنا في اليوم الأول فهذا يكفي؛ والباقي ينتظر.

واعرف ثلاثة أمور من الآن كي لا تضيّع وقتك. أولا أن العنوان الذي تناديه يجب أن يكون موجودا وأن يجيب؛ ولسان Network في الكونسول يبين هل خرج الطلب وأي رمز عاد. وثانيا أنه إن كان العنوان لنطاق آخر فالمتصفح يمنعك من قراءة الجواب إلا أن يكون ذلك الخادم قد سمح. وثالثا وهو الأهم: هذه الشفرة تعمل في متصفح الزائر ويستطيع قراءتها كلها. ولا مكان لأي مفتاح أو كلمة سر في هذا الملف.

كم تحتاج من جافاسكريبت فعلا؟

أقل مما تظن، وهذا موقفنا لا ذوقنا. فجزء كبير مما يفعله المبتدئون بجافاسكريبت صار HTML وCSS يفعلانه بنفسيهما اليوم، وبشكل أفضل وبشفرة أقل:

  • فتح قسم وإغلاقه بـdetails وsummary دون سطر شفرة
  • تحقق أولي من النموذج بـrequired وtype="email" على الحقل نفسه
  • تحميل كسول للصور بـloading="lazy"
  • نافذة منبثقة بوسم dialog
  • استجابة لحالة العنصر بـhover وfocus-visible وhas في CSS
  • شريط تمرير أفقي بـscroll-snap يعمل بالإصبع أيضا كما ينبغي

ولماذا يهم هذا: كل ملف جافاسكريبت يجب أن يُنزَّل ويُحلَّل ويُنفَّذ، والتنفيذ يجري على الخيط نفسه الذي يجيب لمسة المستخدم. وما دامت الشفرة تعمل فالصفحة لا تجيب إصبع أحد. الصورة الثقيلة تخفض الجودة، أما جافاسكريبت الثقيلة فتبطئ الصفحة؛ وإن أردت أن ترى أثر ذلك على سرعة الموقع الفعلية فإن صفحة تسريع الموقع ودروس مسار السرعة تبين ذلك بالقياس.

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

ومثال من هذه الصفحة نفسها: الأشكال التي تراها في هذا الدرس مرسومة بصفر سطر جافاسكريبت. HTML وCSS فقط.

سؤال واحد قبل السطر الأول

جزء كبير مما يُنجَز بجافاسكريبت صار له اليوم جواب داخل HTML وCSS نفسيهما.

هل يحتاج ما تريده فعلا إلى جافاسكريبت؟

إن كان HTML أو CSS يكفي

لا تكتبها

  • فتح الأقسام وإغلاقها بـdetails وsummary
  • تحقق أولي من النموذج بخصائص الحقل نفسه
  • تحميل كسول للصور بخاصية واحدة
  • شريط تمرير أفقي بـscroll-snap في CSS
إن وجب أن يحدث شيء بعد التحميل

اكتب جافاسكريبت

  • عداد أو مرشح حي أو أي شيء يتغير مع كتابة المستخدم
  • جلب بيانات من الخادم دون إعادة تحميل الصفحة
  • حفظ شيء في المتصفح حتى الزيارة التالية
  • أي شيء يجب أن يحسب على مدخلات المستخدم

هذه القاعدة لمواقع المحتوى. أما لمنتج تفاعلي كلوحة تحكم أو محرر فالجواب يكاد يكون نعم دائما، ولا بأس بذلك.

المسار السريع مع الذكاء الاصطناعي

النماذج اللغوية جيدة على نحو غير معتاد في تعلم جافاسكريبت، لأن ما يحتاجه المبتدئ ليس شفرة بل جوابا عن «لماذا»، خمس مرات متتالية وبلا حرج. لكن المسار السريع ليس «خذ شفرة»؛ بل «خذ أصغر نسخة تعمل ثم اجعلها تسألك». والفرق بين الاثنين هو الفرق بين من يملك شفرة ومن يفهمها. ويكفي هنا نموذج سريع ورخيص؛ واختيارنا الحالي في <a class="text-link" href="/ar/ai/">قسم الذكاء الاصطناعي</a>.

  1. اكتب في جملة واحدة ما ينبغي أن يحدث. وإن كانت جملتك فيها «و» مرتين فهاتان مهمتان؛ افصلهما وتقدم واحدة واحدة.
  2. شغّل الوصفة أدناه وضع فيها ترميزك الحقيقي لا وصفا له.
  3. ضع الشفرة في الملف وأبقِ كونسول المتصفح مفتوحا. وإن لم تعمل فسطر الخطأ مكتوب هناك برقم سطره.
  4. والآن الخطوة التي تفصل النسخ عن التعلم: أعد الشفرة نفسها واطلب منه أن يحذف سطرا ويسألك ما الذي ينكسر. وحتى يصح جوابك، فتلك الشفرة ليست لك بعد.

وصفة جاهزة للنسخ

الدور: معلم جافاسكريبت لمن بدأ لتوه.

ما ينبغي أن يحدث:
{اكتبه في جملة واحدة}
الترميز الحالي:
{ضع HTML هنا}

القواعد:
- أعطِ أصغر نسخة تعمل، لا النسخة الكاملة الاحترافية.
- جافاسكريبت حديثة: const وlet وaddEventListener وfetch. بلا jQuery وبلا var وبلا خاصية onclick داخل الوسم.
- بلا مكتبة وبلا إطار عمل. وإن تعذر الأمر فعلا دون مكتبة فقل ذلك أولا واكتب السبب.
- إن كانت المهمة نفسها ممكنة بـHTML أو CSS وحدهما، فاعرض ذلك الطريق أولا وقل لماذا هو أفضل.
- بعد الشفرة، اشرح كل سطر في جملة واحدة.
- لكل قدرة استعملتها، اذكر اسم صفحتها في MDN كي أرى جدول دعم المتصفحات بنفسي.
- لا تكتب أي نص أو رقم أو اسم ليس في مدخلاتي؛ واترك {...} مكانه.

وفي النهاية: احذف سطرا واحدا من الشفرة واسألني ما الذي ينكسر بغيابه. ولا تكتب الجواب الصحيح حتى أطلبه.

قبل أن تثق بالناتج: لا متصفح لدى النموذج. فالشفرة التي «ينبغي أن تعمل» قد تفشل على صفحتك لسبب لا يراه: العنصر لم يكن موجودا بعد، أو عملت الشفرة مبكرا، أو لم يطابق المحدد شيئا. ولهذا الصنف من الأسئلة: الكونسول أولا والمحادثة ثانيا. وحد أخطر: لا ينبغي أن تُنشر شفرة تمس الدفع أو دخول المستخدم أو بيانات شخصية دون أن يقرأها من يفهم اللغة. فجافاسكريبت التي تكتبها تعمل على جهاز الزائر؛ وكل ما تضعه فيها فقد أرسلته.

الذكاء الاصطناعي في هذا العمل

هذا هو الموضوع الذي يساعد فيه الذكاء الاصطناعي المبتدئ أكثر، وموقفنا واضح: استعمله معلما لا موردا. ثلاثة أمور يحسنها فعلا: كتابة أصغر نسخة عاملة لمهمة، وشرح مقطع شفرة لا تفهمه سطرا سطرا، وقراءة رسالة خطأ وبيان مصدرها. وما لا نسلّمه: الحكم على أمان الشفرة.

أدوات تساعد فعلا

  • Claude جيد للشرح سطرا سطرا ولتلك اللعبة نفسها: «احذف سطرا واسألني». وإيران ليست في قائمة الدول المدعومة لدى أنثروبيك؛ قرأنا ذلك في صفحة أنثروبيك نفسها.
  • Gemini يكفي للأسئلة الأساسية ولأول نسخة من دالة، ويتعامل مع الفارسية جيدا. وصفحة غوغل نفسها تقول إن تطبيق جيميناي يعمل في أكثر من مئتين وثلاثين دولة ومنطقة، وإيران ليست في تلك القائمة.
  • Claude Code يعمل في محررك وطرفيتك ويرى الملفات، فيناسب مشروعا صار عدة ملفات أكثر مما تناسبه نافذة محادثة. ولا يحتاجه المبتدئ في يومه الأول. يُثبَّت مجانا لكنه يحتاج اشتراك أنثروبيك، وإيران ليست في قائمة الدول المدعومة.

اين ينقلب ضدك

خطران محددان، وليس أي منهما «شفرة خاطئة». الأول الأنماط القديمة: يعطيك النموذج ما طلبته، وإن لم تقل إنك تريد جافاسكريبت حديثة فلا شيء يمنع var وخاصية onclick داخل الوسم. وفحص ذلك يدوي ويستغرق عشر ثوان: ابحث عن اسم القدرة في MDN واقرأ جدول دعم المتصفحات. والثاني وهو الأهم: الشفرة التي لا تستطيع قراءتها دَين. ويوم تنكسر، وهي تنكسر يوم تحتاجها، لا تملك سبيلا إلى إصلاحها. وحد لا علاقة له بالتعلم: ما تضعه في نافذة محادثة قد خرج من جهازك، فلا مكان فيه للمفاتيح والرموز وبيانات العملاء. ولمعرفة كيفية الدفع لكل أداة من إيران، انظر دليل الشراء.

المصادر: MDN: The script element MDN: Using the Fetch API Anthropic: supported countries Google: where Gemini Apps are available

حدود هذه النصيحة

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

من عملنا نحن

الأرقام الحقيقية التي نعمل بها نحن، على هذا الموقع نفسه، ويمكن فحصها في عرض المصدر. كل جافاسكريبت جهة العميل في قالب rgb.ir ملفان، نحو ستة عشر وخمسة كيلوبايت، وكلاهما بـdefer، وهذه الصفحة التي تقرؤها تحمّل هذين بالضبط مع ملف التحليلات. وأشكال هذا القسم تحمل صفر بايت من جافاسكريبت: فمحرك الأشكال ثمانية ملفات PHP وليس في أي منها وسم script واحد، وكله HTML وCSS. والآن الصراحة التي تكمل الكلام: رغم هذا كله، تحمّل الصفحة الرئيسية لهذا الموقع نفسه jQuery الإصدار ٣.٧.١ أيضا. لم نكتبها ولم نستدعها؛ فإضافة الأمان في الموقع تسجل شفرة الكابتشا الخاصة بها باعتماد على jQuery، وذلك السطر الواحد يجر مكتبة كاملة إلى الصفحة. والدرس الحقيقي هو هذا: ميزانية جافاسكريبت عندك ليست شفرتك وحدها.

اسئلة متابعة حقيقية

هل تختلف جافاسكريبت عن جافا؟

لغتان منفصلتان تماما وتشابه الاسمين تاريخي. جافاسكريبت لغة المتصفح، وجافا تُستعمل غالبا في برمجيات المؤسسات وعلى أندرويد. وإن كنت هنا لبناء المواقع فالتي تحتاجها جافاسكريبت.

أتعلم jQuery أولا أم جافاسكريبت الخالصة؟

الخالصة. فالمهام التي بُنيت jQuery لأجلها تؤديها اليوم جافاسكريبت نفسها بـquerySelector وaddEventListener وfetch. ومع ذلك ستصادفها في مشاريع ووردبريس القديمة، وعلى هذا الموقع نفسه، فتعلّم قراءتها؛ أما كتابتها فلا لزوم لها.

شفرتي لا تعطي خطأ ولا تفعل شيئا. من أين أبدأ؟

افحص أولا أن محددك عثر على شيء فعلا: اطبع المتغير بـconsole.log وتأكد أنه ليس null. ثم تأكد أن الشفرة لم تعمل قبل بناء الصفحة، وهو ما تحله defer. وهذان يجيبان معظم «لا يعمل» في اليوم الأول.