You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ar/7-bank-project/3-data
softchris 3f7ec0bbe8
🌐 Update translations via Co-op Translator
1 month ago
..
README.md 🌐 Update translations via Co-op Translator 1 month ago
assignment.md 🌐 Update translations via Co-op Translator 1 month ago

README.md

بناء تطبيق مصرفي الجزء 3: طرق جلب واستخدام البيانات

تخيل حاسوب المؤسسة في مسلسل ستار تريك - عندما يسأل الكابتن بيكار عن حالة السفينة، تظهر المعلومات فورًا دون أن يتوقف النظام أو يعيد بناء نفسه بالكامل. هذا التدفق السلس للمعلومات هو بالضبط ما نسعى لبنائه هنا من خلال جلب البيانات الديناميكية.

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

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

اختبار ما قبل المحاضرة

اختبار ما قبل المحاضرة

المتطلبات الأساسية

قبل الغوص في جلب البيانات، تأكد من أن لديك هذه المكونات جاهزة:

curl http://localhost:5000/api
# Expected response: "Bank API v1.0.0"

هذا الاختبار السريع يضمن أن جميع المكونات تتواصل بشكل صحيح:

  • يتحقق من أن Node.js يعمل بشكل صحيح على نظامك.
  • يؤكد أن خادم API نشط ويستجيب.
  • يتحقق من أن تطبيقك يمكنه الوصول إلى الخادم (مثل التحقق من الاتصال اللاسلكي قبل المهمة).

فهم جلب البيانات في تطبيقات الويب الحديثة

لقد تطورت طريقة تعامل تطبيقات الويب مع البيانات بشكل كبير خلال العقدين الماضيين. فهم هذا التطور سيساعدك على تقدير قوة التقنيات الحديثة مثل AJAX وFetch API ولماذا أصبحت أدوات أساسية لمطوري الويب.

دعونا نستكشف كيف كانت تعمل المواقع التقليدية مقارنة بالتطبيقات الديناميكية والاستجابية التي نبنيها اليوم.

التطبيقات متعددة الصفحات التقليدية (MPA)

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

sequenceDiagram
    participant User
    participant Browser
    participant Server
    
    User->>Browser: Clicks link or submits form
    Browser->>Server: Requests new HTML page
    Note over Browser: Page goes blank
    Server->>Browser: Returns complete HTML page
    Browser->>User: Displays new page (flash/reload)

تدفق التحديث في تطبيق متعدد الصفحات

لماذا كان هذا النهج يبدو غير عملي:

  • كل نقرة تعني إعادة بناء الصفحة بالكامل من الصفر.
  • المستخدمون كانوا يتعرضون لانقطاع في التفكير بسبب تلك الومضات المزعجة للصفحة.
  • اتصال الإنترنت كان يعمل بجهد إضافي لتحميل نفس الرأس والتذييل مرارًا وتكرارًا.
  • التطبيقات كانت تبدو وكأنها تصفح ملفات بدلاً من استخدام البرمجيات.

التطبيقات أحادية الصفحة الحديثة (SPA)

غيرت AJAX (JavaScript وXML غير المتزامن) هذا النموذج تمامًا. مثل التصميم المعياري لمحطة الفضاء الدولية، حيث يمكن لرواد الفضاء استبدال مكونات فردية دون إعادة بناء الهيكل بالكامل، يسمح AJAX بتحديث أجزاء محددة من صفحة الويب دون إعادة تحميل كل شيء. على الرغم من أن الاسم يشير إلى XML، إلا أننا نستخدم JSON في الغالب اليوم، لكن المبدأ الأساسي يبقى كما هو: تحديث فقط ما يحتاج إلى التغيير.

sequenceDiagram
    participant User
    participant Browser
    participant JavaScript
    participant Server
    
    User->>Browser: Interacts with page
    Browser->>JavaScript: Triggers event handler
    JavaScript->>Server: Fetches only needed data
    Server->>JavaScript: Returns JSON data
    JavaScript->>Browser: Updates specific page elements
    Browser->>User: Shows updated content (no reload)

تدفق التحديث في تطبيق أحادي الصفحة

