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

Mustafa Suleiman

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

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

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

  • عدد الأيام التي تصدر بها

    300

أجوبة بواسطة Mustafa Suleiman

  1. ستحتاج إلى دورة علوم الحاسب وستتعلم بها التالي: 

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

    حيث أن الدورة مناسبة لمن:

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

    وبعد ذلك تستطيع إختيار اللغة والمجال الذي تريده التخصص به، سواء كان دورة تطوير التطبيقات باستخدام لغة JavaScript أو دورة تطوير تطبيقات الويب باستخدام لغة PHP.

    وقد تم الإجابة على سؤال مشابه لسؤالك من قبل في النقاشات التالية، أرجو منك قرائتها وستحصل على فائدة بالتأكيد:

     

  2. تم الإجابة على أغلب أسئلتك بشكل وافي، لكن بخصوص التكلفة أنت بحاجة إلى معرفة التالي:

    في البداية قد تضطر إلى قبول تصميم صفحة هبوط مثلاً تتكلف 100 دولار بمبلغ 50 أو 25 دولار، وذلك من أجل الحصول على أول عميل لك على مواقع العمل الحر.

    حيث أن التكلفة الطبيعية لصفحة الهبوط تتراوح ما بين 50 إلى 100 دولار وقد تصل إلى 300 دولار، وذلك تبعًا لمدى التعقيد في التصميم وهل سيتم تنفيذ التصميم من قبلك، أم ستقوم باستلام التصميم جاهز وستعمل على أنت على تنفيذه.

    بعد ذلك، سيتعين عليك استكشاف متوسط الأسعار التي يطلبها المستقلين الآخرين، وهو عامل هام للمنافسة في ذلك السوق، فلن تستطيع رفع سعرك إلا إذا كان لديك سنوات خبرة ومعرض أعمال مميز.

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

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

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

    وقد تم النقاش حول العمل الحر وحساب تكلفة المشروع في النقاشات التالية بشكل مفصل أكثر:

     

    • أعجبني 1
  3. في React، تستطيع استخدام روابط داخلية باستخدام react-router-dom أيضًا، حتى في صفحة ويب واحدة (وهي عبارة عن عناصر تحكم توجيه).

    وذلك باستخدام عناصر التحكم مثل <Link> و <NavLink> و <Route> في أي مكان داخل مكونات React الخاصة بك لإنشاء روابط داخلية.

    مثال لاستخدام عنصر التحكم <Link> لإنشاء رابط داخلي كما يلي:

    import { Link } from 'react-router-dom';
    
    function MyComponent() {
      return (
        <div>
          <h1>Welcome to my website!</h1>
          <p>Click <Link to="/about">here</Link> to learn more about me.</p>
        </div>
      );
    }

    كما ترى من خلال  <Link> تمكنا من إنشاء رابط داخلي يؤدي إلى صفحة "حول" (/about) في نفس التطبيق، وعند النقر على الرابط ، سيتم تحديث المحتوى المعروض في التطبيق دون إعادة تحميل الصفحة بالكامل.

    ويمكنك أيضا استخدام عنصر التحكم <Route> لتحديد المسارات المتناغمة مع الروابط الداخلية، والذي يستخدم لإظهار محتوى معين عند زيارة رابط معين.

    import { Route } from 'react-router-dom';
    
    function MyComponent() {
      return (
        <div>
          <h1>Welcome to my website!</h1>
          <p>Click <Link to="/about">here</Link> to learn more about me.</p>
          <Route path="/about">
            <About />
          </Route>
        </div>
      );
    }

    حيث يتم عرض محتوى معين (component About) عند زيارة الرابط /about، وعند زيارة الرابط، سيتم تحديث المحتوى المعروض في التطبيق دون إعادة تحميل الصفحة بالكامل.

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

    • شكرًا 1
  4. يتوفر في أكاديمية حسوب دورة خاصة بلغة البايثون، حيث ستتعلم فيها ما يلي:

    • الأسس البرمجية السليمة عبر لغة Python
    • التعامل مع مختلف صيغ الملفات مثل إكسل Excel وورد Word وخدمات المستندات السحابية
    • استخراج البيانات من صفحات الويب Web Scraping وتحليلها
    • أساسيات التعامل مع قواعد البيانات عبر بايثون، والتعامل مع البريد الإلكتروني لإرسال الرسائل
    • أساسيات إطار العمل جانغو Django
    • بناء تطبيق إدارة المهام باستخدام إطار العمل جانغو Django
    • تطوير متجر إلكتروني متكامل باستخدام إطار العمل جانغو Django وربطه مع وسائل الدفع باي بال PayPal وسترايب Stripe
    • أساسيات إطار العمل فلاسك Flask، وبناء مدونة بسيطة
    • تطوير واجهة برمجية API اعتمادًا على نمط RESTful لمعالجة الصور

    وبإمكانك قراءة المقالات التالية للتعرف على الأساسيات، واكتساب نظرة شاملة حور التطوير بلغة بايثون:

    وقد تحتاج إلى قراءة النقاشات التالية:

     

  5. يمكنك ببساطة إضافة القيمة 7.5 إلى حلقة الـ for في برنامج MATLAB،  من خلال إضافتها إلى المعادلة الخاصة بك، كما هو موضح في المثال التالي:

    for i=1:15
       x = i + 7.5;
       % أو يمكنك استخدام القيمة 7.5 مباشرةً في المعادلة الخاصة بك
       % x = i * 7.5;
       fig = العمليات الرياضية الأخرى هنا
    end

    ويجب استخدام الرموز الرياضية الصحيحة في المعادلة الخاصة بك للحصول على نتائج صحيحة.

    وإذا لم يكن ذلك المقصود، أرجو منك مشاركة الكود بشكل نصي هنا من خلال علامة <> عند كتابة السؤال أو التعليق.

  6. يوجد خطأ في السطر السادس من البرنامج.

    حيث لا يمكن استخدام معاملات مثل "result1 = 0" في تعبير شرطي مثل "1 if x==Qustion1 else result1 = 0".

    ويجب استخدام فقط التعبير الشرطي دون المعاملات، ولذلك يمكن إصلاحه عن طريق استخدام التعبير الشرطي في السطر السادس بدون المعاملات كما يلي:

    result1 = 1 if x==Qustion1 else 0
    result2 = 1 if y==Qustion2 else 0
    result3 = 1 if z==Qustion3 else 0

    وهناك عدة طرق لتحسين كتابة البرنامج الخاص بك، ومنها:

    1- استخدام دالة لتقوم بطباعة السؤال واستقبال الإجابة، وذلك لتجنب تكرار الأكواد المتشابهة. 

    def ask_question(question, answer):
        user_input = int(input(question))
        return 1 if user_input == answer else 0
    
    result1 = ask_question("What is 4 + 4? ", 8)
    result2 = ask_question("What is 2 * 3? ", 6)
    result3 = ask_question("What is 5 ** 3? ", 125)
    
    sum = result1 + result2 + result3
    print(sum)

    2- استخدام حلقة تكرارية مثل for لتكرار الأسئلة وجمع النتائج.

    questions = [("What is 4 + 4? ", 8), ("What is 2 * 3? ", 6), ("What is 5 ** 3? ", 125)]
    sum = 0
    
    for question, answer in questions:
        user_input = int(input(question))
        if user_input == answer:
            sum += 1
    
    print(sum)

    3- استخدام القوائم لتخزين الأسئلة والإجابات، وذلك لتسهيل تعديل وإضافة الأسئلة. 

    questions = [
        {"question": "What is 4 + 4? ", "answer": 8},
        {"question": "What is 2 * 3? ", "answer": 6},
        {"question": "What is 5 ** 3? ", "answer": 125},
    ]
    
    sum = 0
    
    for q in questions:
        user_input = int(input(q["question"]))
        if user_input == q["answer"]:
            sum += 1
    
    print(sum)

     

    • شكرًا 1
  7. بتاريخ 1 ساعة قال Abdelrahman Hamed:

    شكراً جزيلاً لك استاذ محمد على إهتمامك بالموضوع..

    المشكلة اني اريد اضافة هذه الأكواد في بلوجر.. لذلك فكرة اني اقوم بإنشاء ملف منفصل تكون صعبة

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

    في البداية، قم بفتح ملف الـ XML الخاص بقالب بلوجر وأضف أكواد HTML و CSS الخاصة بتصميمك.

    كمثال:

    <b:if cond='data:blog.pageType == &quot;index&quot;'>
      <div class="featured-post">
        <img src="IMAGE_URL" alt="Featured Post Image">
        <h2><a href="POST_URL">عنوان المقال المميز</a></h2>
        <p>محتوى المقال المميز</p>
      </div>
    </b:if>
    
    <style>
      .featured-post {
        background-color: #f9f9f9;
        padding: 20px;
        border: 1px solid #ddd;
      }
      
      h2 a {
        color: #333;
        font-size: 24px;
        text-decoration: none;
      }
      
      p {
        color: #666;
        font-size: 16px;
      }
    </style>

    بعد ذلك، يمكنك إستدعاء تصميمك في أي مقالة بإستخدام الـ JavaScript.

    مثلاً، إذا أردت إستدعاء التصميم في أول مقالة على الصفحة الرئيسية، يمكنك إضافة هذا الكود في صفحة المقال:

    <div id="featured-post"></div>
    
    <script>
      const featuredPost = document.getElementById("featured-post");
      const featuredPostHTML = '<b:if cond=\'data:blog.pageType == &quot;index&quot;\'>' +
                              '<div class="featured-post">' +
                                '<img src="IMAGE_URL" alt="Featured Post Image">' +
                                '<h2><a href="POST_URL">عنوان المقال المميز</a></h2>' +
                                '<p>محتوى المقال المميز</p>' +
                              '</div>' +
                            '</b:if>';
      const featuredPostCSS = '.featured-post { background-color: #f9f9f9; padding: 20px; border: 1px solid #ddd; } h2 a { color: #333; font-size: 24px; text-decoration: none; } p { color: #666; font-size: 16px; }';
      
      featuredPost.innerHTML = featuredPostHTML;
      const style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = featuredPostCSS;
      document.getElementsByTagName('head')[0].appendChild(style);
    </script>

    حيث يقوم هذا الكود بإستدعاء تصميم المقال المميز الذي تم إضافته في ملف الـ XML ويعرضه في صفحة المقال.

    ويمكنك تعديل هذا الكود ليتناسب مع تصميمك الخاص.

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

    أيضا إضافة المزيد من الخصائص والأساليب إلى التصميم الخاص بك باستخدام CSS، كتغيير ألوان الخطوط والخلفيات، وتحديد المسافات بين العناصر.

    أما إذا أردت استدعاء ملفات HTML و CSS :

    فعليك باستخدام كود جافاسكريبت كالتالي:

    function loadCSS(url) {
      const link = document.createElement('link');
      link.type = 'text/css';
      link.rel = 'stylesheet';
      link.href = url;
      document.getElementsByTagName('head')[0].appendChild(link);
    }
    
    function loadHTML(html) {
      const article = document.createElement('article');
      article.innerHTML = html;
      document.getElementById('article-container').appendChild(article);
    }
    
    loadCSS('styles.css');
    loadHTML('<div class="my-div"><h1>Hello World!</h1></div>');

    حيث يقوم الكود بتحميل ملف CSS عن طريق إنشاء عنصر link وإضافته إلى رأس الصفحة، ثم يقوم بإنشاء عنصر article ويضيف الـ HTML الذي تم تمريره كنص داخله.

    ثم يضيف هذا العنصر إلى عنصر الـ article-container في صفحة المقال.

    ويمكنك تعديل الـ HTML والـ CSS وتمريرها كمتغيرات إلى الدالة loadHTML و loadCSS على التوالي.

    ولا تنسى تغيير article-container بمعرف العنصر الذي تريد عرض المقال فيه.

    وهناك طريقة أخرى وهي إضافة أكواد HTML و CSS مباشرًة:

    1. قم بتسجيل الدخول إلى حساب بلوجر الخاص بك.
    2. اختر مدونتك وانتقل إلى صفحة "تخطيط" القالب.
    3. اضغط على زر "تحرير HTML" الذي يوجد في الزاوية اليمنى العليا من الصفحة.
    4. ابحث عن العنصر الذي تريد إضافة إليه الأكواد HTML و CSS، و قد يكون هذا العنصر، مثلاً، الجزء الخاص بمحتوى المدونة أو القائمة الجانبية أو الهيدر أو الفوتر.
    5. انقر فوق موضع العنصر الذي تريد تعديله، ثم الصق الأكواد HTML و CSS الخاصة بك بالداخل.
    6. بمجرد الانتهاء من الإضافات، انقر على زر "حفظ" في الزاوية اليمنى العليا للصفحة.

    مثال:

    <div class="header">
      <h1>عنوان المدونة</h1>
      <img src="رابط الشعار" alt="شعار المدونة">
    </div>

     

    أضف الأكواد CSS الخاصة بك في قسم الستايلات style الموجود في نفس صفحة التحرير:

    <style>
      .header {
        background-color: #eee;
        padding: 20px;
        text-align: center;
      }
      
      h1 {
        color: #333;
        font-size: 36px;
        margin-bottom: 10px;
      }
      
      img {
        max-width: 100%;
        height: auto;
      }
    </style>

    بهذا، ستكون قد أضفت عنوانًا وشعارًا إلى الهيدر.

  8. يجب عليك إضافة عنصر آخر إلى ملف AndroidManifest.xml لتمكين Deep Linking من التعرف على وسائل تواصل URL المحددة والمسموح بها في التطبيق.

    وتستطيع إضافة تحويل الروابط العادية إلى روابط عميقة باستخدام مكتبة "react-native-deep-linking" التي تقدم وظائف لإنشاء روابط عميقة واستخدامها في تطبيق React Native.

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

    أولاً ، يجب تثبيت المكتبة باستخدام npm:

    npm install --save react-native-deep-linking

    ثم استيرادها في ملف JS الخاص بك:

    import DeepLinking from 'react-native-deep-linking';

    وهناك دالة DeepLinking.addScheme متوفرة لإضافة أسماء الأساليب الخاصة بتطبيقك إلى قائمة الأساليب المسموح بها للاتصال العميق.

    DeepLinking.addScheme('mychat://');

    ثم استخدام دالة DeepLinking.addRoute لإضافة أنواع معينة من الطرق إلى الأساليب المسموح بها للاتصال العميق.

    مثلاً، إذا كنت تريد أن تكون قادرًا على النقر فوق الروابط التي تحتوي على "/chat/" في الرابط لفتح تطبيقك وعرض المحادثات المتعلقة بهذا المستخدم ، يمكنك استخدام هذا الأمر:

    DeepLinking.addRoute('/chat/:username', (response) => {
      const username = response.username;
      // Perform the appropriate action based on the username parameter
    });

    ستعمل هذه الوظيفة عندما يتم النقر على الروابط التي تحتوي على "mychat://chat/jane".

    أيضًا، يجب إضافة بعض الأكواد إلى ملف AndroidManifest.xml لتمكين التطبيق من التعرف على الروابط العميقة.

    حيث يجب أن تحتوي على وسم <intent-filter> تحت العلامة <activity> في ملف AndroidManifest.xml يحتوي على بيانات الروابط العميقة المراد تمكين التطبيق من التعرف عليها.

    وتحديد مجموعة من البيانات المتعلقة بالروابط العميقة مثل البروتوكول، الرابط الأساسي، وأي معلمات إضافية إذا كانت موجودة.

    ففي الكود السابق، تم إضافة فلاتر النوايا (intent filters) للاعتراف بالروابط العميقة المرتبطة بـ "mychat" و "www.example.com".

    بعد إضافة هذه الفلاتر، عليك باستخدام مكتبة مثل "react-native-deep-link" للتفاعل مع روابط العمليات العميقة في التطبيق، وللتعرف على الروابط العميقة وتحويلها إلى عمليات داخل التطبيق.

    كمثال، تستطيع استخدام الكود التالي للاستجابة لروابط العمليات العميقة:

    import { Linking } from 'react-native';
    
    Linking.addEventListener('url', (event) => {
      // Handle deep link event
    });

    تستخدم دالة Linking.addEventListener للاستماع إلى حدث رابط العمليات العميقة، ويمكن استخدام دالة Linking.getInitialURL للتحقق مما إذا كان التطبيق يفتح لأول مرة باستخدام رابط عملية عميقة.

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

  9. بتاريخ 2 ساعة قال Moath Haimour:

    لم أقم بالتجربة،  ولكن المشكلة قد تكمن في أن الدالة save() في ملف models/cart.js تقوم بإضافة المنتج إلى ملف السلة التسوق كل مرة يتم فيها استدعاءها.

    بمعنى آخر، إذا تم زيادة كمية منتج معين في سلة التسوق بالفعل، فإن الدالة save() ستزيد الكمية مرة أخرى عندما يتم استدعاءها مرة أخرى.

    وتستطيع حل هذه المشكلة بتعديل الدالة Cart.save في ملف cart.js للتأكد من إذا كان المنتج موجودًا بالفعل في العربة فلا تزيد عدد الكمية بل يتم الاحتفاظ بها كما هي، بينما إذا كان المنتج غير موجود يتم حفظه في العربة بعدة قطع والكمية تكون واحدة.

    static async save(id, price) {
      try {
        const cartFile = path.join(__dirname, "../", "data", "cart.json");
        const fileContent = await fs.readFile(cartFile);
        const cart = JSON.parse(fileContent);
        const productIndex = cart.products.findIndex((product) => product.id === id);
    
        if (productIndex !== -1) {
          cart.products[productIndex].quantity++;
        } else {
          cart.products.push({ id, price, quantity: 1 });
        }
    
        await fs.writeFile(cartFile, JSON.stringify(cart));
      } catch (error) {
        console.log(error);
      }
    }

     

  10. اللغة الأكثر استخدامًا في مجال الذكاء الاصطناعي هي لغة بايثون، ولكن أولاً، يمكنك البدء بتعلم الأساسيات في علم الحاسوب والرياضيات، حيث يعتبر التميز في هذين المجالين ضروريًا لفهم مفاهيم الـ AI.

    بعد ذلك، يمكنك تعلم لغات البرمجة المستخدمة في AI مثل Python و R و MATLAB، ويوجد في أكاديمية حسوب دورة كاملة خاصة بلغة البايثون، ستتعلم فيها ما يلي:

    ماذا ستتعلم في هذه الدورة؟

    • الأسس البرمجية السليمة عبر لغة Python

    • التعامل مع مختلف صيغ الملفات مثل إكسل Excel وورد Word وخدمات المستندات السحابية
    • استخراج البيانات من صفحات الويب Web Scraping وتحليلها
    • أساسيات التعامل مع قواعد البيانات عبر بايثون، والتعامل مع البريد الإلكتروني لإرسال الرسائل
    • أساسيات إطار العمل جانغو Django
    • بناء تطبيق إدارة المهام باستخدام إطار العمل جانغو Django
    • تطوير متجر إلكتروني متكامل باستخدام إطار العمل جانغو Django وربطه مع وسائل الدفع باي بال PayPal وسترايب Stripe
    • أساسيات إطار العمل فلاسك Flask، وبناء مدونة بسيطة
    • تطوير واجهة برمجية API اعتمادًا على نمط RESTful لمعالجة الصور

    وقد تم النقاش من قبل حول مجال الذكاء الاصطناعي، فأرجو من قراءة التالي تجنبًا للتكرار:

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

     

  11. Await في Flutter هي كلمة مفتاحية تستخدم مع العمليات الغير متزامنة أو العمليات الثقيلة التي لا يمكن تنفيذها بشكل فوري.

    ويتم استخدام Await في Flutter لتحسين أداء التطبيق وتجنب حدوث مشاكل في التنفيذ، حيث تستخدمات Await مع دوال تعيد Future في Flutter، وتسمى هذه الدوال بـ "Future Functions".

    وعند استخدام Await مع Future Function، يتم إيقاف تنفيذ الدالة الحالية حتى يتم الانتهاء من العملية الغير متزامنة، واسترداد القيمة المتوقعة، ولذلك، فاستخدام Await في Flutter يساعد على تنظيم تنفيذ البرنامج وتفادي حدوث المشاكل والأخطاء التي قد تنجم عن تنفيذ العمليات الثقيلة بشكل متزامن.

    مثلاً، إذا كان لدينا دالة fetchData() التي تقوم بجلب بيانات من API وتعيد Future، يمكننا استخدام await لجلب البيانات وإظهارها في واجهة المستخدم كما يلي:

    Future<void> fetchData() async {
      // جلب البيانات من API
      final response = await http.get(Uri.parse('https://example.com/api/data'));
      
      // تحويل بيانات الاستجابة إلى قائمة من العناصر
      final data = jsonDecode(response.body) as List<dynamic>;
      
      // إظهار البيانات في واجهة المستخدم
      setState(() {
        _data = data;
      });
    }

    وتستطيع استخدام await مع أي دالة تعيد Future في Flutter، مثل دوال تعيد Future من نوع SharedPreferences و AnimationController. 

    مثال آخر:

     إذا كان لدينا طريقة لاستدعاء ملف JSON من الإنترنت باستخدام حزمة http في Flutter ، فتستطيع استخدام await لإيقاف تنفيذ الكود حتى يتم جلب الملف:

    import 'package:http/http.dart' as http;
    
    Future<String> fetchJson() async {
      final response = await http.get(Uri.parse('https://example.com/data.json'));
    
      if (response.statusCode == 200) {
        return response.body;
      } else {
        throw Exception('Failed to load data');
      }
    }

    تعود الدالة fetchJson بـ Future<String> ، وتستخدم http.get() لجلب بيانات JSON من URL.

    بعد ذلك ، نستخدم await لإيقاف تنفيذ الكود حتى يتم جلب الملف.

    إذا كانت الاستجابة من الملقم بنجاح (مثلاً ،رمز الاستجابة 200) ، فستعود الدالة بـ response.body (الجسم الخاص بالاستجابة) كنص String ، وإلا سيتم تنفيذ Exception.

  12. تم التوضيح من قبل عزيزي،  يمكنك دمج البيانات المسترجعة من الجدولين في نفس القائمة باستخدام الدالة addAll() في مكانين مختلفين في الكود.

    هناك عدة طرق للقيام بذلك وهذا مثال لكيفية الدمج:

    Future<void> _fetchData() async {
        final FirebaseFirestore firestore = FirebaseFirestore.instance;
    
        // Fetch the first query snapshot and extract the value of 'TopicState'
        final QuerySnapshot topicsSnapshot = await firestore
            .collection('topics')
            .where('id', isEqualTo: widget.PostID)
            .get();
        final int topicState =
        topicsSnapshot.docs.isNotEmpty ? topicsSnapshot.docs.first.get('Id_Sub_Category') : null;
    
        
        final QuerySnapshot subCategorySnapshot =
        await firestore.collection('Sub_Category').where('idSubCat', isEqualTo: topicState).get();
    
    
        final List<FullListWomanModel> data = [];
    
        if (topicsSnapshot.docs.isNotEmpty) {
          data.addAll(topicsSnapshot.docs.map((doc) => FullListWomanModel.fromJson(doc.data() as Map<String, dynamic>)).toList());
        }
    
        if (subCategorySnapshot.docs.isNotEmpty) {
          // Loop over the documents of the Sub_Category collection and check if the document already exists in the data list to avoid duplication
          subCategorySnapshot.docs.forEach((doc) {
            final FullListWomanModel model = FullListWomanModel.fromJson(doc.data() as Map<String, dynamic>);
            if (!data.contains(model)) {
              data.add(model);
            }
          });
        }
    
        setState(() {
          _ListDataDisplay = data;
        });
    }

    الكود يقوم بإضافة جميع الوثائق التي تم العثور عليها في الجدول الثاني Sub_Category إلى القائمة data، ولكنه يتحقق أيضًا مما إذا كانت الوثيقة موجودة بالفعل في القائمة الرئيسية لتجنب التكرار والحفاظ على وجود عناصر فريدة في القائمة المدمجة النهائية.

    • أعجبني 1
  13. حاول تنفيذ التالي : 

    استخدام قيمة مشتركة بين الجدولين (idSubCat) لدمج البيانات في القائمة، بعد دمج البيانات ، وإضافة القائمة المدموجة إلى القائمة الرئيسية التي تحتوي على جميع البيانات.

    Future < void > _fetchData() async {
        final FirebaseFirestore firestore = FirebaseFirestore.instance;
    
        final QuerySnapshot subCategorySnapshot = await firestore
            .collection('Sub_Category')
            .where('idSubCat',
                isEqualTo: (await firestore
                    .collection('topics')
                    .where('id', isEqualTo: widget.PostID)
                    .get())
                .docs
                .first
                .get('Id_Sub_Category'))
            .get();
    
        final List < FullListWomanModel > data = [];
    
        if (subCategorySnapshot.docs.isNotEmpty) {
            final List < FullListWomanModel > subCategories = subCategorySnapshot.docs
                .map((doc) => FullListWomanModel.fromJson(doc.data() as Map < String, dynamic > ))
                .toList();
            data.addAll(subCategories);
        }
    
        final QuerySnapshot topicsSnapshot = await firestore
            .collection('topics')
            .where('id', isEqualTo: widget.PostID)
            .get();
    
        if (topicsSnapshot.docs.isNotEmpty) {
            final List < FullListWomanModel > topics = topicsSnapshot.docs
                .map((doc) => FullListWomanModel.fromJson(doc.data() as Map < String, dynamic > ))
                .toList();
            // Merge the two lists based on a common field
            final Map < int, FullListWomanModel > mergedData = {};
            for (final topic in topics) {
                mergedData[topic.id] = topic;
            }
            for (final subCategory in subCategories) {
                mergedData[subCategory.idSubCat] = subCategory;
            }
            final List < FullListWomanModel > mergedList = mergedData.values.toList();
    
            data.addAll(mergedList);
        }
        setState(() {
            _ListDataDisplay = data;
        });
    }

     

    • أعجبني 1
  14. قمت بتعديل الكود لك ليصبح مختصرًا أكثر ويحصل على نفس البيانات بشكل أكثر فعالية، وتستطيع استخدام الدالة "sort" بعد ذلك إذا رغبت في فرز البيانات.

    Future<void> _fetchData() async {
      final FirebaseFirestore firestore = FirebaseFirestore.instance;
    
      final QuerySnapshot subCategorySnapshot = await firestore
          .collection('Sub_Category')
          .where('idSubCat',
              isEqualTo: (await firestore
                      .collection('topics')
                      .where('id', isEqualTo: widget.PostID)
                      .get())
                  .docs
                  .first
                  .get('Id_Sub_Category'))
          .get();
    
      final List<FullListWomanModel> data = [];
    
      if (subCategorySnapshot.docs.isNotEmpty) {
        final List<FullListWomanModel> subCategories = subCategorySnapshot.docs
            .map((doc) => FullListWomanModel.fromJson(doc.data() as Map<String, dynamic>))
            .toList();
    
        data.addAll(subCategories);
      }
    
      setState(() {
        _ListDataDisplay = data;
      });
    }

    وإليك شرح مختصر، الكود يستخدم Firebase للاستعلام عن بيانات من جداول مختلفة ودمجها في مصفوفة واحدة.

    وذلك من خلال استخدام الحقل الفريد في جدول الـ "topics" للوصول إلى جدول الـ "Sub_Category" باستخدام دالة الـ "join" ، ثم جمع البيانات التي تحتاجها في مصفوفة واحدة باستخدام الدالة "addAll".

    وتستطيع الاستغناء عن sort فأنت لست بحاجة إليها بالنسبة لسؤالك.

    • أعجبني 1
  15. حاول تجربة الحل التالي:

    1. استخدم الحقل الفريد في جدول الـ "topics" للوصول إلى جدول الـ "Sub_Category" ، وذلك باستخدام دالة الـ "join".
    2. اجمع البيانات التي تحتاجها في مصفوفة واحدة باستخدام الدالة "addAll" كما هو موضح في الكود الحالي الخاص بك.
    3. ثم، تستطيع استخدام الدالة "sort" لفرز المصفوفة بناءً على الوقت الذي تم الحصول عليه من كل جدول.

    ليصبح الكود بعد التعديل كالتالي:

    Future<void> _fetchData() async {
      final FirebaseFirestore firestore = FirebaseFirestore.instance;
    
      final QuerySnapshot topicsSnapshot = await firestore
          .collection('topics')
          .where('id', isEqualTo: widget.PostID)
          .get();
      final int topicState =
          topicsSnapshot.docs.isNotEmpty ? topicsSnapshot.docs.first.get('Id_Sub_Category') : null;
    
      final QuerySnapshot subCategorySnapshot = await firestore
          .collection('Sub_Category')
          .where('idSubCat', isEqualTo: topicState)
          .get();
    
      final List<FullListWomanModel> data = [];
    
      // 1. دمج الجدولين بإستخدام join
      if (topicsSnapshot.docs.isNotEmpty && subCategorySnapshot.docs.isNotEmpty) {
        final List<QuerySnapshot> snapshots = await Future.wait([
          firestore.collection('topics').where('id', isEqualTo: widget.PostID).get(),
          firestore
              .collection('Sub_Category')
              .where('idSubCat', isEqualTo: topicState)
              .get(),
        ]);
    
        final List<FullListWomanModel> topics = snapshots[0].docs.map((doc) =>
            FullListWomanModel.fromJson(doc.data() as Map<String, dynamic>)).toList();
        final List<FullListWomanModel> subCategories = snapshots[1].docs.map((doc) =>
            FullListWomanModel.fromJson(doc.data() as Map<String, dynamic>)).toList();
    
        // 2. إضافة البيانات إلى مصفوفة واحدة باستخدام addAll
        data.addAll(topics);
        data.addAll(subCategories);
    
        // 3. فرز المصفوفة بناءً على الوقت الذي تم الحصول عليه من كل جدول
        data.sort((a, b) => b.time.compareTo(a.time));
      }
    
      setState(() {
        _ListDataDisplay = data;
      });
    }

     

    • أعجبني 1
  16. أرجو أن أكون قد فهمت سؤالك بشكل صحيح، أنت تريد إضافة خدمة جديدة صحيح؟

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

    وقد تم شرح من قبل كيف يتم إضافة الخدمات على منصة خمسات.

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

     

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

    وقد ذكرت لك من قبل طريقة استدعاء البيانات في سؤالك الذي طرحته هنا.

    فأرجو منك التوضيح، ما الذي تم تعديله على الكود الخاص بك، وماهي الأخطاء لنتمكن من مساعدتك.

    وعليك بالتحقق من النقاط التالية:

    1.  تأكد من أن اسم المستخدم وكلمة المرور واسم قاعدة البيانات المستخدمة في ملف الاتصال config.php صحيحة ومتطابقة مع تلك المستخدمة في phpMyAdmin.
    2.  الاستعلام المرسل إلى قاعدة البيانات صحيح ولا يحتوي على أخطاء إملائية أو أخرى.
    3.  المتغيرات المستخدمة في استعلام SQL معرفة مسبقًا وليس لها أي قيم غير صحيحة أو فارغة.
    4. استخدام دالة mysqli_query() يعيد نتيجة صحيحة ولا يوجد بها أي خطأ.
    5.  المتغيرات المستخدمة في الاستعلام SQL تمرر بشكل صحيح إلى دالة mysqli_query()، عن طريق تحديد قيمتها بشكل صحيح في استعلام SQL.
    6. نوع البيانات المرجعة من استخدام دالة mysqli_query() هي من نوع mysqli_result، وإلا فإنها ستكون قيمة خاطئة وستؤدي إلى حدوث الأخطاء.
    7. المتغيرات المستخدمة في العرض والاستخدام في الكود معرفة مسبقًا ولا يوجد بها أي قيم غير صحيحة أو فارغة.
    8. الصفحة التي تستخدمها لعرض البيانات تحتوي على المكونات اللازمة لعرض البيانات بشكل صحيح، مثل جدول HTML وعناوين الأعمدة وصفوف البيانات.

     

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

    والحد الأدنى لتعلم البرمجة يمكن أن يختلف من شخص لآخر، وذلك يعتمد على مدى الاستعداد والقدرة على التعلم والتفاعل مع المواد التعليمية. ومع ذلك، فإن الحد الأدنى الموصى به للبدء في تعلم البرمجة هو حوالي 8-10 سنوات، ويمكن للأطفال في هذا العمر أن يتعلموا البرمجة باستخدام لغات البرمجة المناسبة لهذا العمر مثل Scratch و Blockly وغيرها.

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

    وإليك نبذة مختصرة عن الدورة:

    ماذا ستتعلم في هذه الدورة؟

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

    لمن هذه الدورة؟

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

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

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

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

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

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

     

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

    وفي البداية عليك بمعرفة المجالات الملطوبة في مواقع العمل الحر  والتي منها المواقع التالية:

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

    1.  أعمال وخدمات استشارية
    2.  برمجة، تطوير المواقع والتطبيقات
    3.  هندسة، عمارة وتصميم داخلي
    4.  تصميم، فيديو وصوتيات
    5.  تسويق إلكتروني ومبيعات
    6.  كتابة، تحرير، ترجمة ولغات
    7.  دعم، مساعدة وإدخال بيانات
    8.  تدريب وتعليم عن بعد

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

    والأمر قد يبدوا معقد من الخارج، لكن خطوة بخطوة سيسهل الأمر عليك والجميع بدأ من نقطة الصفر.

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

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

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

    وأيضًا قد تحتاجي إلى قراءة النقاش التالي:

     

    • أعجبني 1
  20. بتاريخ 12 دقائق مضت قال زمزم بنت يوسف:

    شكرا ،جزاك الله خيرا، سؤال آخر لوسمحت هل تعلم إذا كان بإمكان ربط كود بايثون مع كود React Native؟

    بالإمكان ربط كود بايثون مع كود React Native باستخدام Bridge API.

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

    ويتم تنفيذ Bridge API باستخدام وظيفة "native modules" في React Native و "Python modules" في بايثون. ويجب معرفة أنه يمكن استخدام Bridge API لتوفير القدرة على إعادة استخدام برامج بايثون الموجودة بالفعل وإضافة ميزات جديدة إلى تطبيقات React Native باستخدام لغة بايثون.

    مثلاً، تستطيعي استخدام بايثون لإنشاء نماذج التعلم الآلي والتفاعل معها في تطبيق React Native، وذلك من خلال مكتبة TensorFlow المتاحة في بايثون لإنشاء نماذج تعلم الآلة وتدريبها على البيانات.

    وبعد ذلك نستخدم Bridge API لربط تطبيق React Native مع تلك النماذج وتوفير واجهة المستخدم اللازمة لتفاعل المستخدمين معها.

    مثال بسيط على طريقة الربط بين بايثون وReact Native

    في البداية، عليك بإنشاء وحدة بايثون بسيطة تُسمى "calculator.py" وضعي بها الكود التالي:

    def add(a, b):
        return a + b

    الآن سنقوم بإنشاء Native Module في React Native لاستدعاء هذه الوحدة. يمكنك إنشاء ملف جديد يسمى "CalculatorModule.js" وضعي به التالي:

    import { NativeModules } from 'react-native';
    
    const { Calculator } = NativeModules;
    
    export default {
      add: (a, b) => {
        return Calculator.add(a, b);
      },
    };

    وتأكدي من تحديد اسم Native Module كـ "Calculator"، ثم يمكنك استخدام هذا Native Module في كود React Native الخاص بك.

    من خلال إنشاء شاشة جديدة تُسمى "CalculatorScreen.js" كالتالي:

    import React, { useState } from 'react';
    import { View, Text, TextInput, Button } from 'react-native';
    import Calculator from './CalculatorModule';
    
    const CalculatorScreen = () => {
      const [a, setA] = useState('');
      const [b, setB] = useState('');
      const [result, setResult] = useState('');
    
      const handleAdd = () => {
        const res = Calculator.add(Number(a), Number(b));
        setResult(res.toString());
      };
    
      return (
        <View>
          <TextInput value={a} onChangeText={setA} />
          <TextInput value={b} onChangeText={setB} />
          <Button title="Add" onPress={handleAdd} />
          <Text>{result}</Text>
        </View>
      );
    };
    
    export default CalculatorScreen;

    وكما ترين يتم استدعاء Native Module "Calculator" واستخدامه في دالة "handleAdd" لجمع الأعداد المدخلة، وعرض نتيجة الجمع في عنصر "Text".

    والمثال بسيط لكنه يوضح كيفية استخدام Bridge API لربط كود بايثون مع كود React Native، وبنفس المبدأ تستطيعي تطوير تطبيقات React Native متكاملة مع قواعد البيانات والتحكم في التحليلات والأدوات الأخرى.

    • أعجبني 1
  21. بالطبع يمكنك إنشاء مواقع، تطبيقات وبرامج سطح مكتب باستخدام جافاسكريبت.

    والتطبيقات يتم إنشائها باستخدام إطار العمل الشهير "React Native"، و الذي يستخدم مجموعة متنوعة من التقنيات والأدوات بما في ذلك HTML و CSS و JavaScript لإنشاء تطبيقات الهواتف.

    وبالنسبة لكفاءة التطبيقات المبنية باستخدام الجافاسكريبت، فإنها متقاربة في الأداء مقارنة باللغات الأخرى المستخدمة في تطوير التطبيقات مثل Swift و Kotlin و Java.

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

    والمقارنة ظالمة بعض الشيء، حيث أن React Native يسمح لك بإنشاء تطبيقات متعددة المنصات بسهولة بين منصتي iOS و Android ، وبالتالي يسهل عملية تطوير التطبيقات ويوفر الكثير من الوقت والجهد.

    أما التطبيقات الأصلية Native المبنية بواسطة Swift و Kotlin و Java فهي لا تعمل على المنصات الأخرى، أي Swift تستخدم لبناء تطبيقات لنظام iOS بينما  Kotlin و Java لنظام أندرويد.

    وقد تم ذكر المزيد من التفاصيل والشرح والمقارنات في نقاشات سابقة، أرجو منك قرائتها تجنبًا للتكرار.

     

    • أعجبني 1
  22. مساحة الرامات لديك صغيرة جدًا، وتشغيل نظامي وهمي على تلك المساحة من الرامات أمر صعب، لذلك يجب أن تكون على الأقل 8 جيجابايت وتلك مساحة صغيرة أيضًا، ففي الوقت الحالي المساحة المناسبة للرامات هي 16 جيجابايت.

    وذلك لتتمكن من تشغيل المتصفح ومتابعة الدروس وتشغيل محرر الأكواد وبرامج أخرى بجانب النظام الوهمي وأيضًا النظام الأساسي الخاص بك يشغل ما بين 2 جيجابايت إلى 4 جيجابايت.

    ولا تضغط على نفسك كثيرًا، يكفيك 8 جيجابايت من الذاكرة العشوائية لتعمل بشكل جيد، والأفضل هو 16 أو 12 جيجابايت حسب استطاعتك.

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

    لكن كما أشرت لك، الأمر يتوقف على ميزانيتك ولا تضغط على نفسك كثيرًا ،قم بشراء الرامات أولاً وتستطيع شراء رامات مستخدمة و SSD وأيضًا بتكلفة منخفضة.

    • شكرًا 1
  23. .loader {
      border: 16px solid #f3f3f3;
      border-top: 16px solid #3498db;
      border-radius: 50%;
      width: 120px;
      height: 120px;
      animation: spin 2s linear infinite;
    }
    
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    السبب هو أنك قمت بنسخ تنسيق CSS الخاص بالـ Loader السابق حيث أنني وفرت لك تنسيق للـ Loader بسيط يقوم بالدوران، أما إذا أردت استخدام الصورة فعليك باستخدام تنسيق مختلف أي قم بإزالة التنسيق الذي نسخته أنت.

    وعليك بتنسيق كلاس .loader بالشكل الذي تراه مناسبًا.

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

  24. عليك بإضافة مسار الصورة الصحيح في الكود الذي اشرت إليه سابقٌا، فمثلاً لو كانت الصورة داخل مجلد images في مجلد المشروع فسيصبح المسار كالتالي:

    <!-- loader -->
      <div class="loader">
        <img src="images/loader.gif">
      </div>

     

  25. السبب في أن جميع العناصر لديها نفس القيمة percentage هو لأنه تم تحديث القيمة في الحلقة forEach بشكل متكرر وتم استخدام نفس الحالة لجميع العناصر.

    ولذلك، عليك باستخدام دالة محدثة لتحديث قيمة percentage لكل عنصر في الحدث onscroll.

    ويمكن تغيير الكود كالتالي:

    const [percentage, setPercentage] = useState({})
    
    window.onscroll = function () {
      if (window.scrollY >= progressAnim.current.offsetTop - 300) {
        skills.forEach(skill => {
          setPercentage(prevPercentage => ({
            ...prevPercentage,
            [skill.id]: skill.progress
          }))
        })
      }
    }
    
    return (
      <div className="App">
        <Section src={img_1} />
        <Section src={img_2} />
        <div className="skills" ref={progressAnim}>
          {skills.map(skill => (
            <Progress
              key={skill.id}
              percentage={percentage[skill.id] || 0}
              circleWidth="200"
              name={skill.language}
            />
          ))}
        </div>
      </div>
    )

    حيث تم تحويل القيمة percentage إلى كائن حيث يتم استخدام معرف العنصر كمفتاح.

    ثم استخدام دالة محدثة لتحديث قيمة percentage بشكل منفصل لكل عنصر. أخيراً، واستخدام القيمة المحدثة في كل عنصر في عنصر تقدم الدائرة Progress.

    طريقة أخرى 

    و هناك طريقة أخرى لحل هذه المشكلة، وهي باستخدام useEffect بدلاً من استخدام دالة محدثة في حدث onscroll، كالتالي:

    const [percentage, setPercentage] = useState({})
    
    useEffect(() => {
      const handleScroll = () => {
        if (window.scrollY >= progressAnim.current.offsetTop - 300) {
          const newPercentage = {}
          skills.forEach(skill => {
            newPercentage[skill.id] = skill.progress
          })
          setPercentage(newPercentage)
        }
      }
      window.addEventListener('scroll', handleScroll)
      return () => {
        window.removeEventListener('scroll', handleScroll)
      }
    }, [skills, progressAnim])
    
    return (
      <div className="App">
        <Section src={img_1} />
        <Section src={img_2} />
        <div className="skills" ref={progressAnim}>
          {skills.map(skill => (
            <Progress
              key={skill.id}
              percentage={percentage[skill.id] || 0}
              circleWidth="200"
              name={skill.language}
            />
          ))}
        </div>
      </div>
    )

    باستخدام useEffect بدلاً من الحدث onscroll، يتم استدعاء دالة handleScroll في كل مرة يتم فيها التمرير، وتحدث قيمة percentage فقط إذا تم تمرير العنصر المطلوب.

    ثم إضافة الحدث الذي يتم استدعاءه إلى النافذة في useEffect. وفي النهاية، وإزالة الحدث عند إزالة المكون.

×
×
  • أضف...