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

لوحة المتصدرين

  1. Wael Aljamal

    Wael Aljamal

    الأعضاء


    • نقاط

      11

    • المساهمات

      6975


  2. محمد أبو عواد

    محمد أبو عواد

    الأعضاء


    • نقاط

      3

    • المساهمات

      6234


  3. Flutter Dev

    Flutter Dev

    الأعضاء


    • نقاط

      3

    • المساهمات

      787


  4. Salah Kr

    Salah Kr

    الأعضاء


    • نقاط

      2

    • المساهمات

      98


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 02/19/22 في كل الموقع

  1. السلام عليكم كتبت كود بلغة php لجلب البيانات من قاعدة البيانات الى جدول ولكن عند تكرار البيانات في الجدول تكون النتيجة قي الحقل الاول فقط ولا يرفق البقية للجدول بل يضيفها خارج الجدول
    2 نقاط
  2. يمكن استخدام لغة الأنماط الانسيابية CSS في إنشاء رسوم متحركة بسيطة، دون الحاجة إلى شيفرة JavaScript إطلاقًا، لكن يمكننا بالطبع استخدام JavaScript للتحكم برسوم CSS المتحركة وجعلها أفضل بكتابة القليل من الشيفرة. الحركة الانتقالية في CSS إنّ فكرة الحركة الانتقالية transition في CSS بسيطة جدًا، حيث نصف خاصيةً محددةً وآليةً لإظهار التغيرات فيها على شكل رسوم متحركة، فعندما تتغير قيمة الخاصية سيُظهر المتصفح هذا التغيير في حركة، وبالتالي كل ما علينا فعله هو تغيير الخاصية، وسينفذ المتصفح دفقًا من التغيرات المتتالية فيها. تُحرّك شيفرة CSS التغييرات في الخاصية background-color لمدة ثلاث ثوان: .animated { transition-property: background-color; transition-duration: 3s; } فلو كان لأي عنصر الصنف CSS الذي سميناه animated، فستظهر أي تغيرات على الخاصية background-color في هذا العنصر في حركة لمدة 3 ثوان. انقر على الزر الذي ستُظهره الشيفرة التالية لتحريك الخلفية: <button id="color">Click me</button> <style> #color { transition-property: background-color; transition-duration: 3s; } </style> <script> color.onclick = function() { this.style.backgroundColor = 'red'; }; </script> See the Pen JS-P3-03-Fetch-Download-progress-ex8 by Hsoub (@Hsoub) on CodePen. توصف الحركة الانتقالية في CSS بأربعة خصائص، هي: transition-property. transition-duration. transition-timing-function. transition-delay. سنشرح هذه الخصائص بعد قليل، لكن دعونا نلاحظ أنّ الخاصية transition ستسمح بالتصريح عن الخصائص الأربعة السابقة معًا وفق الترتيب التالي:property duration timing-function delay، بالإضافة إلى قدرتها على إظهار الحركة الانتقالية على عدة خصائص معًا. يُظهر النقر على الزر في الشيفرة التالية الحركة الانتقالية للخاصيتين color وfont-size: <button id="growing">Click me</button> <style> #growing { transition: font-size 3s, color 2s; } </style> <script> growing.onclick = function() { this.style.fontSize = '36px'; this.style.color = 'red'; }; </script> See the Pen JS-P3-05-CSS-animations-ex2 by Hsoub (@Hsoub) on CodePen. سنشرح الآن خصائص الحركة الانتقالية. الخاصية transition-property نكتب ضمن هذه الخاصية قائمةً بخصائص CSS التي نريد إظهار تغييراتها على شكل حركة انتقالية، مثل left وmargin-left وheight وcolor وغيرها، أو يمكن أن نختار all التي تعني تحريك كل الخصائص . توجد خصائص لا يمكن تحريكها، لكن معظم الخصائص شائعة الاستعمال وقابلة للتحريك. الخاصية transition-duration يمكن أن نحدد في هذه الخاصية المدة التي ستجري فيها الحركة الانتقالية، وينبغي أن يكون التوقيت بتنسيق CSS ومقدرًا بالثانية s أو بالميلي ثانية ms. الخاصية transition-delay نحدد في هذه الخاصية فترة الانتظار قبل عرض الحركة الانتقالية، فلو كانت قيمتها ثانيةً واحدةً وقيمة الخاصية transition-duration ثانيتن، فستُعرض الحركة الانتقالية بعد ثانية من تغيّر الخاصيّة، وستستمر لمدة ثانيتين، كما يمكن استخدام قيم سالبة أيضًا، وعندها ستبدأ الحركة مباشرةً، إلا أنّ نقطة البداية ستنسحب قليلًا، فلو كانت قيمة الخاصية transition-delay هي "-1" ثانية وقيمة الخاصية transition-duration هي "2" ثانية، فستبدأ الحركة من المنتصف، ولمدة ثانية واحدة. لاحظ تغير الأعداد من 0 إلى 9 في الرسم المتحرك التالي باستخدام الخاصية translate في CSS: شيفرة الملف script.js: stripe.onclick = function() { stripe.classList.add('animate'); }; شيفرة الملف style.css: #digit { width: .5em; overflow: hidden; font: 32px monospace; cursor: pointer; } #stripe { display: inline-block } #stripe.animate { transform: translate(-90%); transition-property: transform; transition-duration: 9s; transition-timing-function: linear; } شيفرة الملف index.html: <!doctype html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> </head> <body> Click below to animate: <div id="digit"><div id="stripe">0123456789</div></div> <script src="script.js"></script> </body> </html> وستكون النتيجة: تجري الحركة الانتقالية للخاصية transform بالشكل التالي: #stripe.animate { transform: translate(-90%); transition-property: transform; transition-duration: 9s; } تضيف شيفرة JavaScript السابقة الصنف animate إلى العنصر، وتبدأ الحركة عند تنفيذ الأمر: stripe.classList.add('animate'); يمكن أن نبدأ التحريك انطلاقًا من نقطة ما من الحركة الانتقالية، أي من رقم محدد -وقد يكون متعلقًا بالثانية الحالية مثلًا- وباستخدام قيمة سالبة للخاصية transition-delay. لو نقرت على الرقم في المثال التالي، فستبدأ الحركة من الثانية الحالية: شيفرة الملف script.js: stripe.onclick = function() { let sec = new Date().getSeconds() % 10; stripe.style.transitionDelay = '-' + sec + 's'; stripe.classList.add('animate'); }; شيفرة الملف style.css: #digit { width: .5em; overflow: hidden; font: 32px monospace; cursor: pointer; } #stripe { display: inline-block } #stripe.animate { transform: translate(-90%); transition-property: transform; transition-duration: 9s; transition-timing-function: linear; } شيفرة الملف index.html: <!doctype html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> </head> <body> Click below to animate: <div id="digit"><div id="stripe">0123456789</div></div> <script src="script.js"></script> </body> </html> وستكون النتيجة: يمكن تنفيذ ذلك باستخدام JavaScript لكن بإضافة سطر آخر من الشيفرة: stripe.onclick = function() { let sec = new Date().getSeconds() % 10; // مثلًا تعني القيمة -3 هنا أن الحركة ستبدأ من الثانية الثالثة stripe.style.transitionDelay = '-' + sec + 's'; stripe.classList.add('animate'); }; الخاصية transition-timing-function تصف دالة التوقيت هذه كيفية توزيع الحركة الانتقالية أثناء فترة العرض، كأن تبدأ ببطء ثم تسرع، أو العكس. ستبدو هذه الخاصية في البداية معقدة، لكنها ستغدو بسيطةً إذا فهمناها، كما ستقبل نوعين من القيم هما منحني بيزيه Bezier curve، أو الدالة steps، لنبدأ مع المنحني كونه الأكثر استخدامًا. منحني بيزيه يمكن إعداد منحنى بيزيه بأربعة نقاط حاكمة تحقق الشروط التالية: إحداثيات النقطة الأولى (0,0). إحداثيات النقطة الأخيرة (1,1). ينبغي أن يكون الإحداثي x لنقطتي المنتصف بين 0 و1، بينما يمكن أن نختار أي قيمة للإحداثي y. إن صيغة منحني بيزيه هي: (cubic-bezier(x2, y2, x3, y3، إذًا علينا فقط أن نحدد النقطتين الحاكمتين الثانية والثالثة، لأنّ الأولى والأخيرة ثابتتان. تحدد دالة التوقيت سرعة تحريك عملية تشكيل المنحني: يمثل المحور x محور الزمن الذي يبدأ بالنقطة "0"، وينتهي بالنقطة "1" لقيمة transition-duration. يمثل المحور y مقدار اكتمال العملية، ويبدأ بالنقطة "0" وينتهي بالنقطة "1" لقيمة الخاصية التي نريد إظهار الحركة الانتقالية لها. المثال الأبسط هو التحريك المنتظم، أي الخطي، وذلك باستخدام المنحني (cubic-bezier(0, 0, 1, 1، الذي سيبدو بالشكل التالي: عندما يمر الوقت (x) ستكتمل عملية التحريك (y) بثبات وتناغم من القيمة 0 إلى 1. وفي مثالنا التالي ستتحرك صورة القطار من اليسار إلى اليمين بسرعة ثابتة، إذا نقرت عليه: شيفرة الملف style.css: .train { position: relative; cursor: pointer; width: 177px; height: 160px; left: 0; transition: left 5s cubic-bezier(0, 0, 1, 1); } شيفرة الملف index.html: <!doctype html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> </head> <body> <img class="train" src="https://js.cx/clipart/train.gif" onclick="this.style.left='450px'"> </body> </html> وستكون النتيجة: إليك شيفرة استخدام الخاصية transition بناءً على منحني بيزيه: .train { left: 0; transition: left 5s cubic-bezier(0, 0, 1, 1); /* JavaScript sets left to 450px */ } لكن كيف سنرى القطار وهو يُبطئ؟ يمكن استعمال منحني بيزيه آخر من الشكل (cubic-bezier(0.0, 0.5, 0.5 ,1.0، وفي المقال التالي سنرى كيفية بدء العملية بسرعة، حيث يتحرك القطار سريعًا ثم يتباطأ. شيفرة الملف style.css: .train { position: relative; cursor: pointer; width: 177px; height: 160px; left: 0px; transition: left 5s cubic-bezier(0.0, 0.5, 0.5, 1.0); } شيفرة الملف index.html: <!doctype html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> </head> <body> <img class="train" src="https://js.cx/clipart/train.gif" onclick="this.style.left='450px'"> </body> </html> وستكون النتيجة: شيفرة CSS: .train { left: 0; transition: left 5s cubic-bezier(0, .5, .5, 1); /* JavaScript sets left to 450px */ } يمكنك استخدام العديد من المنحنيات الجاهزة، مثل linear أو ease أو ease-in أو ease-out أو ease-in-out، وإليك جدولًا بالمنحنيات الموافقة لها: وفي ملاحظة هامة، تجدر الإشارة إلى أن * تستخدَم ease قيمةً افتراضيةً إذا لم نحدد دالة توقيت timing-function. وكما هو واضح يمكن استعمال ease-out في حالة القطار الذي يُبطئ حركته: .train { left: 0; transition: left 5s ease-out; /* transition: left 5s cubic-bezier(0, .5, .5, 1); */ } لكنه يبدو مختلفًا نوعًا ما. قد تتجاوز الحركة الانتقالية المدى عند استخدام منحني بيزيه. ويمكن أن تحمل النقاط الحاكمة في منحني بيزيه أي قيمة للإحداثي y حتى القيم السالبة أو الضخمة، وبهذا قد يمتد المنحني على مساحة ضيقة جدًا أو واسعة جدًا، وقد تتجاوز الرسوم المتحركة مداها الطبيعي. لاحظ الشيفرة التالية: .train { left: 100px; transition: left 5s cubic-bezier(.5, -1, .5, 2); /* JavaScript sets left to 400px */ } ينبغي إظهار حركة انتقالية للخاصية left بين القيمتين 100px و400px، لكنك بالنقر على صورة القطار سترى ما يلي: أولًا سيتراجع القطار إلى الخلف، وستغدو قيمة left أقل من 100px. يتقدم بعدها القطار إلى الأمام لتتجاوز left القيمة 400px بقليل. ثم يعود مجددًا إلى القيمة 400px للخاصية left. شيفرة الملف style.css: .train { position: relative; cursor: pointer; width: 177px; height: 160px; left: 100px; transition: left 5s cubic-bezier(.5, -1, .5, 2); } شيفرة الملف index.html: <!doctype html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> </head> <body> <img class="train" src="https://js.cx/clipart/train.gif" onclick="this.style.left='400px'"> </body> </html> وستكون النتيجة على النحو الآتي: ما جرى واضح جدًا إذا نظرنا إلى رسم منحني بيزيه لهذه الحركة، فقد نقلنا قيمة الإحداثي y للنقطة الثانية تحت الصفر، وجعلنا قيمته بالنسبة للنقطة الثالثة تتجاوز 1، لذا سيخرج شكل المنحني عن الشكل النظامي للمنحني من الدرجة الرابعة، فقيمة y خارج المجال المعياري بين 0 و1. وكما نعرف، تقيس y مدى اكتمال الحركة الانتقالية، حيث تتطابق القيمة y = 0 مع بداية الحركة، والقيمة y = 1 مع نهايتها. إذًا ستنقل القيمة y<0 نقطة البدء إلى ما قبل البداية، والقيمة y>1 إلى ما بعدها. يُعَد هذا التغيير بسيطًا طبعًا، فلو ضبطنا y على القيمة 99 أو -99، فسيقفز القطار بسرعة أكبر بكثير خارج المجال، لكن كيف سننشئ منحني بيزيه من أجل مهمة معينة؟ هنالك أدوات كثيرة، كما يمكن تنفيذه ضمن مواقع عديدة على الإنترنت. دالة التوقيت steps تسمح دالة التوقيت ([steps(number of steps[, start/end بتقسيم الحركة الانتقالية إلى خطوات، لنرى ذلك من خلال مثال قائمة من الأرقام التي لا تبدي أي حركة: شيفرة الملف style.css: #digit { border: 1px solid red; width: 1.2em; } #stripe { display: inline-block; font: 32px monospace; } شيفرة الملف index.html: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> </head> <body> <div id="digit"><div id="stripe">0123456789</div></div> </body> </html> وستكون النتيجة: سنُظهر الأرقام منفصلة، وذلك بجعلها غير مرئية خارج النافذة الحمراء، بعدها سنحرك القائمة نحو اليسار في كل خطوة، وبالتالي سنحتاج إلى 9 خطوات لتنفيذ الأمر: #stripe.animate { transform: translate(-90%); transition: transform 9s steps(9, start); } شيفرة الملف style.css: #digit { width: .5em; overflow: hidden; font: 32px monospace; cursor: pointer; } #stripe { display: inline-block } #stripe.animate { transform: translate(-90%); transition-property: transform; transition-duration: 9s; transition-timing-function: steps(9, start); } شيفرة الملف index.html: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> </head> <body> Click below to animate: <div id="digit"><div id="stripe">0123456789</div></div> <script> digit.onclick = function() { stripe.classList.add('animate'); } </script> </body> </html> وستكون النتيجة: يُمثّل الوسيط الأول للدالة (steps(9, start عدد الخطوات، أي ستقسم الحركة الانتقالية إلى 9 أجزاء -10% لكل خطوة-، كما سيُقسم الفاصل الزمني تلقائيًا إلى 9 أجزاء أيضًا، فلو كانت قيمة الخاصية transition تعادل 9 ثوان، فسيظهر كل رقم لمدة ثانية؛ أما الوسيط الثاني فيأخذ إحدى القيمتين start أو end، حيث تعني القيمة start أننا نريد تنفيذ الخطوة الأولى مباشرةً عند بداية الحركة، ويمكنك ملاحظة ذلك خلال الحركة، فعندما ننقر على الرقم سيتغير إلى "1" -أي الخطوة الأولى- مباشرةً، ثم يكمل ثانيةً وهكذا. تتقدم العملية كالتالي: -10% - 0s: يحدث التغيير الأول في بداية الثانية الأولى مباشرةً. 1s – -20%. … 8s – -80%. تُظهر الثانية الأخيرة القيمة الأخيرة. بينما تعني القيمة end وجوب تطبيق التغيير في نهاية كل ثانية، ويكتمل في نهاية الثانية المعدودة. وتتقدم العملية كالتالي: 0s – 0: لا يتغير شيء في الثانية الأولى. 1s – -10%: يحدث التغير الأول عند نهاية الثانية الأولى مباشرةً. 2s – -20%. … 9s – -90%. إليك مثالًا نموذجيًا عن استخدام الدالة (steps(9, start. شيفرة الملف style.css: #digit { width: .5em; overflow: hidden; font: 32px monospace; cursor: pointer; } #stripe { display: inline-block } #stripe.animate { transform: translate(-90%); transition-property: transform; transition-duration: 9s; transition-timing-function: steps(9, end); } شيفرة الملف index.html: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> </head> <body> Click below to animate: <div id="digit"><div id="stripe">0123456789</div></div> <script> digit.onclick = function() { stripe.classList.add('animate'); } </script> </body> </html> وستكون النتيجة: إليك بعض القيم المختصرة: step-start: تماثل (steps(1, start. step-end: تماثل (steps(1, end. لا تستخدم هذه القيم إلا نادرًا لأنها لا تُصنَّف حركات فعلًا، بل تغيرات تحدث بالخطوة. الحدث transitionend يقع الحدث transitionend عندما تنتهي الحركة المبنية على خصائص CSS، ويستخدم لتنفيذ عمل ما بعد انتهاء الحركة، حيث يمكننا مثلًا ضم حركات مختلفة، فالسفينة في المثال التالي ستبدأ رحلتها وتستمر بالعودة عند النقر، وفي كل مرة تبتعد نحو اليمين أكثر: تبدأ الحركة نتيجة تنفيذ الدالة go، التي يُعاد تنفيذها في كل مرة تنتهي فيها الحركة، وتغير اتجاه الحركة: boat.onclick = function() { //... let times = 1; function go() { if (times % 2) { // sail to the right boat.classList.remove('back'); boat.style.marginLeft = 100 * times + 200 + 'px'; } else { // sail to the left boat.classList.add('back'); boat.style.marginLeft = 100 * times - 200 + 'px'; } } go(); boat.addEventListener('transitionend', function() { times++; go(); }); }; لكائن الحدث transitionend عدة خصائص مميزة، هي: event.propertyName: يعيد اسم الخاصية التي أنهت حركتها الانتقالية، وتظهر فائدتها عند تحريك عدة خصائص معًا. event.elapsedTime: الوقت الذي استغرقته الحركة بالثواني، دون احتساب transition-delay. القاعدة keyframes يمكن ضم عدة حركات بسيطة معًا باستخدام قاعدةkeyframes@ من CSS، والتي تحدد اسم الحركة الانتقالية، وقواعد مكانها وزمانها وكيفيتها، بعدها سنتمكن باستخدام الخاصية animation من ربط الحركة بالعنصر وتخصيص معاملات إضافية قد نحتاجها، إليك مثالًا مع الشرح: <div class="progress"></div> <style> @keyframes go-left-right { /* "go-left-right" أعط القاعدة اسمًا*/ from { left: 0px; } /* left: 0px حرك ابتداءً من قيمة */ to { left: calc(100% - 50px); } /* 100%-50px: حرك نحو اليسار */ } .progress { animation: go-left-right 3s infinite alternate; /* طبق الحركة التي عرفناها في الأعلى على العنصر المدة 3 ثوان عدد المرات: لانهائي بدّل اتجاه الحركة في كل مرة */ position: relative; border: 2px solid green; width: 50px; height: 20px; background: lime; } </style> See the Pen JS-P3-05-CSS-animations-ex3 by Hsoub (@Hsoub) on CodePen. ستجد العديد من المقالات التي تشرح القاعدة @keyframes من CSS مع ميزاتها المفصلة، ولن تحتاجها غالبًا إلا عندما يكون كل شيء في موقعك متحركًا باستمرار. الأداء يمكن تحريك أغلب خاصيات CSS بما أنها قيم رقمية مثل width و color و font-size، فيعمل المتصفح عندما تحرك هذه الخاصيات على تغيير هذه القيم تدريجيًا في كل إطار من الإطارات مما يعطي إيحاء بتأثير حركي سلس، ولكن انتظر، لا تبدو كل الحركات سلسلة كما تريدها لأن تغيير بعض خاصيات CSS عملية مجهدة. لنغوص أكثر في التفاصيل، عندما يكتشف المتصفح حدوث تغير في التنسيق، فإنه يمر بثلاثة خطوات حتى يخرج الصفحة بالتنسيق الجديد وهي: التخطيط Layout: إعادة حساب إحداثيات ومواضع كل عنصر من عناصر الصفحة، ثم الشكل Paint: إعادة حساب كيف يجب أن يظهر كل عنصر بعد تموضعه في مكانه وكل شيء حرفيًا بما فيها الخلفيات والألوان، ثم التركيب Composite: تصيير النتائج النهائية وإخراجها وعرضها على بكسلات الشاشة وتطبيق تحويلات CSS إن وجدت. تكرر هذه الخطوات خلال إجراء تحريك عبر CSS لكل إطار من الإطارات، رغم أن خاصيات CSS التي لا تؤثر على الإحداثيات أو التموضع مثل تغيير خاصية اللون color فقد تتخطى الخطوة الأولى وينتقل المتصفح إلى الخطوة الثانية مباشرةً ثم الثالثة وقد تتخطى بعض الخاصيات حتى الخطوة الثانية وتنتقل إلى الخطوة الثالثة مباشرةً، ويمكنك أن تطلع على قائمة خاصيات CSS والمراحل التي تستهدفها من موقع CSS Triggers. معلومٌ أن تلك الخطوات تأخذٌ وقتًا في الحساب خصوصًا إن حوت الصفحة على عناصر كثيرة وكانت تخطيطها معقدًا، فقد يُلاحظ تأخر في الحركة على أغلب الأجهزة مسببًا حركة مضطربة مرتعشة، لذا تتصف الحركات المطبقة على الخاصيات التي تتخطى حساب التخطيط (ويفضل أيضًا الشكل أي الخطوة الثانية) بالسرعة والسلاسة. تعد الخاصية transform خيارًا جيدًا لسببين هما: تستهدف التحويلات في CSS صندوق العنصر ككل (تدوير، أو قلب أو تمديد أو إزاحة …إلخ.) لا تؤثر التحويلات على العناصر المجاورة للعنصر المستهدف. وفقًا ذلك، تطبق التحويلات على عناصر يكون فيها التخطيط والشكل محسوبين مسبقًا وتنتقل مباشرةً إلى الخطوة الثالثة من الخطوات السابقة، أي أن المتصفح يحسب التخطيط (الحجم والمواضع) ثم يضيف لها تسنيق الشكل من ألوان وواجهات وغيرهما في المرحلة الثانية ثم يطبق التحويل الممثل بالخاصية transform على صندوق العنصر إن وجدت. أي تغييرات (تحريكات) تطبق على الخاصية transform لا تستدعي المرور ضمن الخطوة الأولى والثانية مطلقًا، علاوة على أن المتصفح يستغل قدرات الحاسوب الرسومية (بطاقة العرض التي تكون مدمجة في المعالج أو منفصلة) لمعالجة التحويلات مما يزيد من كفاءة العملية. مما سبق نجد أن الخاصية transform قوية للغاية ويمكنك عبرها تدوير عنصرٍ أو قلبه أو تطويله أو تقصيره أو حتى تحريكه وغيرها (انظر صفحة الخاصية على موسوعة حسوب)، فيمن استعمال transform: translateX(…)‎ بدلًا من استعمال الخاصية left أو margin-left أو استعمال transform: scale لزيادة حجم عنصر وهكذا. لاحظ أن الخاصية opacity لا تمر على الخطوة الأولى من الخطوات السابقة (أيضًا تتخطى الخطوة الثانية في محرك Mozilla Gecko)، ويمكن استعمالها لتطبيق تأثيرات مثل الإظهار أو الإخفاء أو التلاشي، ويمكن استعمال transform معها لإنشاء حركات سلسلة جميلة. انظر مثلًا المثال التالي الذي يتحرك فيه العنصر بمجرد الضغط عليه إلى اليمين مقدار 300 بكسل ثم يختفي: <img src="https://js.cx/clipart/boat.png" id="boat"> <style> #boat { cursor: pointer; transition: transform 2s ease-in-out, opacity 2s ease-in-out; } .move { transform: translateX(300px); opacity: 0; } </style> <script> boat.onclick = () => boat.classList.add('move'); </script> See the Pen JS-P3-05-CSS-animations-ex4 by Hsoub (@Hsoub) on CodePen. وإليك أيضًا مثال آخر أكثر تعقيدًا يُطبَّق فيه إطارات الحركة ‎@keyframes: <h2 onclick="this.classList.toggle('animated')">click me to start / stop</h2> <style> .animated { animation: hello-goodbye 1.8s infinite; width: fit-content; } @keyframes hello-goodbye { 0% { transform: translateY(-60px) rotateX(0.7turn); opacity: 0; } 50% { transform: none; opacity: 1; } 100% { transform: translateX(230px) rotateZ(90deg) scale(0.5); opacity: 0; } } </style> See the Pen JS-P3-05-CSS-animations-ex5 by Hsoub (@Hsoub) on CodePen. خلاصة تسمح الحركات الانتقالية التي تدعمها CSS بإجراء تغيرات ناعمة على خاصية أو أكثر، وهي تقنية جيدة للكثير من مهام الرسوم المتحركة، كما يمكننا استخدام رسوم JavaScript المتحركة وهذا ما سنراه في جزئية لاحقة من هذه السلسلة. النقاط الأساسية التي تجعل الرسومات المتحركة باستخدام CSS محدودةً موازنةً برسوم JavaScript هي: الإيجابيات. تنفَّذ الأشياء البسيطة ببساطة. سريعة وخفيفة على المعالج. السلبيات. رسوم JavaScript أكثر مرونةً، إذ يمكنها تنفيذ أي منطق رسومي، مثل "انفجار" عنصر مثلًا. لا تعتمد رسوميات JavaScript على تغيرات الخاصية، بل يمكن إنشاء عناصر جديدة في JavaScript مثل جزء من الرسوميات. في أمثلتنا الأولى حركنا font-size وleft وwidth وheight، لكن إذا رغبنا في أداء أفضل في مشاريعنا الحقيقية، فيجب أن نستخدم ()transform: scale و()transform: translate. يمكن تنفيذ الرسوميات المتحركة باستخدام CSS كما شرحناها في هذا المقال، وسيسمح لنا الحدث transitionend باستخدام JavaScript بعد انتهاء الحركة الانتقالية، وبالتالي ستتكامل جيدًا مع الشيفرة. سنتعرف في المقال القادم على رسوم JavaScript المتحركة التي تساعدنا في تنفيذ حالات أكثر تعقيدًا. مهام لإنجازها تحريك طائرة في CSS أظهر رسمًا متحركًا يشابه صورة الطائرة في الأسفل: يزداد حجم الصورة من 40x24px إلى 400x240px. تستغرق العملية 3 ثوان. اطبع كلمة "!Done" عند الانتهاء. لا يجب أن تتوقف العملية بالنقر على الصورة أثناء التنفيذ. افتح المثال في بيئة تجريبية الحل إليك الشيفرة: /* original class */ #flyjet { transition: all 3s; } /* JS adds .growing */ #flyjet.growing { width: 400px; height: 240px; } انتبه إلى أن الحدث transitionend يقع مرتين، مرة لكل خاصية، وبذلك ستظهر الرسالة مرتين إن لم نضع أي شرط تحقق. تحرك الطائرة 2 أعد التمرين السابق لكن اجعل الحجم يتجاوز الحجم الأقصى للصورة 400x240px، ثم يعود إلى هذا الحجم. الحل نريد اختيار أنسب منحني بيزيه لتلك الحركة، إذ يجب أن تحقيق y>1 في موضع ما للطائرة لتحقيق تأثير القفزة مثل cubic-bezier(0.25, 1.5, 0.75, 1.5)‎، انظر المخطط: افتح الحل في بيئة تجريبية. تحريك دائرة أنشئ الدالة showCircle(cx, cy, radius) التي تظهر دائرةً تنمو. cx,cy: يمثلان إحداثيات مركز الدائرة بالنسبة إلى إحداثيات النافذة. radius: نصف قطر الدائرة. انقر الزر لترى كيف سيظهر الحل: تجد المثال في هذه البيئة التجريبية وتجد حله في هذه البيئة التجريبية. تحريك دائرة مع دالة استدعاء انطلاقًا من المهمة السابقة، نحتاج إلى دائرة تُظهر رسالةً داخلها. ينبغي أن تظهر الرسالة مباشرةً بعد اكتمال الحركة، أي ظهور الدائرة بحجمها الكامل، وإلا سيبدو المنظر سيئًا. ترسم الدالة (showCircle(cx, cy, radius الدائرة، لكن لا يمكنها أن تدلّك على اكتمال الرسم، لذا أضف دالة استدعاء callback مثل معامل إلى الدالة السابقة (showCircle(cx, cy, radius, callback، حيث تُستدعى عندما ينتهي الرسم المتحرك. ينبغي أن تتلقى دالة الاستدعاء callback العنصر <div> للدائرة مثل وسيط. إليك مثالًا: showCircle(150, 150, 100, div => { div.classList.add('message-ball'); div.append("Hello, world!"); }); النموذج: تجد حل المثال في هذه البيئة التجريبية. ترجمة -وبتصرف- للفصل css-animations من سلسلة The Modern JavaScript Tutorial. اقرأ أيضًا المقال السابق: منحنى بيزيه وأهميته في الرسوميات وصناعة الحركات في جافاسكربت تأثيرات الانتقال والحركة في CSS منحنى بيزيه وأهميته في الرسوميات وصناعة الحركات في جافاسكربت table { width: 100%; } thead { vertical-align: middle; text-align: center; } td, th { border: 1px solid #dddddd; text-align: right; padding: 8px; text-align: inherit; } tr:nth-child(even) { background-color: #dddddd; } p iframe { border: 1px solid #e7e5e3 !important; }
    1 نقطة
  3. السلام عليكم ورحمة الله وبركاته كنت أريد القيام بعمل مشرع يقوم بعرض المننتجات وحذفها والتعديل عليها والبحث عنها قمت بعمل خاصية العرض والحذف والتعديل وكتبت كود البحث ولكنه لا يعمل أرجو حل هذه المشكلة cud.zip
    1 نقطة
  4. واجهتني مشكلة في مكتبة requests بايثون , هو ان عندما اريد طباعه الصفحه بصيغه json تظهر لي مشكله .. وهذه هي اكوادي import requests url = "https://www.instagram.com/7sampli/?__a=1" res = requests.get(url) print(res.json())
    1 نقطة
  5. تحيه طيبه للجميع لدي استفسار لو تكرمتم لو احد لديه فكره عن الامر هل سياسة تطبيق الواتساب تمنعنا من مشاركة الصور بشكل مباشر من تطبيقاتنا من خلال نظام IOS وتطبيق فلاتر الى الواتساب بشكل مباشر؟ قمت باستعمال هذا المكتبة : https://pub.dev/packages/flutter_share في نظام الاندرويد مشاركة الصور تنجح من خلال تطبيق فلاتر وارسالها بصورة مباشرة او مشاركتها مع تطبيق الواتساب ولكن في نظام iOS لم ينجح الامر كل ما يذهب هو نص فقط قمت بتجربة مشاركة الصور على نظام IOS مع تطبيقات مختلفة مثل تويتر وقد نجح الامر اذن هل سياسة الواتساب تمنع ذلك؟ او احتاج الى وضع صلاحيات محدده لفعل ذلك؟
    1 نقطة
  6. في إطار تعلم ل problème solving واجهت مشكلة لدينا قائمة Arrays = [1,2,3,6,7,1,2,2,4,4,4] يجب أن اضهر الأرقام المكررة فيها، قمت بحذف الأرقام المكررة ب سهولة، لكن انا احتاج ان اضهر هاته الأرقام المكررة ؟
    1 نقطة
  7. عليك حساب تكرار كل عدد من عناصر المصفوفة، ثم بعد الانتهاء من العد، يمكنك طباعة الأعداد التي لها تكرار حسب شرط المسألة
    1 نقطة
  8. هل الشهادة من اكادمية حسوب معترف بها دولياً
    1 نقطة
  9. كل الشكر لك اخي الكريم فعلا المشكلة ليس لها حل فعلي حتى الان وعلى ما يبدو ان مطور المكتبة يعلم بذلك ولكن قد يحتاج الى بعض الوقت حتى يتم حل المشكلة ( قمت بتخلي عن الصورة في الواتساب بنسبة الى نظام IOS حتى تحديث المكتبة) اكرر شكري لك اخي الكريم
    1 نقطة
  10. تم أحيانا خطأ قد تراه بسيط و لكن يأخذ منك الكثير من الوقت مضى أكثر من ثلاث أيام و أنا أحاول. شكرا جزيلا
    1 نقطة
  11. في الكود التالي أقوم بحفظ منشور post في قاعدة البيانات: MyModel.objects.create(title="post 1", content="Hello, Wolrd") كيفية الوصول إلى قيمة id الخاصة بالمنشور الذي تم حفظه في قاعدة البيانات للتو. هل هناك طريقة للحصول على هذا المعرف id واستخدامه في مكان آخر في الكود الخاص بي؟
    1 نقطة
  12. لدي نموذج بسيط بالشكل التالي: class Registration_FORM(ModelForm): class Meta: model = My_Class fields = ('name', 'email' , 'gender') كيف أجعل الحقل gender إختياري في جانغو Django؟ لكي لا يتم إجبار المستخدم على إدخال هذه القيمة
    1 نقطة
  13. السلام عليكم طبقت هذا الصنف كثيرا" ولم تظهر معي هذه المشكله من قبل ولا اعرف سببها في البدايه لم تظهر الصوره ولا الكلام في 6 اعمده فوجدت ان ال row اخد نصف ال container كهامش مع اني اعطيته no-gutters فقمت باعطاءه 100% من العرض فنزل لاسفل كيف اعدلها حيث انه وضع حاشيه كبيره كالصوره قمت بارفاق الصورتين
    1 نقطة
  14. يمكن ضغط أي مجلد بالطريقة التالية: ثم في التعليق نقوم بإرفاق الملف المضغوط أسفل هذه النص يوجد عبارة "اسحب الملفات إلى هنا أو اختر ملف" يمكنك من إرفاق ملفات
    1 نقطة
  15. مرحبا اعمل على مشروع استخدم فيه webpack تواجهني مشكلة عدم ظهور الصور عند تشغيل السيرفر حيث انه لا يتم عرض رسالة خطأ في التيرمينل ولا يوجد خطأ في الاستدعاء. عند تشغيل السيرفر يتم فتح صفحة html المقلصة وعند فتح الصورة لا تظهر مع انها موجودة في ملف images علما اني استخدمت loader للتعامل مع الصور ولكن الاستدعاء لا يتم من خلال المجلد images اي ان الاستدعاء يتم من ملف dist وليس من الملف images الموجود داخل dist
    1 نقطة
  16. دائما بعد استخدام خاصية float نحتاج لاستخدام الخاصية clear لكي لا تؤثر خاصية التعويم -float- على العناصر التالية , أما بالنسبة لخاصية transform فمن الممكن أن يتم ازاحة العناصر بشكل كبير فيتم تداخلها مع عناصر أخرى , هكذا ممكن أن تؤثر هذه الخاصيات على عرض العناصر
    1 نقطة
  17. المشكلة في القسم serv الذي يسبق القسم team3 , والمشكلة بالتحديد العنصر الذي لديه الصنف banner-img , لقد قمت باعطائه التنسيقات التالية section.team .serv .banner-img { float: right; ^^^^^^^^^^^^^^ width: 530px; height: 500px; transform: translateY(-320px); } بعد استخدام خاصية float يجب استخدام الخاصية clear للعنصر الأب أي العنصر overlay2 , هناك طريقة ابسط لفعل ذلك ولا داعي لاستخدام الخاصية float أو الخاصية transform, يمكنك أولا حذف الخاصيتين float و transform من العنصر banner-img واعطاءه هامش خارجي من جهة الشمال من خلال الخاصية margin كالتالي section.team .serv .banner-img { width: 530px; height: 500px; margin-left: auto; } ويمكننا اعطاء الصنف overlay2 الخاصية display وقيمتها flex وبشكل تلقائي سوف تعرض العناصر بشكل افقي section.team .overlay2 { background-color: rgba(40, 42, 42, .92); padding-left: 11.5%; padding-right: 14.5%; height: 430px; display: flex; } سوف تعرض العناصر بشكل أجمل بهذا الشكل ,وأيضا سوف تظهر الصورة الخاصة بالجوال بشكل كبير لأنك حددت عرض 99% لجميع الصور بداخل القسم team , لاحظ section.team img { width: 99%; } يمكنك تحديد الصورة بشكل محدد لكي لا تطبق على جميع الصور
    1 نقطة
  18. يمكن إرفاق الملف مضغوط مباشرة في التعليق، الرابط يحتاج صلاحية وصول
    1 نقطة
  19. حاول عدم استخدام الخاصية text بشكل عام، نحتاج لمكتبة تدعم whatsapp لنظام IOS وعند بحثي رأيت هذا التعليق، الخاصية الاختيارية text سبب هذه المشكلة له و قد عمل البرنامج عنده بعد إزالتها.
    1 نقطة
  20. أي مكتية تستخدم؟ share plus أم flutter share؟ لأنك طرحت سؤالين و كل مرة مكتبة، لا مشكلة من استخدام المكتيتين سوياً، لكن اعط المكتية اسم مستعار باستعمال as عند التضمين.
    1 نقطة
  21. سوف تصبح هكذا: Future ShareImage()async{ var urls='https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1200px-Image_created_with_a_mobile_phone.png'; final name = 'Image_created_with_a_mobile_phone'; final url=Uri.parse(urls); final res =await http.get(url); final bytes =res.bodyBytes; // هذه Share.file( title, "$name", bytes, // هنا "image/png", ) } /* final temp = await getTemporaryDirectory(); final path ='${temp.path}/imageToShare.jpg'; File(path).writeAsBytesSync(bytes); // Share.shareFiles([path],text:'Great picture'); */ جرب هذه، هنا مشاركة ملف ثنائي بصيفة binary - bytes
    1 نقطة
  22. اهلا اخي الكريم اعتذر لم اشرح جيدا المقصد اعلم طبيعة عمل الشيفرة التي ارفقتها لك ولكني اقصد لم اعلم الطريقة لكيفية إضافة الشيفرة التي أرسلتها انت مع الشيفرة التي ارفقتها انا القديمة قمت بعمل دالة للكود ليكون بشكل مستقل كالتالي: Future ShareImage()async{ var urls='https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1200px-Image_created_with_a_mobile_phone.png'; final url=Uri.parse(urls); final res =await http.get(url); final bytes =res.bodyBytes; final temp = await getTemporaryDirectory(); final path ='${temp.path}/imageToShare.jpg'; File(path).writeAsBytesSync(bytes); Share.shareFiles([path],text:'Great picture'); } ولكني هنا واجهة المشكلة : )Share.file( title, "$name.png", bytes, "image/png", // text: title,
    1 نقطة
  23. هه الشيفرة تقوم بتحميل ملف صورةمن رابط انترنت أو مخدم محلي، ثم تكتب الملف على التخزين الخاص بالتطبيق ضمن الهاتف، ثم تشارك المسار. تحتاج للمتغير path أن يكون عام للجميع اماباقي الشيفرة تستخدم ضمن دالة تحميل الصورة. لكي لا تعبث بالشيفرة القديمة أضف هذه الشيفرة كما هي في دالة function مستقلة، واربطها مع زر مشاركة. الشيفرةةالسابقة التي ارفقادتعا لك والتي تمرر bytes ل share أي ملف ثنائي بدل المسار أي مرر لها هذه مباشرة
    1 نقطة
  24. لديك حزمتين تقومان بمعالجة الصور لديك , الحزمة file-loader والحزمة html-loader , لمنع هذا التعارض تحتاج الى تثبيت اصدار 1 من حزمة html-loader من خلال الأمر التالي npm i html-loader@1.3.2 ثم جرب تشغيل السيرفر مرة أخرى ولاحظ هل يتم عرض الصور أم لا وأخبرني بالنتيجة رجاء
    1 نقطة
  25. تلك المشكلة تحدث بسبب أنك قمت بإغلاق قوس الwhile بعد إغلاق وسم table, بالإضافة أنك بدأت الحلقة قبل بدأ الوسم tbody وبالتالي يتم إغلاق الجدول وكتابة باقي الحقول خارجه, الحل أن تقوم بوضع الحلقة التكررية داخل tbody وتقوم بإغلاقها قبل إغلاق الجدول ليكون شكل الشفرة البرمجية لديك كالتالي <tbody> <?php while($row=fetch_data($query)){ ?> <tr> <td><?php echo $row['FirstName'].$row['LastName'?></td> ////باقي الحقول </tr> <?php } ?> </tbody>
    1 نقطة
  26. الأمر بسيط حيث في البدايه 1 - يجب استدعاء تلك السطور في ملف models.py from django.core.files import File from urllib import request import os بالعلم أن السطر " import os " يمكن عدم استدعاؤه ( اختياري ) 2 - يتم إنشاء class في ملف models.py كالمثال التالي : class Item(models.Model): image_file = models.ImageField(upload_to='images') image_url = models.URLField() - حيثُ أن image_file من نوع ImageField وهو الحقل الذي يتم رفع به الصوره بشكل تقليدي و أن image_url من نوع URLField وهو يقبل إدخال الروابط فقط 3 - يتم تطبيق الفكره المُراد تطبيقها عن طريق كتابة الداله التاليه أسفل ال class الذي تم انشاؤه def get_remote_image(self): if self.image_url and not self.image_file: result = request.urlretrieve(self.image_url) self.image_file.save( os.path.basename(self.image_url), File(open(result[0], 'rb')) ) self.save() حيثُ أن تلك الداله تهدف إلى جعل الأمر منطقياً من خلال معادله بسيطه تٌفيد بأنها في حال وجود ملف للصوره تم رفعه في خانة " image_file " يتم تنزيل الملف من الرابط المتواجد داخل خانة " image_url " و حفظها و اعتبارها هي الصوره الأساسيه
    1 نقطة
  27. لتقوية نفسك في أساسيات اللغة مثل التعامل مع المشاكل البرمجية التي تتطلب وضع الشروط و الحلقات و استدعاء التوابع يمكنك التوجه إلى موقع codeforces مثلا، وهو موقع مختص في المسابقات البرمجية. يمكنك من تصفح المسائل البرمجية من تبويب problem set حيث أن المسائل من نوع A هي الأسهل ثم B أصعب ثم C تصبح تعتمد على الخوارزميات في حلها.. بعد قرائتك لمسألة ما، تكتب حلاً لها في محرر الأكواد الذي تستخدمه عادة وتتأكد من تنفيذ الأمثلة sample test الموجودة في صفحة المسألة ثم يمكنك من رفع ملف الحل submit من صفحة المسألة بجهة اليمين بعد اختيار للغة البرمجة JavaScript والإصدار الذي تستخدمه. في حال كان الحل صحيح سوف يعطيك Accepter و إلا wrong answer أو شيئ آخر حسب حلك.
    1 نقطة
  28. هل يمكن بناء تطبيقات الويب جيدة ب فلاسك و دجانغو ،خصوصا فلاسك لاني بدأت في تعلمه، علما اني اتحدت عن تطبيقات الويب وليس مواقع الويب، اريد البدأ ب مواقع الويب تم المرور لتعلم تطبيقات الويب، لكن لا أعرف الكتير عن تطبيقات الويب ولهذا أسألكم هل هذا ممكن ام الأمر ممكن فقط باستخدام أطر php متلا؟ واذا كان ممكن ان تطور تطبيقات الويب ب فلاسك ما الذي يجب عليك تعلمه ؟ وشكرا
    1 نقطة
  29. Flask هو إطار عمل ويب بلغة Python صغير وخفيف الحجم يوفر أدوات وميزات مفيدة تجعل إنشاء تطبيقات الويب بواسطة Python أسهل. يمنح المطورين المرونة وهو إطار عمل يسهل الوصول إليه للمطورين الجدد حيث يمكنك إنشاء تطبيق ويب بسرعة باستخدام ملف Python واحد فقط. يستخدم Flask محرك قوالب Jinja لبناء صفحات HTML ديناميكيًا باستخدام مفاهيم Python المألوفة مثل المتغيرات والحلقات والقوائم وما إلى ذلك. ستستخدم هذه النماذج كجزء من هذا المشروع. سيسمح لك Flask بإنشاء تطبيقات ويب بسرعة في Python. يمكنك الاستفادة من مكتبات Python لإضافة ميزات متقدمة إلى تطبيق الويب الخاص بك ، مثل تخزين بياناتك في قاعدة بيانات أو التحقق من صحة نماذج الويب. المتطلبات الأساسية للتعامل مع flask : HTML,CSS اساسيات فهم مفاهيم بايثون 3 الأساسية بيئة python نبذة بسيطة عن آلية عمل flask : سنقوم بكتابة الكود الذي سيهتم بمعالجة جانب الخادم. سوف يتلقى رمزنا الطلبات من صفحات HTML. سيحدد ما الذي تتعامل معه هذه الطلبات وما يطلبونه. سيحدد أيضًا الرد الذي يجب إرساله إلى المستخدم. اي أن العملية سوف تكون مراسلة بين السيرفر و صفحات القوالب المكتوبة ب html
    1 نقطة
  30. حاولت التأكد من المشكلة وتبين أنها ليست بسبب السياسة للتطبيق، لأنه في تلك الحالة يجب أن تطبق على أندرويد أيضا. تبين أنها كانت تعمل حتى قامت واتساب بتحديث API خاصتهم، أي أنها مشكلة برمجية وفي واتساب IOS فقط. أي ملف صورة مع نص.يمكن ان تعمل المشاركة لواتساب عن طريق الخاصية التالية باستخدام bytes: Share.file( title, "$name.png", bytes, "image/png", // text: title, ) ); ويمكنك مراجعة واتساب API هنا أي الحل وضع زر مشاركة خاص بالواتساب فقط لبيئة IOS والتي يمكنك اختبارها ضمن شرط if بالاستعانة ب مزوظ platform من فلاتر
    1 نقطة
  31. تدل هذه الأرقام على عدد صفحات التعليقات المرتبطة بالدرس، حيث يتم تلقائياً عرض فقط 50 تعليق أسفل كل درس في صفحة واحدة (لتسريع تحميل الموقع، بعض الدروس تحوي على 500 تعليق فيكون حجم الصفحة ضخماً)، أما باقي التعليقات يمكن التنقل لهم عن طريق رقم الصفحة. يمكنك التعلم برمجياً عن طريقةالتقسيم التي تدعى paginating حيث تتكلم المقالة عن طريقة تطبيقها في إطار Laravel/PHP
    1 نقطة
  32. لحساب عدد المنتجات في كل وسم (Tag) نقوم بالدمج بين الدوال التالية: Count: التي تقومُ بحساب المنتجات في كل وسم annotate: التي تقوم بإنشاء حقل جديد للنتيجة. (الحقل الذي سوف نضيفه هو count). values: لتحديد حقول معينة من الكائنات في النتيجة النهائية. from django.db.models import Count # نستدعي الدالة Count result = Product.objects .values('tag') # نحدد الحقول التي ستظهر في النتيجة النهائية .annotate(count=Count('tag')) # نقوم بإنشاء حقل جديد count .order_by() النتيجة سوف تكون مماثلة لجملة ال SQL التالية: SELECT tag_id, COUNT(tag_id) AS count FROM product GROUP BY tag_id النتيجة النهائية سوف تكون على الشكل: [{'tag': 'tag1', 'count': 12}, {'tag': 'tag2', 'count': 20}, ....]
    1 نقطة
  33. لقد بحثت على جوجل ووجدت انه يجب ان تكون تلك الدالة بداخل دالة setup(). ولكن في القالب لا يوجد دالة setup. فأنشأت واحدة في قالب الاب ووضعت دالة text-load بداخلها ولكن لم يتغير اي شيء. مع العلم اني غيرت بعض العبارات عن طريق ملفات php وتغير البعض منها والبعض الاخر لم يتغير. لقد ارسلت لك ملفات العمل اذ يمكنك معاينتها ومساعدتي في حل المشكلة. شكراً لاهتمامك
    1 نقطة
  34. المصفوفة (Array) هي مجموعة من عناصر تنتمي إلى نفس النوع، وموضوعة في أماكن متجاورة في الذاكرة، ويمكن الرجوع إلى كل عنصر من عناصر المصفوفة على حدة عبر مُعرِّف فريد يُسمَّى الفهرس. ويسمح ذلك بالتصريح عن قيم متعددة لمتغير ما ومن ثم الوصول إلى كل واحدة منها بشكل منفرد دون الحاجة إلى التصريح عن متغير لكل قيمة. تهيئة المصفوفة المصفوفة هي كتلة مكوّنة من مواقع متسلسلة في الذاكرة والمخصصة لنوع معيّن من المتغيرات. تخصيص المصفوفات يشبه تخصيص المتغيرات العادية، ولكن مع إضافة قوسين مربّعين إلى اسمها [] يحتويان على عدد يمثل عدد العناصر التي يمكن أن تحتويها ذاكرة المصفوفة. يستخدم المثال التالي مصفوفة تستخدم نوع int، واسم المتغير arrayOfInts، وعدد عناصرها هو [ 5 ]: int arrayOfInts[5]; يمكن التصريح عن المصفوفة وتهيئتها في نفس الوقت على النحو التالي: int arrayOfInts[5] = {10, 20, 30, 40, 50}; إذا هيّأت مصفوفة بسرد جميع عناصرها فلا يلزمك تضمين عدد عناصر المصفوفة داخل القوسين المعقوفين، إذ سيحسُبه المُصرّف تلقائيًا. في المثال التالي، تعداد المصفوفة هو 5: int arrayOfInts[] = {10, 20, 30, 40, 50}; كذلك نستطيع تهيئة العناصر الأولى فقط، مع تخصيص مساحة للمزيد من العناصر، وفي هذه الحالة يلزمك كتابة طول المصفوفة بين القوسين المعقوفين. انظر الشيفرة التالية حيث نخصص مصفوفةً خماسية (تحتوي 5 عناصر) مع تهيئتها جزئيًّا، سيُهيّئ المصرّف بقية العناصر بالقيمة الافتراضية لنوع العنصر (في هذه الحالة، تلك القيمة هي 0). int arrayOfInts[5] = {10,20}; أي أن عناصر المصفوفة السابقة هي (10, 20, 0, 0, 0). كذلك يمكن تهيئة مصفوفات أنواع البيانات الأساسية الأخرى بالطريقة نفسها. انظر المثال التالي للتصريح عن مصفوفة وتخصيص مساحة ذاكرة لها دون تهيئتها: char arrayOfChars[5]; أو للتصريح عنها مع تهيئتها: char arrayOfChars[5] = { 'a', 'b', 'c', 'd', 'e' } ; double arrayOfDoubles[5] = {1.14159, 2.14159, 3.14159, 4.14159, 5.14159}; string arrayOfStrings[5] = { "C++", "is", "super", "duper", "great!"}; لاحظ أنه عند الوصول إلى عناصر المصفوفة فإن فهرس المصفوفة (أو موضعها) يبدأ عند القيمة 0. انظر المثال التالي، حيث يكون العنصر 10 هو العنصر رقم 0، و20 هو العنصر رقم 1، وهكذا. int array[5] = { 10, 20, 30, 40, 50}; std::cout << array[4]; // 50 std::cout << array[0]; // 10 المصفوفات متعددة الأبعاد ذات الحجم الثابت يشير الفهرس m[y]‎ في المثال أدناه إلى الصف رقم yمن المصفوفة m، حيث y مؤشرٌ يبدأ من الصفر، ويمكن فهرسة هذا الصف على النحو التالي my ‎ والذي يشير إلى العنصر/العمود x من الصف y، وذلك يعني أن الفهرس الأخير هو الأسرع تغيرًا، ونطاقه في التصريح -حيث النطاق هنا هو رقم الأعمدة لكل صف- هو آخر و"أعمق" حجم محدَّد. #include <iostream> #include <iomanip> using namespace std; auto main() -> int { int const n_rows = 3; int const n_cols = 7; int const m[n_rows][n_cols] = { { 1, 2, 3, 4, 5, 6, 7 }, { 8, 9, 10, 11, 12, 13, 14 }, { 15, 16, 17, 18, 19, 20, 21 }, }; for( int y = 0; y < n_rows; ++y ) { for( int x = 0; x < n_cols; ++x ) { // m[y,x] لا تستخدم cout << setw( 4 ) << m[y][x]; } cout << '\n'; } } يكون الناتج: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 لا تدعم C++‎ صياغة خاصة لفهرسة المصفوفة متعددة الأبعاد، وإنما تتعامل معها على أنها مصفوفة مكونة من مصفوفات أخرى داخلها، وتستخدم الفهرسة العادية لكل مستوى. وبما أن C++‎ لا توفر دعمًا بشكل افتراضي للمصفوفات ذات الحجم المتغير أو المصفوفات الديناميكية (Dynamic Size Arrays) ما عدا التخصيص الديناميكي (Dynamic Allocation)، فإن المصفوفة الديناميكية تُستخدم غالبًا كصنف (Class). لكن هناك بعض التعقيدات المرتبطة بصياغة الفهرسة m[y][x]‎، إما بكشف الاستخدام ليستحيل عرض منقول المصفوفة مثلًا (Transposed Matrix) أو بإضافة حمل زائد على البرنامج عند تنفيذه بإعادة كائن وكيل (Proxy Object) من عامل الفهرسة operator[OD1][]‎، وعليه قد تكون صياغة الفهرسة مختلفة سواء في الشكل أو في ترتيب الفهارس، كما هو الحال في m(x,y)‎ أو m.at(x,y)‎ أو m.item(x,y)‎. المصفوفات الديناميكية (Dynamically sized raw array) انظر المثال التالي كمثال على مصفوفة ديناميكية، واعلم أن الأفضل عمومًا هو استخدام std::vector: #include <algorithm> // std::sort #include <iostream> using namespace std; auto int_from( istream& in ) -> int { int x; in >> x; return x; } auto main() -> int { cout << "Sorting n integers provided by you.\\n"; cout << "n? "; int const n = int_from( cin ); // n تخصيص مصفوفة عدد عناصرها int* a = new int[n]; for( int i = 1; i <= n; ++i ) { cout << "The #" << i << " number, please: "; a[i-1] = int_from( cin ); } sort( a, a + n ); for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; } cout << '\\n'; delete[] a; } في بعض المُصرِّفات التي تدعم المصفوفات ذات الطول المتغير وفق معيار C99 ‏(variadic length arrays أو VLAs) كإضافة للّغة، يمكن تصريف برنامج يعلن عن مصفوفة T a[n];‎، حيث لا تُحدَّد n حتى وقت التشغيل (run-time). لكنّ C++‎ القياسية لا تدعم تلك المصفوفات، لذا يمكن استخدام تعبير new[]‎ لتخصيص مصفوفة ديناميكية بشكل يدوي، انظر المثال التالي حيث نخصص مصفوفة مكونة من n عنصر: int* a = new int[n]; تستطيع إلغاء تخصيص المصفوفة بعد استخدامها عبر delete[]‎: delete[] a; قيم المصفوفة التي صرّحنا عنها أعلاه غير محددة، ولكن يمكن تهيئة عناصرها عند القيمة صفر عبر إضافة قوسين فارغين () هكذا: new int[n]()‎، وعمومًا فإنه لأي نوع من أنواع البيانات، يهيئ هذا التعبير قيمَ المصفوفة بالقيمة الافتراضية لذلك النوع. لن تكون هذه الشيفرة آمنة للتنفيذ كجزء من دالة في أسفل هرمية الاستدعاء، ذلك أنه قد يحدث تسريب للذاكرة في حالة وجود استثناء قبل تعبير delete[]‎‎، (أو بعد ‎new[]‎)، وحل ذلك يكون بأتمتة عملية التنظيف عبر استخدام المؤشر الذكي std::unique_ptr، رغم أن الأفضل هو استخدام متجه (std::vector) إذ تلك هي وظيفته الأساسية. حجم المصفوفة انظر المثال التالي: #include // size_t, ptrdiff_t //-----------------------------------: using Size = ptrdiff_t; template < class Item, size_t n > constexpr auto n_items(Item( & )[n]) noexcept -> Size { return n; } //----------------------------------- الاستخدام: #include using namespace std; auto main() -> int { int const a[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4}; Size const n = n_items( a ); Size const n = n_items(a); int b[n] = {}; // a مصفوفة لها نفس حجم (void) b; cout <} يمكن الحصول على حجم المصفوفة في لغة C عبر: sizeof(a)‎ أو sizeof(a[0])‎، في حال تمرير مؤشر كوسيط، لكن تكون النتيجة بشكل عام غير دقيقة. أما في C++11، يمكنك الحصول على حجم المصفوفة بالتعبير التالي: std::extent<decltype(MyArray)>::value; مثال: char MyArray[] = { 'X','o','c','e' }; const auto n = std::extent<decltype(MyArray)>::value; std::cout << n << "\n"; // يطبع 4 لم يكن في أي إصدار من C++‎ إلى الإصدار C++17 أي آلية أو مكتبة قياسية مضمَّنة فيها للحصول على أحجام المصفوفات، وإنما نحصل على ذلك بتمرير مرجع يشير للمصفوفة إلى قالب دالة (function template) كما هو موضح أعلاه. معامل حجم القالب (template size parameter) هو size_t، وهو غير متوافق مع النوع المؤشَّر (signed type) للقيمة المعادة من الدّالة Size، وذلك لأجل التوافق مع المُصرّف g++‎ الذي يصر أحيانًاعلى size_t من أجل مطابقة القوالب. كبديل عن ذلك، يمكن استخدام std::size في C++17 والإصدارات اللاحقة لها، إذ هو تابع مخصص للمصفوفات. توسيع المصفوفات الديناميكية باستخدام المتجهات انظر المثال التالي الذي يوضح استخدام متجه std::vector كمصفوفة ديناميكية قابلة للتوسع: #include <algorithm> // std::sort #include <iostream> #include <vector> // std::vector using namespace std; int int_from( std::istream& in ) { int x = 0; in >> x; return x; } int main() { cout << "Sorting integers provided by you.\n"; cout << "You can indicate EOF via F6 in Windows or Ctrl+D in Unix-land.\n"; vector < int > a; // ← الحجم يساوي 0 افتراضيا while( cin ) { cout << "One number, please, or indicate EOF: "; int const x = int_from( cin ); if( !cin.fail() ) { a.push_back( x ); } // التوسيع بحسب الضرورة } sort( a.begin(), a.end() ); int const n = a.size(); for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; } cout << '\n'; } std::vector هو قالب صنف في المكتبة القياسية التي توفر مفهوم المصفوفة ذات الحجم المتغير (الديناميكية)، وتتكفل تلك المكتبة بإدارة الذاكرة، كما أنّ المخزن المؤقت (buffer) متصل (contiguous)، لذا يمكن تمرير مؤشر يشير إلى المخزن المؤقت (على سبيل المثال ‎&v[0]‎ أو v.data()‎) إلى دوال الواجهة البرمجية (API) التي تتطلّب مصفوفةً خام (raw array). يمكن توسيع المتجهة vector في وقت التشغيل عبر التابع push_back الذي يضيف عنصرًا إلى المصفوفة. يُحدَّد تعقيد سلسلة عمليات push_back عددها n، بما في ذلك عمليات النسخ والنقل المستخدمتين في توسيعات المتجهات، في المتوسط من خلال O(n)، ويُنفّذ ذلك داخليًا عبر مضاعفة حجم المخزن المؤقّت للمتجهة vector وسِعتها عند الحاجة إلى حجم أكبر. فمثلًا، إذا كان المخزن المؤقّت يبدأ بالحجم 1، ثم يتضاعف حجمه بشكل متكرر حسب الحاجة، فإنّه في مقابل n=17 عملية استدعاءً للتابع push_back، ستكون هناك 1 + 2 + 4 + 8 + 16 = 31 عملية نسخ، أي أقل من 2 × n = 34. لكن بشكل عام فلا يمكن أن يتجاوز مجموع هذا التسلسل القيمة 2 × n. مقارنةً بمثال المصفوفة الديناميكيّة، فإنّ هذه الشيفرة المستندة إلى المتجهات لا تتطلب من المستخدم أن يحدد (أو يعرف) عدد العناصر مقدّمًا، وإنما تُوسَّع المتجهة حسب الضرورة بدلًا من ذلك. استخدام std::vector في المصفوفة الديناميكية للتخزين بدءًا من الإصدار C++14 لم يعد هناك أي صنف (Class) مخصص للمصفوفات الديناميكية في المكتبة القياسية، وإنما ستجد مثل تلك الأصناف التي تدعم الحجم المتغير في بعض مكتبات الطرف الثالث، بما في ذلك مكتبة Boost Matrix (مكتبة فرعية داخل مكتبة Boost). وإن لم ترد الاعتماد على Boost أو أيّ مكتبة أخرى، فيمكنك كتابة المصفوفات متعددة الأبعاد الديناميكية في ++C على نحو ما في المثال التالي، حيث vector هي متجهة من النوع std::vector. vector<vector<int>> m( 3, vector<int>( 7 ) ); تُنشأ المصفوفة هنا عن طريق نسخ متجه صفِّي (row vector) عددًا من المرات قدره n مرة، حيث n هو عدد الصفوف الذي يساوي 3 في مثالنا أعلاه. تمتاز تلك الطريقة بدعمها لصيغة الفهرسة m[y][x]‎ كما في المصفوفة متعددة الأبعاد ثابتة الحجم، لكنها غير فعّالة من جهة أخرى إذ تتطلّب تخصيص ذاكرة ديناميكيّ لكل صفّ، كما أنّها غير آمنة بسبب إمكانية تغيير حجم الصف عن غير عمد. وعلى أي حال توجد طريقة أخرى أفضل وهي استخدام متجه واحد كتخزين للمصفوفة، وتوجيه شيفرة العميل (x,y) إلى فهرس مناسب في ذلك المتجه. انظر المثال التالي لمصفوفة متغير الحجم (ديناميكية) تستخدم std::vector للتخزين: //--------------------------------------------- الألية: #include // std::copy #include // assert #include // std::initializer_list #include // std::vector #include // ptrdiff_t namespace my { using Size = ptrdiff_t; using std::initializer_list; using std::vector; template <class Item> class Matrix { private: vector items_; Size n_cols_; auto index_for(Size const x, Size const y) const -> Size { return y * n_cols_ + x; } public: auto n_rows() const -> Size { return items_.size() / n_cols_; } auto n_cols() const -> Size { return n_cols_; } auto item(Size const x, Size const y) -> Item & { return items_[index_for(x, y)]; } auto item(Size const x, Size const y) const -> Item const & { return items_[index_for(x, y)]; } Matrix() : n_cols_(0) {} Matrix(Size const n_cols, Size const n_rows) : items_(n_cols * n_rows), n_cols_(n_cols) { } Matrix(initializer_list<initializer_list> const &values) : items_(), n_cols_(values.size() == 0 ? 0 : values.begin()->size()) { for (auto const &row : values) { assert(Size(row.size()) == n_cols_); items_.insert(items_.end(), row.begin(), row.end()); } } }; } // namespace my //--------------------------------------------- الاستخدام: using my::Matrix; auto some_matrix() -> Matrix { return { {1, 2, 3, 4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14}, {15, 16, 17, 18, 19, 20, 21}}; } #include #include using namespace std; auto main() -> int { Matrix const m = some_matrix(); assert(m.n_cols() == 7); assert(m.n_rows() == 3); for (int y = 0, y_end = m.n_rows(); y < y_end; ++y) { for (int x = 0, x_end = m.n_cols(); x < x_end; ++x) { cout <← Note : not `m[y][x]`! } cout < } } يكون الخرج: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 الشيفرة أعلاه ليست مناسبة لا توافق معايير بيئات الإنتاج في الشركات، وإنما صُممت لتوضيح المبادئ الأساسية وخدمة احتياجات الطلاب الذي يتعلمون C++‎، فمثلًا يمكن تحديد التحميل الزائد لـ ()operator لتبسيط صيغة الفهرسة. هذا الدرس جزء من سلسلة دروس عن C++‎. ترجمة -بتصرّف- للفصل Chapter 8: Arrays من كتاب C++ Notes for Professionals
    1 نقطة
×
×
  • أضف...