لماذا التطبيقات أحادية الصفحة تبدو أفضل بكثير:

  • يتم تحديث فقط الأجزاء التي تغيرت بالفعل (ذكي، أليس كذلك؟).
  • لا مزيد من الانقطاعات المزعجة - يبقى المستخدمون في تدفقهم.
  • بيانات أقل تنتقل عبر الشبكة تعني تحميل أسرع.
  • كل شيء يبدو سريعًا واستجابياً، مثل التطبيقات على هاتفك.

التطور إلى Fetch API الحديث

توفر المتصفحات الحديثة Fetch API، الذي يحل محل XMLHttpRequest القديم. مثل الفرق بين تشغيل التلغراف واستخدام البريد الإلكتروني، يستخدم Fetch API الوعود لكتابة كود غير متزامن بشكل أنظف ويتعامل مع JSON بشكل طبيعي.

الميزة XMLHttpRequest Fetch API
الصياغة معقدة تعتمد على الاستدعاءات تعتمد على الوعود بشكل نظيف
التعامل مع JSON يتطلب التحليل اليدوي طريقة .json() مدمجة
التعامل مع الأخطاء معلومات محدودة عن الأخطاء تفاصيل شاملة عن الأخطاء
الدعم الحديث توافق مع الإصدارات القديمة وعود ES6+ وasync/await

💡 توافق المتصفح: أخبار جيدة - يعمل Fetch API في جميع المتصفحات الحديثة! إذا كنت مهتمًا بالإصدارات المحددة، caniuse.com يحتوي على القصة الكاملة للتوافق.

الخلاصة:

  • يعمل بشكل رائع في Chrome، Firefox، Safari، وEdge (بشكل أساسي في كل مكان يتواجد فيه المستخدمون).
  • فقط Internet Explorer يحتاج إلى مساعدة إضافية (وبصراحة، حان الوقت للتخلي عن IE).
  • يجهزك بشكل مثالي لأنماط async/await الأنيقة التي سنستخدمها لاحقًا.

تنفيذ تسجيل الدخول واسترجاع البيانات

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

سنقوم ببناء هذا تدريجيًا، بدءًا من المصادقة الأساسية ثم إضافة قدرات جلب البيانات.

الخطوة 1: إنشاء أساس وظيفة تسجيل الدخول

افتح ملف app.js وأضف وظيفة login جديدة. هذه الوظيفة ستتعامل مع عملية مصادقة المستخدم:

async function login() {
  const loginForm = document.getElementById('loginForm');
  const user = loginForm.user.value;
}

لنقم بتفصيل هذا:

  • الكلمة المفتاحية async؟ تخبر JavaScript "مرحبًا، قد تحتاج هذه الوظيفة إلى الانتظار لبعض الوقت".
  • نحن نحصل على النموذج من الصفحة (ليس هناك شيء معقد، فقط العثور عليه بواسطة معرفه).
  • ثم نقوم بسحب ما كتبه المستخدم كاسم مستخدم.
  • إليك خدعة رائعة: يمكنك الوصول إلى أي إدخال نموذج بواسطة خاصية name - لا حاجة لاستدعاءات إضافية لـ getElementById!

💡 نمط الوصول إلى النموذج: يمكن الوصول إلى كل عنصر تحكم في النموذج بواسطة اسمه (المحدد في HTML باستخدام خاصية name) كخاصية لعنصر النموذج. هذا يوفر طريقة نظيفة وسهلة للحصول على بيانات النموذج.

الخطوة 2: إنشاء وظيفة جلب بيانات الحساب

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

async function getAccount(user) {
  try {
    const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user));
    return await response.json();
  } catch (error) {
    return { error: error.message || 'Unknown error' };
  }
}

ما يحققه هذا الكود:

  • يستخدم Fetch API الحديث لطلب البيانات بشكل غير متزامن.
  • يبني عنوان طلب GET مع معلمة اسم المستخدم.
  • يطبق encodeURIComponent() للتعامل بأمان مع الأحرف الخاصة في عناوين URL.
  • يحول الاستجابة إلى صيغة JSON لتسهيل التعامل مع البيانات.
  • يتعامل مع الأخطاء بشكل جيد عن طريق إرجاع كائن خطأ بدلاً من التعطل.

⚠️ ملاحظة أمان: وظيفة encodeURIComponent() تتعامل مع الأحرف الخاصة في عناوين URL. مثل أنظمة التشفير المستخدمة في الاتصالات البحرية، تضمن وصول رسالتك كما هو مقصود، مما يمنع الأحرف مثل "#" أو "&" من أن يتم تفسيرها بشكل خاطئ.

لماذا هذا مهم:

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

فهم طلبات HTTP GET

إليك شيء قد يفاجئك: عندما تستخدم fetch بدون أي خيارات إضافية، فإنه ينشئ تلقائيًا طلب GET. هذا مثالي لما نقوم به - طلب من الخادم "مرحبًا، هل يمكنني رؤية بيانات حساب هذا المستخدم؟"

فكر في طلبات GET كطلب استعارة كتاب من المكتبة - تطلب رؤية شيء موجود بالفعل. طلبات POST (التي استخدمناها للتسجيل) تشبه تقديم كتاب جديد ليتم إضافته إلى المجموعة.

طلب GET طلب POST
الغرض استرجاع البيانات الموجودة
المعلمات في مسار/سلسلة استعلام URL
التخزين المؤقت يمكن تخزينه مؤقتًا بواسطة المتصفحات
الأمان مرئي في عنوان URL/السجلات

الخطوة 3: جمع كل شيء معًا

الآن الجزء الممتع - دعونا نربط وظيفة جلب الحساب بعملية تسجيل الدخول. هنا حيث كل شيء يتكامل:

async function login() {
  const loginForm = document.getElementById('loginForm');
  const user = loginForm.user.value;
  const data = await getAccount(user);

  if (data.error) {
    return console.log('loginError', data.error);
  }

  account = data;
  navigate('/dashboard');
}

تتبع هذه الوظيفة تسلسلًا واضحًا:

  • استخراج اسم المستخدم من إدخال النموذج.
  • طلب بيانات حساب المستخدم من الخادم.
  • التعامل مع أي أخطاء تحدث أثناء العملية.
  • تخزين بيانات الحساب والانتقال إلى لوحة التحكم عند النجاح.

🎯 نمط Async/Await: بما أن getAccount هي وظيفة غير متزامنة، نستخدم الكلمة المفتاحية await لإيقاف التنفيذ حتى يستجيب الخادم. هذا يمنع الكود من الاستمرار مع بيانات غير معرفة.

الخطوة 4: إنشاء مكان لبياناتك

تطبيقك يحتاج إلى مكان لتذكر معلومات الحساب بمجرد تحميلها. فكر في هذا كمكان ذاكرة قصيرة المدى لتطبيقك - مكان للحفاظ على بيانات المستخدم الحالي في متناول اليد. أضف هذا السطر في أعلى ملف app.js:

// This holds the current user's account data
let account = null;

لماذا نحتاج هذا:

  • يحافظ على بيانات الحساب متاحة من أي مكان في تطبيقك.
  • البدء بـ null يعني "لا أحد مسجل الدخول بعد".
  • يتم تحديثه عندما يسجل أحدهم الدخول أو التسجيل بنجاح.
  • يعمل كمصدر واحد للحقيقة - لا يوجد ارتباك حول من سجل الدخول.

الخطوة 5: ربط النموذج الخاص بك

الآن دعونا نربط وظيفة تسجيل الدخول الجديدة الخاصة بك بنموذج HTML الخاص بك. قم بتحديث علامة النموذج الخاصة بك مثل هذا:

<form id="loginForm" action="javascript:login()">
  <!-- Your existing form inputs -->
</form>

ما الذي يفعله هذا التغيير الصغير:

  • يوقف النموذج من القيام بسلوكه الافتر للمحتوى الأكثر تعقيدًا، اجمع بين document.createElement() وطريقة append():
// Safe way to create new elements
const transactionItem = document.createElement('div');
transactionItem.className = 'transaction-item';
transactionItem.textContent = `${transaction.date}: ${transaction.description}`;
container.append(transactionItem);

فهم هذا النهج:

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

⚠️ اعتبارات الأمان: بينما يظهر innerHTML في العديد من الدروس، يمكنه تنفيذ النصوص البرمجية المضمنة. مثل بروتوكولات الأمان في CERN التي تمنع تنفيذ الأكواد غير المصرح بها، فإن استخدام textContent و createElement يوفر بدائل أكثر أمانًا.

مخاطر استخدام innerHTML:

  • تنفيذ أي علامات <script> في بيانات المستخدم
  • عرضة لهجمات حقن الأكواد
  • خلق ثغرات أمنية محتملة
  • البدائل الأكثر أمانًا التي نستخدمها توفر نفس الوظائف

جعل الأخطاء سهلة الفهم للمستخدمين

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

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

الخطوة 1: إضافة مكان لرسائل الخطأ

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

<!-- This is where error messages will appear -->
<div id="loginError" role="alert"></div>
<button>Login</button>

ما يحدث هنا:

  • نحن ننشئ حاوية فارغة تبقى غير مرئية حتى الحاجة إليها
  • يتم وضعها في مكان ينظر إليه المستخدمون بشكل طبيعي بعد النقر على "تسجيل الدخول"
  • تلك الخاصية role="alert" هي لمسة لطيفة لقراء الشاشة - تخبر التكنولوجيا المساعدة "مرحبًا، هذا مهم!"
  • المعرف الفريد id يمنح JavaScript هدفًا سهلاً

الخطوة 2: إنشاء وظيفة مساعدة مفيدة

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

function updateElement(id, text) {
  const element = document.getElementById(id);
  element.textContent = text;
}

فوائد الوظيفة:

  • واجهة بسيطة تتطلب فقط معرف العنصر ومحتوى النص
  • تحديد وتحديث عناصر DOM بأمان
  • نمط قابل لإعادة الاستخدام يقلل من تكرار الأكواد
  • الحفاظ على سلوك التحديث المتسق عبر التطبيق

الخطوة 3: عرض الأخطاء حيث يمكن للمستخدمين رؤيتها

الآن لنقم باستبدال رسالة وحدة التحكم المخفية بشيء يمكن للمستخدمين رؤيته بالفعل. قم بتحديث وظيفة تسجيل الدخول الخاصة بك:

// Instead of just logging to console, show the user what's wrong
if (data.error) {
  return updateElement('loginError', data.error);
}

هذا التغيير الصغير يحدث فرقًا كبيرًا:

  • تظهر رسائل الخطأ في المكان الذي ينظر إليه المستخدمون
  • لا مزيد من الفشل الصامت الغامض
  • يحصل المستخدمون على ردود فعل فورية وقابلة للتنفيذ
  • يبدأ تطبيقك في الشعور بالاحترافية والاهتمام

الآن عند الاختبار باستخدام حساب غير صالح، سترى رسالة خطأ مفيدة مباشرة على الصفحة!

لقطة شاشة تظهر رسالة الخطأ أثناء تسجيل الدخول

الخطوة 4: أن تكون شاملاً مع إمكانية الوصول

هناك شيء رائع حول تلك الخاصية role="alert" التي أضفناها سابقًا - إنها ليست مجرد زخرفة! هذه الخاصية الصغيرة تخلق ما يسمى منطقة حية تعلن فورًا عن التغييرات لقراء الشاشة:

<div id="loginError" role="alert"></div>

لماذا هذا مهم:

  • يسمع مستخدمو قارئ الشاشة رسالة الخطأ بمجرد ظهورها
  • يحصل الجميع على نفس المعلومات المهمة، بغض النظر عن كيفية التنقل
  • إنها طريقة بسيطة لجعل تطبيقك يعمل لمزيد من الأشخاص
  • يظهر أنك تهتم بخلق تجارب شاملة

لمسات صغيرة كهذه تميز المطورين الجيدين عن العظماء!

الخطوة 5: تطبيق نفس النمط على التسجيل

للحفاظ على التناسق، قم بتطبيق معالجة الأخطاء نفسها في نموذج التسجيل الخاص بك:

  1. أضف عنصر عرض الخطأ إلى HTML الخاص بالتسجيل:
<div id="registerError" role="alert"></div>
  1. قم بتحديث وظيفة التسجيل الخاصة بك لاستخدام نمط عرض الخطأ نفسه:
if (data.error) {
  return updateElement('registerError', data.error);
}

فوائد معالجة الأخطاء المتسقة:

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

إنشاء لوحة معلومات ديناميكية

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

باستخدام تقنيات التلاعب بـ DOM التي تعلمتها، سنقوم بإنشاء لوحة معلومات يتم تحديثها تلقائيًا بمعلومات الحساب الحالية.

التعرف على بياناتك

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

{
  "user": "test",
  "currency": "$",
  "description": "Test account",
  "balance": 75,
  "transactions": [
    { "id": "1", "date": "2020-10-01", "object": "Pocket money", "amount": 50 },
    { "id": "2", "date": "2020-10-03", "object": "Book", "amount": -10 },
    { "id": "3", "date": "2020-10-04", "object": "Sandwich", "amount": -5 }
  ]
}

يوفر هيكل البيانات هذا:

  • user: مثالي لتخصيص التجربة ("مرحبًا بعودتك، سارة!")
  • currency: يضمن عرض المبالغ المالية بشكل صحيح
  • description: اسم ودود للحساب
  • balance: الرصيد الحالي المهم للغاية
  • transactions: سجل المعاملات الكامل بجميع التفاصيل

كل ما تحتاجه لبناء لوحة معلومات مصرفية احترافية!

💡 نصيحة احترافية: هل تريد رؤية لوحة المعلومات الخاصة بك تعمل على الفور؟ استخدم اسم المستخدم test عند تسجيل الدخول - يأتي محملاً مسبقًا ببيانات نموذجية حتى تتمكن من رؤية كل شيء يعمل دون الحاجة إلى إنشاء معاملات أولاً.

لماذا الحساب التجريبي مفيد:

  • يأتي مع بيانات نموذجية واقعية محملة مسبقًا
  • مثالي لرؤية كيفية عرض المعاملات
  • رائع لاختبار ميزات لوحة المعلومات الخاصة بك
  • يوفر عليك من إنشاء بيانات وهمية يدويًا

إنشاء عناصر عرض لوحة المعلومات

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

الخطوة 1: تحديث هيكل HTML الخاص بك

أولاً، استبدل قسم "الرصيد" الثابت بعناصر نائبة ديناميكية يمكن لبرمجيات JavaScript ملؤها:

<section>
  Balance: <span id="balance"></span><span id="currency"></span>
</section>

بعد ذلك، أضف قسمًا لوصف الحساب. نظرًا لأن هذا يعمل كعنوان لمحتوى لوحة المعلومات، استخدم HTML دلالي:

<h2 id="description"></h2>

فهم هيكل HTML:

  • استخدام عناصر <span> منفصلة للرصيد والعملة للتحكم الفردي
  • تطبيق معرفات فريدة لكل عنصر لاستهداف JavaScript
  • اتباع HTML دلالي باستخدام <h2> لوصف الحساب
  • إنشاء تسلسل منطقي لقراء الشاشة وتحسين محركات البحث

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

الخطوة 2: إنشاء وظيفة تحديث لوحة المعلومات

الآن قم بإنشاء وظيفة تقوم بملء لوحة المعلومات الخاصة بك ببيانات الحساب الحقيقية:

function updateDashboard() {
  if (!account) {
    return navigate('/login');
  }

  updateElement('description', account.description);
  updateElement('balance', account.balance.toFixed(2));
  updateElement('currency', account.currency);
}

خطوة بخطوة، إليك ما تفعله هذه الوظيفة:

  • التحقق من وجود بيانات الحساب قبل المتابعة
  • إعادة توجيه المستخدمين غير المصادقين إلى صفحة تسجيل الدخول
  • تحديث وصف الحساب باستخدام وظيفة updateElement القابلة لإعادة الاستخدام
  • تنسيق الرصيد ليظهر دائمًا برقمين عشريين
  • عرض رمز العملة المناسب

💰 تنسيق الأموال: تلك الطريقة toFixed(2) هي منقذ! إنها تضمن أن الرصيد يبدو دائمًا كأموال حقيقية - "75.00" بدلاً من مجرد "75". سيقدر المستخدمون رؤية تنسيق العملة المألوف.

الخطوة 3: التأكد من تحديث لوحة المعلومات الخاصة بك

لضمان تحديث لوحة المعلومات الخاصة بك ببيانات حالية في كل مرة يزور فيها شخص ما، نحتاج إلى الربط بنظام التنقل الخاص بك. إذا أكملت مهمة الدرس 1، يجب أن يكون هذا مألوفًا. إذا لم يكن كذلك، لا تقلق - إليك ما تحتاجه:

أضف هذا إلى نهاية وظيفة updateRoute() الخاصة بك:

if (typeof route.init === 'function') {
  route.init();
}

ثم قم بتحديث المسارات الخاصة بك لتضمين تهيئة لوحة المعلومات:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: updateDashboard }
};

ما يفعله هذا الإعداد الذكي:

  • التحقق مما إذا كان للمسار كود تهيئة خاص
  • تشغيل هذا الكود تلقائيًا عند تحميل المسار
  • ضمان عرض لوحة المعلومات دائمًا بيانات حديثة وحالية
  • الحفاظ على منطق التوجيه نظيفًا ومنظمًا

اختبار لوحة المعلومات الخاصة بك

بعد تنفيذ هذه التغييرات، اختبر لوحة المعلومات الخاصة بك:

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

يجب أن تعرض لوحة المعلومات الخاصة بك الآن معلومات الحساب الديناميكية التي يتم تحديثها بناءً على بيانات المستخدم المسجل!

بناء قوائم معاملات ذكية باستخدام القوالب

بدلاً من إنشاء HTML يدويًا لكل معاملة، سنستخدم القوالب لتوليد تنسيق متسق تلقائيًا. مثل المكونات الموحدة المستخدمة في تصنيع المركبات الفضائية، تضمن القوالب أن كل صف معاملة يتبع نفس الهيكل والمظهر.

هذه التقنية تتوسع بكفاءة من عدد قليل من المعاملات إلى الآلاف، مع الحفاظ على الأداء والعرض المتسق.

flowchart LR
    A[Transaction Data] --> B[HTML Template]
    B --> C[Clone Template]
    C --> D[Populate with Data]
    D --> E[Add to DOM]
    E --> F[Repeat for Each Transaction]

الخطوة 1: إنشاء قالب المعاملة

أولاً، أضف قالبًا قابلاً لإعادة الاستخدام لصفوف المعاملات في HTML <body> الخاص بك:

<template id="transaction">
  <tr>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</template>

فهم قوالب HTML:

  • تعريف الهيكل لصف جدول واحد
  • البقاء غير مرئي حتى يتم نسخه وملؤه باستخدام JavaScript
  • تضمين ثلاث خلايا للتاريخ، الوصف، والمبلغ
  • توفير نمط قابل لإعادة الاستخدام لتنسيق متسق

الخطوة 2: تجهيز الجدول للمحتوى الديناميكي

بعد ذلك، أضف معرفًا إلى جسم الجدول حتى يتمكن JavaScript من استهدافه بسهولة:

<tbody id="transactions"></tbody>

ما يحققه هذا:

  • إنشاء هدف واضح لإدخال صفوف المعاملات
  • فصل هيكل الجدول عن المحتوى الديناميكي
  • تمكين سهولة مسح وإعادة ملء بيانات المعاملات

الخطوة 3: بناء وظيفة مصنع صف المعاملة

الآن قم بإنشاء وظيفة تحول بيانات المعاملة إلى عناصر HTML:

function createTransactionRow(transaction) {
  const template = document.getElementById('transaction');
  const transactionRow = template.content.cloneNode(true);
  const tr = transactionRow.querySelector('tr');
  tr.children[0].textContent = transaction.date;
  tr.children[1].textContent = transaction.object;
  tr.children[2].textContent = transaction.amount.toFixed(2);
  return transactionRow;
}

تفصيل هذه الوظيفة:

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

الخطوة 4: إنشاء صفوف معاملات متعددة بكفاءة

أضف هذا الكود إلى وظيفة updateDashboard() الخاصة بك لعرض جميع المعاملات:

const transactionsRows = document.createDocumentFragment();
for (const transaction of account.transactions) {
  const transactionRow = createTransactionRow(transaction);
  transactionsRows.appendChild(transactionRow);
}
updateElement('transactions', transactionsRows);

فهم هذا النهج الفعال:

  • إنشاء مستند جزئي لتجميع عمليات DOM
  • التكرار عبر جميع المعاملات في بيانات الحساب
  • إنشاء صف لكل معاملة باستخدام وظيفة المصنع
  • جمع جميع الصفوف في المستند الجزئي قبل إضافتها إلى DOM
  • تنفيذ تحديث DOM واحد بدلاً من عمليات إدخال فردية متعددة

تحسين الأداء: document.createDocumentFragment() يعمل مثل عملية التجميع في بوينغ - يتم تجهيز المكونات خارج الخط الرئيسي، ثم يتم تثبيتها كوحدة كاملة. هذا النهج التجميعي يقلل من إعادة تدفق DOM عن طريق تنفيذ إدخال واحد بدلاً من عمليات فردية متعددة.

الخطوة 5: تحسين وظيفة التحديث للمحتوى المختلط

وظيفة updateElement() الخاصة بك حاليًا تتعامل فقط مع محتوى النص. قم بتحديثها للعمل مع النصوص وعقد DOM:

function updateElement(id, textOrNode) {
  const element = document.getElementById(id);
  element.textContent = ''; // Removes all children
  element.append(textOrNode);
}

التحسينات الرئيسية في هذا التحديث:

  • مسح المحتوى الحالي قبل إضافة محتوى جديد
  • قبول إما سلاسل نصية أو عقد DOM كمعلمات
  • استخدام طريقة append() للمرونة
  • الحفاظ على التوافق مع الاستخدام النصي الحالي

تجربة لوحة المعلومات الخاصة بك

حان وقت الحقيقة! لنرى لوحة المعلومات الديناميكية الخاصة بك قيد العمل:

  1. قم بتسجيل الدخول باستخدام حساب test (يحتوي على بيانات نموذجية جاهزة)
  2. انتقل إلى لوحة المعلومات الخاصة بك
  3. تحقق من ظهور صفوف المعاملات بتنسيق صحيح
  4. تأكد من أن التواريخ، الأوصاف، والمبالغ تبدو جيدة

إذا كان كل شيء يعمل، يجب أن ترى قائمة معاملات وظيفية بالكامل على لوحة المعلومات الخاصة بك! 🎉

ما أنجزته:

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

لقد نجحت في تحويل صفحة ويب ثابتة إلى تطبيق ويب ديناميكي.


تحدي GitHub Copilot Agent 🚀

استخدم وضع Agent لإكمال التحدي التالي:

الوصف: قم بتحسين التطبيق المصرفي من خلال تنفيذ ميزة البحث والتصفية للمعاملات التي تسمح للمستخدمين بالعثور على معاملات محددة حسب نطاق التاريخ، المبلغ، أو الوصف. المهمة: إنشاء وظيفة بحث لتطبيق البنك تتضمن: 1) نموذج بحث يحتوي على حقول إدخال لنطاق التاريخ (من/إلى)، الحد الأدنى/الأقصى للمبلغ، وكلمات مفتاحية لوصف المعاملة، 2) وظيفة filterTransactions() لتصفية مصفوفة account.transactions بناءً على معايير البحث، 3) تحديث وظيفة updateDashboard() لعرض النتائج المصفاة، و4) إضافة زر "مسح الفلاتر" لإعادة العرض إلى حالته الأصلية. استخدم طرق حديثة لمصفوفات JavaScript مثل filter() وتعامل مع الحالات الخاصة بمعايير البحث الفارغة.

تعرف على المزيد حول وضع الوكيل هنا.

🚀 التحدي

هل أنت مستعد لنقل تطبيق البنك الخاص بك إلى المستوى التالي؟ دعنا نجعله يبدو ويشعر وكأنه شيء ترغب فعلاً في استخدامه. إليك بعض الأفكار لتحفيز إبداعك:

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

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

أضف بعض اللمسات: فكر في تلوين المعاملات (الأخضر للدخل، الأحمر للنفقات)، إضافة أيقونات، أو إنشاء تأثيرات عند التمرير تجعل الواجهة تبدو تفاعلية.

إليك كيف يمكن أن تبدو لوحة التحكم المصقولة:

لقطة شاشة لنتيجة مثال للوحة التحكم بعد التنسيق

لا تشعر بأنك مضطر لمطابقة هذا بالضبط - استخدمه كمصدر إلهام واجعلها خاصة بك!

اختبار ما بعد المحاضرة

اختبار ما بعد المحاضرة

الواجب

إعادة هيكلة وتعليق الكود الخاص بك


إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.