لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 03/23/15 في كل الموقع
-
النمو السكاني المُطّرد والبطالة المُتنامية الناجمة لاسيما في أوساط الشباب أظهرت مُعاناة حقيقية في دول كثيرة من العالم، وما يجدر ذكره بأن البطالة المُطلقة امتدّت لتشمل أصحاب الشهادات العُليا ولم تقتصر على متوسطي التعليم أو طبقة الأُميين، هذا عدا عن نمو واضح في فئة محدودي الدخل كتحصيل حاصل للتضخم. كُلها أسباب حقيقيّة دفعت الحكومات إلى تشجيع الأعمال الحُرة سواء أكان بشكلها العائلي (الأعمال أو المشاريع العائليّة) أو كانت مُوجّهة لباقي أفراد المُجتمع (أعمال الأفراد المُستقلين أو مجموعات الأفراد المُستقلين). وكنتيجة لذلك نمت خلال العقد المُنصرم مفاهيم جديدة أصبحت تتردد على مسامعنا كالـ (مُستقل freelancer – الرائد أو المُبادر entrepreneur والذي يختلف بطريقته عن العامل الحر .. ومفاهيم أخرى). ما هو العمل الحرّ ومن هو المُستقل العمل الحر هو مُصطلح يُطلق على الأعمال التي تُدار من طرف أشخاص يعملون لحساباتهم الشخصيّة والذين أطلقنا عليهم مفهوم المُستقلين "freelancers". الجدير بالذكر أن العمل الحرّ قديم بقدم البشرية وإن اختلفت مُسمياته وتطورت أدواته وقنواته (قد يكون العامل الحر مُزارعًا – مُحاميًا – راعي أغنام - روائيًّا .... الخ). العمل الحرّ قد يكون مُعتمدًا على المادة (رأس المال) كأن يقوم طبيب مُتخصص بترك وظيفته في مُستشفى وافتتاح عيادة خاصة به. وقد يكون مُعتمدًا على المهارات (كمهارات التصميم والبرمجة والكتابة ... الخ). والاعتماد على المهارة مُرتبطة بشكل أكبر في "العمل الحرّ". بإمكاننا تقسيم العمل الحرّ إلى: عمل مُستقل كامل: أي اعتماد الفرد على العمل الحرّ كعمل أساسي مُطلق. عمل مُستقل بشكل جزئي: أي اعتماد الفرد على العمل الحرّ كعمل ثانوي "من يعمل بشكل إضافي إلى جانب وظيفته الصباحية". سنتناول معكم في سلسلة من المقالات جميع المبادئ والإرشادات التي يحتاجها الفرد للتحوّل إلى مُستقل كامل أو مُستقل بشكل جزئي، مُرتكزين على العمل الحرّ بشكله الافتراضي (باستخدام شبكة الإنترنت) بحيث سننتقل معكم خطوة بخطوة ابتداءً من الانطلاق وتأسيس العمل الحرّ، مُرورًا بآليات توجيه العروض والترويج وإدارة العمليات والوقت، إضافة إلى التطرق لأبرز المشاكل التي قد تعترض العمل الحرّ مع إيضاح الحلول. إذن .. إن كُنت عاطلًا عن العمل، أو كُنت تبحث عن تنمية لمواردك وتحسين وضعك المعيشي بعمل إضافي إلى جانب وظيفتك فهذه السلسلة موجهة لك بشكل خاص. سنستخدم في هذه السلسلة مُصطلحي "العمل الحر" ، "العمل المُستقل" للدّلالة على نفس المفهوم (freelancing) وسنشير إلى الـ freelancer بمُصطلحي "مُستقل" أو "العامل الحر". أسّس عملك المُستقل الآن "عجلة الحياة مُستمرة والأمان فكرة خُرافية غير موجودة في الواقع، وعلى الإنسان الفطن أن يسعى بعد التّوكّل على الله إلى الاستمرار في طلب الرزق وتأمين الحياة الكريمة له ولعائلته ومُحيطه" كلمات لطالما سمعناها من أشخاص حكماء، عصاميين وناجحين كانوا على يقين بإمكانياتهم وامتلكوا الشجاعة لاتخاذ قرارهم بالاستقلال والانطلاق بأعمالهم. أبرز الميزات التي يجب أن تدفعك الآن للعمل المُستقل باستخدام الإنترنت: 1- الإدارة الذاتية: تميل النفس البشرية بطبيعتها إلى القيادة والرغبة في امتلاك اتخاذ القرار، لذلك من الطبيعي أن تجد أفراد كُثرًا لا يتآلفون مع فكرة العمل الوظيفي رغم أنهم مُنضبطين ومُنظمين. 2- مصاريف تشغيل مُنخفضة وتكاد تكون معدومة. 3- لا مكان – لا زمان: يتميز هذا النوع من الأعمال بمرونة عالية بحيث يُمكن مُتابعة العمل في أي مكان وفي أي زمان من خلال التواصل مع الزبائن باستخدام شبكة الإنترنت. 4- سوق عالمي مفتوح وطلب في ازدياد مُطّرد. 5- العمل في أمور مُحببة. (مُعظم العاملين المُستقلين بدؤوا أعمالهم عبر استغلال هواياتهم المُحبّبة). 6- زيادة الدخل ورفع درجة الأمان المعيشي. "العمل الحرّ لا يرتبط بعدم الانتظام، فنجاحك كمُستقل على المدى الطويل يرتبط بكونك مُنظّمًا، مُلتزمًا، مُنضبطًا وخبيرًا بمجال عملك" نحث الأفراد في مُجتمعنا العربي الفتي إلى التفكير جديًّا بمواكبة هذه التّوجه لما له من منفعة عليهم وعلى أسرهم، مُجتمعاتهم، وأوطانهم. أما عن الأدوات، والقنوات، وطرق العمل الحرّ وجميع التفاصيل الأخرى فهذه الأمور ستعرف عنها الكثير من خلال هذه السّلسلة. استغل خبراتك ومواهبك واستفد إذا ما استثنينا أصحاب الإمكانيات العقلية المُنخفضة وفئة الأطفال، فإنه لا يُمكن تصديق فكرة وجود شخص على سطح البسيطة مُنعدم تمامًا من أي موهبة، أو مرّ خلال حياته سواء إن صغرت أو عظُمت بتجارب مُختلفة نمّت لديه خبرات فوّقته على أشخاص آخرين هُم أيضًا متفوقين عليه بخبرات أخرى. أساس العمل الحرّ يُشرق من هُنا بعض الأشخاص بارعون في فئات مُعينة من الفنون (كالفن المعماري – الرسم – التصميم - التصوير ... وغيرها)، والبعض منهم حباهم الله بحب الرياضيات والمنطق فتجدهم يستمتعون في كتابة الأسطر البرمجية، وبعضهم مر بتجارب أكسبته خبرات عملية في أمور حياتية مُختلفة (كالترجمة – تقديم النصائح والاستشارات المُختلفة ... وغيرها)، وقد تجد بعضهم الآخر بارعًا في إسعاد الآخرين،نعم إسعاد الآخرين هو عمل مُربح ويبحث عنه أشخاص كُثر. عليك منذ الآن بالتفكير في أمور تُحبها وتُجيد فعلها على حد سواء، دوّنها ورتبها ثم فكّر بشكل منطقي في كيفية استفادتك منها، ولا تغفل أبداً التخصص بقدر المُستطاع. أمثلة "رائد" موظف في أحد البنوك بدوام صباحي. يمتلك رائد إلى جانب خبرته المصرفية قدرة عالية في تدوين القيود وإعداد ميزان المُراجعة والقوائم المالية وأمور مُحاسبية أخرى إلّا أنه يعيش في مدينة صغيرة مُتخمة بالسكان والحصول على وظيفة إضافية مسائية أشبه بالمُعجزة. توجّه "رائد" إلى حاسوبه المنزلي المُرتبط بشبكة إنترنت وأنشأ حسابًا في إحدى منصات العمل المُتخصصة للمُستقلين وعرض خدماته على جمهور واسع وبدأ في مساء كل يوم بمُتابعة الطلبات الواردة وتنفيذها بجوار مدفئته وكوب القهوة خاصته. أما "أحمد" صاحب الإجازة الجامعية في التاريخ، فهو عاطل عن العمل تمامًا، ولم يترك أبدًا أي باب إلّا وقام بطرقه في سبيل إيجاد وظيفة، لكنه بالرغم من ذلك لم يحصل على مُراده في بلد عربي مليء بالكفاءات فقير بالوظائف. ذات يوم أيقن "أحمد" بأن عليه التفكير بشكل أوسع خارج نطاق بلده فقرر الاستفادة من إمكانياته الجيّدة في الكتابة الإبداعية والتنقيح اللغوي ليعرض خدماته على جمهور واسع في بلدان مُختلفة حول العالم باستخدامه لشبكة الإنترنت. صديقنا المُفترض "أحمد" وبعد أيام وأشهر قلة من إثبات نفسه ككاتب مُبدع على شبكة الإنترنت أصبح يبحث عن أوقات فراغ بسيطة كنوع من الإجازة. على جانب آخر من العالم هُناك ربة المنزل "هبة" التي تعيش في مدينة سياحية ساحرة، والتي قررت تزويد الأشخاص المُهتمين بالسياحة بإرشادات سياحية حول مدينتها بحيث سهّلت عليهم عناء البحث واستفادت من نصائحها ماديًا. وهُناك "فاطمة" كاتبة الروايات الناشئة التي لا تمتلك مقومات مالية لطباعة ونشر رواياتها، والتي قررت استغلال إحدى مواقع العمل الحُر بجعله وسيط لبيع رواياتها بعد أن حولتها إلى نسخ إلكترونية، فساهمت تلك الخطوة ببيعها لمئات النُسخ وتحقيقها لشهرة واسعة. أيضًا هُناك عبد العزيز الذي رزقه الله عز وجل بصوتٍ رخيم وموهبة في الإلقاء فقرر الاستفادة من ذلك عبر تقديم خدمات التسجيلات الصوتية والإلقاء حسب الطلب. منصات العمل للمُستقلين انتشرت على شبكة الإنترنت العديد من منصات العمل الخاصة بالمُستقلين والتي تحمل بمُعظمها الصفة العالمية، ولكل موقع منها طرق عمل وتصنيفات وإمكانيات خاصة، إلّا أنها اتفقت جميعها بعمل دور الوسيط بين أصحاب المواهب والخبرات (المُستقلين)، وأصحاب الأعمال (طالبي العمل) الذين ليسوا بالضرورة أن يكونوا مُنعدمين من تلك الخبرات إنما قد يُحاولون تركيز استغلال أوقات عملهم باستئجارهم لمُستقلين جاهزين لأداء مهام مُعينة مُقابل عوائد مالية. التالي باقة بأهم المواقع المُتخصصة بالعمل الحرّ عربيًا وعالميًا: أولاً: أشهر المواقع العربية للمُستقلين 1- مُستقل منصة عربية تعمل كصلة وصل بين أصحاب المشاريع والشركات من جهة والمُستقلين المُحترفين من جهة أخرى، بحيث يستطيع المُستقل بناء ملف تعريفي خاص به على الموقع يحوي نُبذة عنه وعن مهاراته إضافة إلى معرض خاص بأعماله. الجدير بالذكر أن الموقع أُطلق في أواخر العام 2014 وحاز خلال وقت قصير على شهرة واسعة من خلال تجسيده لخدمة حقيقية عبر أسلوب عرضي سلس واضح. 2- خمسات سوق عربي لبيع وشراء الخدمات المُصغرة في شتى المجالات، يستفيد منه آلاف الشباب العربي عبر تقديمهم لخدمات ومُنتجات مُصغرة بأسعار تبدأ بـ 5 دولار أمريكي فقط وطرحها على شريحة واسعة من الزبائن المُستفيدين من تلك الخدمات ذات الأسعار الاقتصادية. يتميز الموقع بإقبال مُرتفع ومصداقية عالية ودعم فني مُمتاز. 4- بيكاليا متجر خاص للمُصممين، يُمكّنهم من بيع تصاميمهم وأعمالهم الفنية للجمهور العربي عبر إضافة تلك الأعمال وشرحها بشكل واضح لزبائن المتجر مع توفير المُعاينة الحية بحسب الطلب. ثانياً: أشهر المواقع العالمية للمُستقلين: 1- Freelancer من أشهر مواقع العمل الحُر على مستوى العالم وأكثرها إقبالًا. يوفّر الموقع منصة سهلة التعامل تُمكّن أصحاب الأعمال والشركات من استئجار مُستقلين لتنفيذ مهام مُختلفة في التصميم والهندسة والعلوم والتسويق والخدمات القانونية وغيرها. 2- Odesk يلعب الموقع دور الوسيط بين أصحاب الأعمال والمُستقلين، بحيث يقوم صاحب العمل بعرض طلبه ويتقدم إليه طالبو العمل ممن يرون في أنفسهم الكفاءة، ويقوم صاحب العمل باختيار أحد المُتقدمين (أو أكثر من مُتقدم من المُستقلين). الموقع ضخم جدًا ولا يُستهان به على الإطلاق ولديه طرق وخوارزميات مُختلفة لإبراز أفضل الخبرات، لذلك وبالمُختصر كُلما كان المُستقل مُتخصّصًا أكثر ومُبدعًا أكثر في مجاله كُلما زادت مبيعاته وأرباحه. 3- Elance يُعدّ الموقع الأفضل في مجاله، وبإمكان المُستقل إنشاء حساب وإضافة بياناته وتحديد مجال العمل ضمن خيارات كثيرة مُتوفرة وأيضًا تحديد السعر وطريقة العمل. أكثر ما يُميّز الموقع احتواؤه على عدد كبير جدًا من المشاريع المطروحة، ووجود نسبة كبيرة من المشاريع ذات الميزانيات العالية، بالإضافة إلى موثوقيته العالية واحتوائه على خصائص وميزات مُمتازة. 4- Design Crowd منصة مثالية لعمل المُصممين المُحترفين في مجالات التصميم المُتنوعة (شعارات – أغلفة – بطاقات أعمال – تصميم مواقع ... الخ)، ما يُميّز الموقع بأن مُعظم مُرتاديه من أصحاب الأعمال يحترمون العمل التصميمي ويقدرون ثمنه، لذلك ستجد بأن أسعار الأعمال به جيّدة مُقارنة بباقي المواقع المُشابهة. 5- People Per Hour كما هو واضح من اسمه فإن الموقع يقدّم منصة تُمكّن المُستقلين من العمل بشكل حُر، بحيث بإمكان المُستقل إنشاء ملفه الشخصي بسهولة من خلال الموقع والبحث عن مشاريع تُناسب خبراته. يعتمد الموقع بشكل كبير على التقييم لذا فالعمل الجيّد المصحوب بتقييم إيجابي سيجلب بالتأكيد أعمال أخرى. 6- 99designs المكان الأمثل لعمل المُصممين المُستقلين، حيث يُوفر الموقع منصة غاية في الجودة تُمكّن المُصممين من عرض أعمالهم والتقديم للمشاريع. يتميّز الموقع بإقبال عالي جدًا من طرف أصحاب المشاريع ويُعدّ الأفضل في اختصاصه. 7- Guru هو الآخر موقع رائع وستجد عليه كمُستقل عدد كبير من فرص العمل في مجالات مُختلفة، كُل ما عليك فعله هو بناء ملف تعريفي مُتكامل والبحث عن أفضل فُرص. 8- Sellfy أفضل مكان للمُستقلين ممن لديكم مُنتجات رقمية (كتب إلكترونية – خطوط – قوالب – تسجيلات صوتية ..الخ) ويريدون بيع نسخ منها إلى أكبر عدد مُمكن من المُهتمين. تتميّز المنصة بسهولة التعامل كما يتميّز الموقع بانخفاض نسبة عمولته مُقارنة بباقي المواقع ذات نفس المجال حيث يتقاضى الموقع 5% فقط لقاء كل عملية بيع مُنتج رقمي تتم عبره. 9- Themeforest منصة مُوجّهة للمُصممين والمُبرمجين وهي الأفضل على مستوى العالم بمجالها. تُعدّ (ثيم فورست – themeforest) أفضل مكان لبيع القوالب والتصاميم والإضافات التصميمية والبرمجية، يتقاضى الموقع عمولة مُرتفعة نسبيًا كما أن لديه سياسة صارمة جدًا عند قبول أي ملفات أو قوالب للبيع لكن رغم ذلك فهو يُوفر شريحة ضخمة جدًا من المُشترين وهذا ما يُميزه، لذا يتوجّب على أي عامل مُستقل عند انعقاد نيته لصناعة مُنتج وبيعه من خلال المنصة أن يطّلع أولًا على تفاصيل وشروط الموقع بالكامل وأن يتصفح الأعمال الشبيهة بعمله والمقبولة على الموقع ثم يُعطي كل الاهتمام لإنجاز عمله على المستوى المطلوب، وعندها بالتأكيد سيكون قد حاك لنفسه بداية قصة نجاح مُبهرة! 10- Gumroad منصة عرض موجهة للمُستقلين تهدف إلى مُساعدتهم في بيع مُنتجاتهم الرقمية، فهي أشبه بالمتجر الذي بإمكانك أن تعرض وتبيع به مُنتجاتك الرقمية (كتب إلكترونية – برامج – شروحات – مقاطع فيديو ... الخ) بكل بساطة ودون أي تعقيدات. قد يخطر ببالك حاليًا السؤال التالي: لماذا لا أفتح متجري الخاص وأبيع أعمالي إلى زبائني مُباشرة وبالتالي أوفر على نفسي رسوم أو نسبة أرباح مواقع (منصات العمل الحُر)؟ السؤال مشروع، إنما ما رأيك بالوقوف أولًا على الميزات التي توفرها منصات العمل الحر: 1- توفير عناء ووقت وكلفة إنشاء متجر إلكتروني، فمنصّات العمل الحُر جاهزة وتحتاج منك فقط إدخال بياناتك وتأكيدها وبناء معرض أعمالك بطريقة عالية الجودة. 2- توفير وسائل الدفع المُختلفة. 3- توفير قاعدة عظيمة من المُتابعين والمُطّلعين على الخدمات، فمواقع العمل الحُر تُسوّق وتأتي بالزبائن لكامل شبكتها بالنيابة عنك. 4- توفير عامل الثقة للزبائن (أصحاب الأعمال) عبر وجود طرف ثالث ضامن لحقوقهم والمُمثّل بمنصة العمل الحُر، وهو أمر أساسي ومُحفّز لهم على الشراء. بينما إن كانت منصة الشراء خاصة بك وحدك وأنت صاحب القرار بها، فبالتأكيد مسألة الثقة بينك وبين زبائنك ستتطلب وقت طويل جدًا وهذا أمر طبيعي في المُعاملات المالية. بالتوقف والتفكير قليلًا في الميزات السابقة ستجد بأن رسوم (أو نسبة الأرباح المُقتطعة) هي بسيطة مُقابل الخدمة التي تتلقاها. تلميح: إن قيام منصات العمل الحُر بالترويج عن كامل شبكتها لا يعني أبدًا ألّا تسعى في التسويق والترويج لحساباتك في تلك المنصات عبر أساليب مُختلفة سوف نتحدث عنها في وقت لاحق. في المقالات القادمة سنناقش بالتتابع الخطوات العملية للانطلاق وآليات العمل والمُتابعة مع الوقوف على أهم المشاكل التي قد تعترض عملك كمُستقل والحلول لها إضافة إلى أمور أخرى ستمكنك بالنهاية من العمل بثبات لتحقيق النجاح.1 نقطة
-
ما هو AngularJS؟AngularJS هو إطار عمل JavaScript لطرف العميل يتبع بنية Model-View-Controller/Model-View-View-Model، ويعتبر اليوم مُهمًا لبناء تطبيقات ويب وحيدة الصفحة (SAP) أو حتى المواقع العادية. يُعتبر Angular JS قفزة كبيرة نحو مستقبل HTML وما يجلبه الإصدار الخامس منها (مع التطورات على صعيد JavaScript بالطبع!)، ويبعث الحياة من جديد في تعاملنا مع الويب الحديث. هذا المقال جولة شاملة في Angular JS مستخلصة من تجاربي ونصائح وممارسات تعلمتها خلال استخدامي. المُصطلحاتليس عليك أن تبذل جهداً كبيراً لتعلم Angular، وأهم ما يجب معرفته هو معاني المُصطلحات وتبني نمط MVC، وMVC هو اختصار لـModel-View-Controller، أي نموذج-طريقة عرض-مُتحكِّم. فيما يلي بعض المصطلحات والواجهات البرمجية الأساسية التي تزوّدنا بها Angular. MVCربما سمعت بهذا الاختصار من قبل، وهو مستخدم في لغات برمجة عديدة كوسيلة لبناء هيكل التطبيقات أو البرامج. وهاك تلخيص سريع لمعناه: النموذج (Model): بنية البيانات التي تقوم عليها أجزاء التطبيقات، غالبًا ما تُمثل بصيغة JSON. يفضل أن تكون لديك معرفة مسبقة بـJSON قبل تعلم Angular، لأنها ضرورية للتواصل بين الخادوم وطريقة العرض (سنأتي على شرحها في النقطة التالية). على سبيل المثال، لنفترض أنه لدينا مجموعة من المستخدمين، يمكن تمثيل بيانات تعريفهم كما يلي:{ "users" : [{ "name": "أحمد", "id": "82047392" },{ "name": "سامر", "id": "65198013" }] }عادة ما تُجلب هذه المعلومات من خادوم بطلب XMLHttpRequest، ويقابله في jQuery الإجراء $.ajax، وفي Angular الكائن $http. وقد تكون هذه المعلومات مكتوبة ضمن النص البرمجي أثناء تفسير الصفحة (من قاعدة بيانات أو مخزن بيانات). بعد ذلك يكون بإمكانك تعديل هذه المعلومات وإعادة إرسالها. طريقة العرض (View): وهو أمر سهل التفسير، فهي ببساطة المُخرج النهائي أو صفحة HTML التي تعرض البيانات (النموذج) على المستخدم مثلاً. باستخدام إطار عمل MVC، تُجلب البيانات من النموذج وتُعرض المعلومات المناسبة في صفحة HTML.المُتحكِّم (Controller): وله من اسمه نصيب، فهو يتحكم بالأشياء، ولكن أية أشياء؟ البيانات. المُتحكمات هي الطريقة التي تصل من خلالها بين الخادوم وطريقة العرض، فتسمح بتحديث البيانات سريعًا من خلال التواصل مع كلا الخادوم والعميل.إعداد مشروع Angular JS (الأساسيات)يجب أولاً تهيئة الأساسيات التي يقوم عليها مشروعنا. يجب أن نبدأ بتطبيق (ng-app) الذي يُعرِّف التطبيق (وng هي بادئة تعني Angular وتسبق عادة كل مكونات Angular JS)، ثم متحكم (Controller) ليتواصل مع طريقة العرض، ثم ربط DOM ولا ننسى تضمين Angular بالطبع. إليك الأساسيات: نص HTML مع تصريحات ng-*:<div ng-app="myApp"> <div ng-controller="MainCtrl"> <!-- محتويات المتحكم --> </div> </div>وحدة Angular مع متحكم:var myApp = angular.module('myApp', []); myApp.controller('MainCtrl', ['$scope', function ($scope) { // أوامر المتحكم }]);قبل أن نستبق الأمور، نحتاج لإنشاء وحدة Angular (أو Angular module)، التي ستتضمن كل النص البرمجي المُتعلق بالمشروع. هناك أكثر من طريقة للتصريح عن الوحدات، إحداها سَلسَلة كل النص البرمجي معًا (لا أفضل هذه الطريقة): angular.module('myApp', []) .controller('MainCtrl', ['$scope', function ($scope) {...}]) .controller('NavCtrl', ['$scope', function ($scope) {...}]) .controller('UserCtrl', ['$scope', function ($scope) {...}]);ولكن الطريقة التي أفضلها، والتي أثبتت أنها الأفضل لكل مشاريع Angular التي صمّمتها هي تعريف الوحدة العامة بشكل منفصل. الطريقة التي تعتمد على تسلسل التصريحات قد تجعلك تنسى إغلاق بعض الأقواس وتجعل قراءة النص البرمجي وتصحيحه أكثر تعقيدًا. لذا أُفضّل هذا الأسلوب: var myApp = angular.module('myApp', []); myApp.controller('MainCtrl', ['$scope', function ($scope) {...}]); myApp.controller('NavCtrl', ['$scope', function ($scope) {...}]); myApp.controller('UserCtrl', ['$scope', function ($scope) {...}]);بهذه الطريقة أُقسّم النص البرمجي على عدة ملفات، وفي كل ملف أربط مكوّناً من المكونات مع فضاء الأسماء myApp فيصبح تلقائيًا جزءًا من تطبيقي. نعم، الأمر كما فهمت، أفضل أن أنشئ ملفًا مستقلًا لكل متحكم ومُرشِد (directive) ومعمل (factory) وأي شيء آخر (ستشكرني على هذا). فيما بعد يمكنك دمجها معًا وتقليصها لتصبح ملفًا واحدًا (مستخدمًا مُدير مهام مثل Grunt أو Gulp) فتدفعَه إلى DOM. المُتحكّمات (Controllers)أصبحت تعرف الآن مفهوم MVC وتعلمت طريقة إعداد مشروع جديد، فلنطّلع الآن على الكيفية التي يُطبِّق فيها Angular JS العمل بالمتحكّمات. بناء على المثال السابق، بإمكاننا الآن أن نخطو خطوة بسيطة نحو عرض بعض البيانات ضمن طريقة العرض مستخدمين مُتحكّمًا. يستخدم Angular تركيب " handlebars" لقولبة HTML. ببساطة يعني هذا أنه بإمكان المتحكمات أن تعرض البيانات في صفحة HTML بأن تستبدل كل عبارة فيها مكتوبة ضمن الأقواس المزدوجة هكذا: {{ data }} قيمة يُعيّنها المُتحكم. في الحالة المثالية يجب أن لا تحوي صفحة HTML نصًا حقيقيًا أو قيمًا مُدرجة مسبقًا، ويجب أن تترك هذه المهمة لمتحكمات Angular. فيما يلي مثال يُبيّن كيف يمكن عرض نص أو سلسلة حروف String بسيطة ضمن الصفحة: <div ng-app="myApp"> <div ng-controller="MainCtrl"> {{ text }} </div> </div>في ملف JavaScript: var myApp = angular.module('myApp', []); myApp.controller('MainCtrl', ['$scope', function ($scope) { $scope.text = 'مرحباً بمعجبي Angular!'; }]);والناتج النهائي: رابط المثال أهم مفهوم هنا هو مفهوم النطاق ($scope) والذي ستربطه بكل الوظائف ضمن متُحكّم مُعيّن. يُشير $scope إلى العُنصر أو المنطقة الحالية في DOM (فهو لا يُساوي this ضمن النص البرمجي) وبهذا يخلق نطاقًا يُحيط بكل البيانات والوظائف ضمن العناصر (DOM elements)، ويعزلها عن العناصر الأخرى، فيبدو وكأنه ينقل مجالات JavaScript العامة/الخاصة إلى DOM، وهذا شيء رائع. قد يبدو مفهوم النطاق مخيفًا للوهلة الأولى، لكنه طريقك الواصل بين الخادوم (أو حتى البيانات المحلية) من جهة وDOM من الجهة الأخرى. يعطيك هذا المثال فكرة عن الطريقة التي "تُدفع" بها البيانات إلى DOM. لنٌلقِ نظرة على بيانات حقيقية نفترض أننا جلبناها من خادوم لنعرض تفاصيل تسجيل دخول المستخدم، سنكتفي في هذه المرحلة باستخدام بيانات جاهزة، وسنتعلم كيفية جلبها من الخادوم على هيئة JSON لاحقًا. أولاً سنكتب شفرة JavaScript: var myApp = angular.module('myApp', []); myApp.controller('UserCtrl', ['$scope', function ($scope) { // لنجعل معلومات المستخدم ضمن عنصر فرعي $scope.user = {}; $scope.user.details = { "username": "Todd Motto", "id": "89101112" }; }]);ثم ننتقل إلى DOM لعرض هذه البيانات <div ng-app="myApp"> <div ng-controller="UserCtrl"> <p class="username">Welcome, {{ user.details.username }}</p> <p class="id">User ID: {{ user.details.id }}</p> </div> </div>النتيجة من المهمّ أن تتذكر أن المتحكمات تستخدم فقط للبيانات ولإنشاء وظائف تتواصل مع الخادوم وتجلب أو ترسل بيانات JSON. لا تستخدم المتحكمات لمعالجة DOM (كأن تنقل عنصرًا ضمن الصفحة أو تخفيه أو تظهره...)، فمعالجة DOM مهمة المُرشِدات (directives)، وهي ما سنشرحه لاحقًا، المهم أن تتذكر أن موضع jQuery وغيرها من المكتبات التي تتعامل مع DOM ليس ضمن المتحكّمات. تنويه: خلال اطلاعك على وثائق Angular الرسمية، ستلاحظ أن الأمثلة المقدمة تعتمد الأسلوب التالي لإنشاء المتحكمات: var myApp = angular.module('myApp', []); function MainCtrl ($scope) { //... };لا تفعل ذلك. هذا سيجعل كل الوظائف المُصرّحة تابعةً للنطاق العامّ (global scope) ولا يربطها بشكل جيد مع التطبيق. هذا يعني كذلك أن عمليات التقليص للنص البرمجي والتجارب ستكون أكثر صعوبة. لا تلوّث فضاء الأسماء العام، بل اجعل المتحكمات ضمن التطبيق. المُرشِدات (Directives)الُمرشد في أبسط صوره هو نص HTML مٌقولَب، يفضل أن يكون استخدامه متكررًا ضمن التطبيق. توفر المرشدات طريقة سهلة لإدخال أجزاء DOM ضمن التطبيق دون عناء. تعلم استخدام المرشدات ليس أمرًا سهلًا على الإطلاق، وإتقانها يتطلب جهدًا، ولكن الفقرات التالية ستضعك على الطريق الصحيح. إذن، ما فائدة المُرشدات؟ إنها مفيدة في عدة أمور، منها إنشاء عناصر DOM، مثل علامات التبويب (tabs) وقوائم التصفح - ففائدتها تعتمد على ما يفعله تطبيقك في الواجهة. لتسهيل الشرح، سأقول ببساطة: إن كنت استعملت ng-show وng-hide من قبل، فقد استعملت المرشدات (حتى وإن كان هذان لا يُدرجان أية عناصر DOM). على سبيل التمرين، سنُنشئ نوعًا خاصًّا من الأزرار ونُسميه customButton، يُدرج هذا العنصر بعض العناصر الفرعية التي لا نريد كتابتها في كل مرة. تتنوع طرق التصريح عن المرشدات في DOM، وهي مبينة في النص البرمجي التالي: <!-- 1: تصريح عن مُرشد كخاصّة (attribute) --> <a custom-button>انقرني</a> <!-- 2: كعنصر مخصص (custom elements) --> <custom-button>انقرني</custom-button> <!-- 3: كصنف (class) (للتوافق مع النسخ القديمة من IE) --> <a class="custom-button">انقرني</a> <!-- 4: كتعليق (comment) (ليس ملائماً لهذا التمرين) --> <!-- directive: custom-button --> أفضّل استخدام المرشدات كخواصّ (attributes)، أما العناصر المُخصصة (custom elements) فقادمة في النسخ المستقبلية من HTML باسم Web Components، يوفر Angular ما يشبهها، ولكنها قد تنطوي على بعض العيوب والعلل في المتصفحات القديمة. الآن نعرف كيف نصرح عن المرشدات ضمن الصفحة، سننتقل إلى إنشائها ضمن JavaScript. لاحظ أنني سأربطه مع فضاء الأسماء العام myApp؛ في صيغته الأبسط يُكتب المرشد كما يلي: myApp.directive('customButton', function () { return { link: function (scope, element, attrs) { // هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه } }; });عرّفنا المرشد باستخدام الدالة .directive()، ومررنا إليها اسم المرشد 'customButton'. عندما تكتب حرفًا كبيرًا بالإنجليزية في اسم المُرشد، فإنه ينبغي استخدام اسم المرشد ضمن DOM بصيغته التي يُفصل بها باستخدام الشرطة (-) بين الحروف الكبيرة (كما في المثال السابق: استخدمنا 'customElement' في JavaScript و"custom-button" في HTML). يُرجع المُرشد كائنًا (Object) له عدد من الخصائص. أهم ما يجب تعلّمه منها: restrict وreplace وtransclude وtemplate وtemplateUrl وأخيرًا link. لنُضف بعضها إلى شفرتنا البرمجية: myApp.directive('customButton', function () { return { restrict: 'A', replace: true, transclude: true, template: '<a href="" class="myawesomebutton" ng-transclude>' + '<i class="icon-ok-sign"></i>' + '</a>', link: function (scope, element, attrs) { // هنا اكتب التعليمات التي تعالج DOM أو تتعامل مع أحداثه } }; });النتيجة تأكد من فحص العنصر (من الأمر Inspect element في المُتصفح) لرؤية العناصر الجديدة التي أُدخلت في الصفحة. اعلم أن الرمز لم يظهر ضمن العنصر الجديد، ببساطة لأنني لم أُضمّن Font Awesome ضمن المشروع، ولكن يمكنك فهم كيف تعمل المرشدات. لنتعرف الآن ما تعنيه كل واحدة من خصائص المرشد السابقة الذكر: الخاصية restrict: تُقيّد هذه الخاصة كيفية استخدام المُرشد، كيف نريد أن نستخدمه؟ إن كنت تبني مشروعًا يتطلب دعم النسخ القديمة من IE، فعليك استخدامه كخاصّة (attribute) أو صنف (class). القيمة 'A' تعني حصر استخدام المرشد بالخواص (attributes) فقط. 'E' تعني Element و'C' صنف و'M' تعليق. القيمة الافتراضية هي 'EA' (أي عنصر وخاصة). الخاصية replace: تعني استبدال HTML العنصر المصرّح عن المُرشد ضمن الصفحة بالقالب (template) الذي يُحدد في الخاصة template (مشروحة أدناه). الخاصةtransclude: تسمح بنسخ المحتوى الأصلي للعنصر المُصرّح عن المُرشد في الصفحة ودمجه ضمن المرشد (عند التنفيذ، ستلاحظ أن العبارة "انقرني" انتقلت إلى المُرشد). الخاصية template: قالب (كذلك المستخدم في المثال) يُدخل إلى الصفحة. يفضّل استخدام القوالب الصغيرة فقط. تُعالج القوالب وتبنى من قبل Angular مما يسمح باستخدام صيغة handlebars ضمنها. الخاصة templateUrl: مشابهة للسابقة، ولكنها تُجلب من ملف أو من وسم <script> بدل كتابتها ضمن تعريف المُرشد. كل ما عليك هو تعيين مسار الملف الذي يحوي القالب. يكون هذا الخيار مناسبًا عندما تريد الاحتفاظ بالقوالب خارج النص البرمجي لملفات JavaScript: myApp.directive('customButton', function () { return { templateUrl: 'templates/customButton.html' // directive stuff... });وضمن الملف، نكتب: <!-- inside customButton.html --> <a href="" class="myawesomebutton" ng-transclude> <i class="icon-ok-sign"></i> </a>ملاحظة: لا يخضع اسم الملف إلى أية قاعدة، وليس من الضروري أن يوافق اسمَ المُرشد. عند استخدام الأسلوب السابق، سيحتفظ المتصفح بنسخة مُخبأة (cached) من ملف HTML، وهو أمر رائع، الخيار البديل هو استخدام قالب ضمن وسم <script> وهنا لا تُخبأ نسخة منه في المتصفح: <script type="text/ng-template" id="customButton.html"> <a href="" class="myawesomebutton" ng-transclude> <i class="icon-ok-sign"></i> </a> </script>هنا أخبرنا Angular بأن وسم <script> هذا هو قالب (ng-template) وأعطيناه المُعرف. سيبحث Angular عن القالب أو عن ملف html، فاستخدم ما تراه مناسبًا. شخصيًا، أفضّل إنشاء ملفات html لسهولة تنظيمها ولتحسين الأداء وإبقاء DOM نظيفًا، فقد يستخدم مشروعك مع الوقت عشرات المُرشدات، وترتيبها في ملفات مستقلة يجعل مراجعتها أسهل. الخدمات (Services)كثيرًا ما تثير الخدمات في Angular ارتباك المطورين، ومن خبرتي وأبحاثي، أعتقد أن الخدمات وُضعت كنمط وأسلوب للتصميم أكثر من اختلافها بالوظيفة التي تؤديها. بعد التنقيب في مصدر Angular، وجدت أنها تُعالج وتبنى باستخدام المُجمّع (compiler) ذاته، وكذلك فهي تقدم العديد من الوظائف المشابهة. أنصح باستخدام الخدمات لبناء الكائنات المُتفرِّدة (singletons)، واستخدام المعامل (Factories) لبناء وظائف أكثر تعقيدًا كالكائنات الحرفيّة (Object Literals). فيما يلي مثال لاستخدام خدمة توجد ناتج الضرب لعددين: myApp.service('Math', function () { this.multiply = function (x, y) { return x * y; }; });يمكنك بعد هذا استخدامها ضمن مُتحكم كما يلي: myApp.controller('MainCtrl', ['$scope', function ($scope) { var a = 12; var b = 24; // الناتج: 288 var result = Math.multiply(a, b); }]);نعم بالطبع إيجاد ناتج الضرب سهل ولا يحتاج خدمة، لكننا نستخدمه لإيصال الفكرة فحسب. عندما ننشئ خدمة (أو معملاً) نحتاج إلى إخبار Angular عن متطلبات هذه الخدمة، وهو ما يسمى "حقن المتطلبات Dependency Injection" - إن لم تُصرّح عن المتطلبات فلن يعمل المتحكم المعتمد على الخدمة، وسيحدث خطأ عند التجميع. ربما لاحظت الجزء function ($scope) ضمن التصريح عن المتحكم أعلاه، وهذا هو ببساطة حقن المتطلبات. ستُلاحظ أيضًا [$scope] قبل الجزء function ($scope)، وهو ما سأشرحه لاحقًا. فيما يلي طريقة استخدام حقن المتطلبات لإخبار Angular أنك تحتاج إلى الخدمة التي أنشأتها للتو: // مرر الخدمة Math myApp.controller('MainCtrl', ['$scope', 'Math', function ($scope, Math) { var a = 12; var b = 24; // يُعطي 288 var result = Math.multiply(a, b); }]);المعامل (Factories)إيضاح فكرة المعامل سهل إذا كنت قد استوعبت فكرة الخدمات، بإمكاننا إنشاء كائن حرفي (Object Literal) ضمن المعمل أو عبر طرق أكثر تعقيدًا: function ($http) { return { get: function(url) { return $http.get(url); }, post: function(url) { return $http.post(url); }, }; }]);هنا أنشأنا مُغلفات (wrappers) مخصصة لخدمة $http في Angular المسؤولة عن طلبات XHR. بعد حقن المتطلبات ضمن المتحكم يمكننا استخدام هذا المعمل بسهولة: myApp.controller('MainCtrl', ['$scope', 'Server', function ($scope, Server) { var jsonGet = 'http://myserver/getURL'; var jsonPost = 'http://myserver/postURL'; Server.get(jsonGet); Server.post(jsonPost); }]);إذا أرت طلب التحديثات من الخادوم، بإمكانك إنشاء دالة Server.poll أو إن كنت تستخدم مقبسًا (ٍSocket)، فربما سترغب في إنشاء دالة Server.socket وهكذا... المعامل تسمح لك بتنظيم نصك البرمجي ضمن وحدات يمكن إدراجها ضمن المتحكمات منعًا لتكرار النص البرمجي فيها والحاجة المتكررة لصيانته. المُرشّحاتتستخدم المرشحات مع مصفوفات (arrays) من البيانات وخارج الحلقات (loops). إن احتجت للمرور على عناصر من مصفوفة بيانات والحصول على بعض منها فقط، فأنت في المكان الصحيح، يمكنك أيضًا استخدام المرشحات لتصفية ما يكتبه المستخدم ضمن حقل إدخال <input> مثلًا. هناك عدة طرق لاستخدام المُرشحات: ضمن متحكم أو دالة مُعرفة. فيما يلي الطريقة الأخيرة: myApp.filter('reverse', function () { return function (input, uppercase) { var out = ''; for (var i = 0; i < input.length; i++) { out = input.charAt(i) + out; } if (uppercase) { out = out.toUpperCase(); } return out; } }); // Controller included to supply data myApp.controller('MainCtrl', ['$scope', function ($scope) { $scope.greeting = 'Todd Motto'; }]);وفي HTML: <div ng-app="myApp"> <div ng-controller="MainCtrl"> <p>No filter: {{ greeting }}</p> <p>Reverse: {{ greeting | reverse }}</p> </div> </div>رابط المثال وهنا نستخدم المُرشح ضمن حلقة ng-repeat: <ul> <li ng-repeat="number in myNumbers |filter:oddNumbers">{{ number }}</li> </ul>مثال عن مُرشح ضمن متحكم: myApp.controller('MainCtrl', ['$scope', function ($scope) { $scope.numbers = [10, 25, 35, 45, 60, 80, 100]; $scope.lowerBound = 42; // Does the Filters $scope.greaterThanNum = function (item) { return item > $scope.lowerBound; }; }]);واستخدامه حلقة ng-repeat: <li ng-repeat="number in numbers | filter:greaterThanNum"> {{ number }} </li>رابط المثال كان هذا القسم الأكبر مما تحتاج لمعرفته عن AngularJS وواجهاتها البرمجية، ومع أن ما تعلمناه كافٍ لبناء تطبيق Angular، ولكننا إلى الآن لم نسكتشف أغوراها بعد. ربط البيانات ثنائي الاتجاهعندما سمعت للمرة الأولى عن ربط البيانات ثنائي الاتجاه لم أفهم ما يعنيه. باختصار يمكن القول إنه حلقة متصلة من البيانات المُزامنة: حدّث النموذج (Model) لتُحدَّث طريقة العرض (View)، أو حدّث طريقة العرض ليُحدَّث النموذج (Model). هذا يعني أن البيانات تبقى محدثة دومًا دون عناء. إن ربطت نموذج ng-model مع حقل إدخال <input> وكتبت فيه، فهذا يُنشئ (أو يُحدِّث) نموذجاً في الوقت ذاته. فيما يلي نقوم بإنشاء حقل <input> ونربطه بنموذج نسميه myModel، يمكنني الآن استخدام صياغة handlebars لعكس هذا النموذج وما يطرأ عليه من تحديثات في طريقة العرض في الوقت ذاته: <div ng-app="myApp"> <div ng-controller="MainCtrl"> <input type="text" ng-model="myModel" placeholder="Start typing..." /> <p>My model data: {{ myModel }}</p> </div> </div> myApp.controller('MainCtrl', ['$scope', function ($scope) { // Capture the model data // and/or initialise it with an existing string $scope.myModel = ''; }]); النتيجة طلبات XHR/Ajax/$http وربط JSONنعرف الآن كيف نرسل بيانات بسيطة ضمن المجال ($scope)، ونعرف ما يكفي عن كيفية عمل النماذج وربط البيانات ثنائي الجانب، والآن حان الوقت لمحاكاة طلبات XHR حقيقية للخادوم. ليس هذا ضروريًا لمواقع الويب العادية، لكنه مناسب جدًا لجلب البيانات في تطبيقات الويب. عندما تطور تطبيقك على جهازك المحلي، فغالبًا ما ستستخدم لغة مثل Java أو ASP.NET أو PHP أو غيرها لتشغيل خادوم محلي. وسواء كنا نتصل بقاعدة بيانات محلية أم بخادوم بعيد كواجهة برمجية، فإننا نتبع نفس الخطوات بالضبط. هنا يأتي دور $http، صديقك المخلص من اليوم فصاعدًا. الدالة $http هي مُغلّف wrapper تقدمه Angular للوصول إلى البيانات من الخادوم، وهو سهل الاستخدام للغاية ولا يحتاج لأية خبرة. فيما يلي مثال عن طلب GET لجلب البيانات من الخادوم. الصياغة مشابهة جدًا لصياغة jQuery، وهذا يُسهل الانتقال من الأخيرة إلى Angular: myApp.controller('MainCtrl', ['$scope', '$http', function ($scope, $http) { $http({ method: 'GET', url: '//localhost:9000/someUrl' }); }]);يُعيد Angular إلينا أمرًا يُصطلح على تسميته الوعد (Promise) ، وهو بديل أسهل استخدامًا من الاستدعاءات الراجعة (callbacks). يمكن تركيب الوعود في سلسلة باستخدام النقطة، ويمكننا ربطها مع مستقبلات النجاح والفشل: myApp.controller('MainCtrl', ['$scope', function ($scope) { $http({ method: 'GET', url: '//localhost:9000/someUrl' }) .success(function (data, status, headers, config) { // successful data retrieval }) .error(function (data, status, headers, config) { // something went wrong :( }); }]);سهلة الاستخدام والقراءة. هنا نربط طريقة العرض والخادوم بربط نموذج أو تحديثه. لنفترض أنه لدينا خادومًا مُعدًّا ولنقم بدفع اسم المستخدم إلى طريقة العرض عن طريق طلب AJAX. علينا --لو كنا حريصين على المثالية-- أن نصمم بيانات JSON التي نريدها أولاً. دعونا الآن نُبسط الأمور، ولندع هذا الأمر ليتولاه من يفهم في أمور النهاية الخلفية (backend)، ولكن لنقل أننا تفترض أن نستقبل بيانات مثل هذه: { "user": { "name": "Todd Motto", "id": "80138731" } }هذا يعني أننا سنحصل على كائن Object من الخادوم (سنسميه data، وسترى أنه يُمرر إلى مستقبلات الوعد الذي أنشأناه). علينا الآن أن نربط هذا الكائن بالخاصة data.user، وضمنها لدينا name وid. يمكن ببساطة الوصول إلى هذه القيم باستخدام data.user.name للحصول على "Todd Motto" مثلاً. فيما يلي الشفرة البرمجية (اطلع على التعليقات المضمنة): myApp.controller('UserCtrl', ['$scope', '$http', function ($scope, $http) { // create a user Object $scope.user = {}; // Initiate a model as an empty string $scope.user.username = ''; // نريد أن نرسل طلباً ونحصل على اسم المستخدم $http({ method: 'GET', url: '//localhost:9000/someUrlForGettingUsername' }) .success(function (data, status, headers, config) { // عند نجاح الطلب، نُسنِد الاسم إلى النموذج الذي أنشأناه $scope.user.username = data.user.name; }) .error(function (data, status, headers, config) { // وقع خطأ ما! :( }); }]);الآن ضمن الصفحة يمكننا ببساطة كتابة: <div ng-controller="UserCtrl"> <p>{{ user.username }}</p> </div>هذا سيعرض اسم المستخدم. لننتقل الآن إلى خطوة أبعد بفهم ربط البيانات التصريحي (Declarative data-binding) حيث تصبح الأمور أكثر إثارة. ربط البيانات التصريحيتقوم فلسفة Angular على إنشاء نصوص HTML ديناميكية قادرة على القيام بوظائف بنفسها لم نكن نتوقع أنها ممكنة ضمن المتصفح. هذه هي المهمة التي تقوم بها Angualar على خير وجه. لنتخيل أننا أرسلنا طلب AJAX لجلب قائمة بعناوين البريد الإلكتروني وسطر الموضوع فيها مع تاريخ إرسالها، ولنفترض أننا نريد عرضها ضمن الصفحة. في هذا المكان بالضبط تذهلنا Angular بقدراتها. لننشئ أولاً متحكماً بالبريد الإلكتروني: yApp.controller('EmailsCtrl', ['$scope', function ($scope) { // نُنشئ كائناً يدعاً `emails` $scope.emails = {}; // لنفترض أننا حصلنا على هذه البيانات من الخادوم // هذه **مصفوفة** من **الكائنات** $scope.emails.messages = [{ "from": "Steve Jobs", "subject": "I think I'm holding my phone wrong :/", "sent": "2013-10-01T08:05:59Z" },{ "from": "Ellie Goulding", "subject": "I've got Starry Eyes, lulz", "sent": "2013-09-21T19:45:00Z" },{ "from": "Michael Stipe", "subject": "Everybody hurts, sometimes.", "sent": "2013-09-12T11:38:30Z" },{ "from": "Jeremy Clarkson", "subject": "Think I've found the best car... In the world", "sent": "2013-09-03T13:15:11Z" }]; }]);علينا الآن دفعها ضمن الصفحة. هنا نستخدم الربط التصريحي لنُعلن عما سيفعله تطبيقنا: إنشاء أول جزء من عناصر HTML الحيوية. سنستخدم مُرشد ng-repeat المبني ضمن Angular، والذي سوف يمر على البيانات ويعرض الناتج دون عناء الاستدعاءات الرجعية أو تغيير الحالة، بهذه السهولة: <ul> <li ng-repeat="message in emails.messages"> <p>From: {{ message.from }}</p> <p>Subject: {{ message.subject }}</p> <p>{{ message.sent | date:'MMM d, y h:mm:ss a' }}</p> </li> </ul>النتيجة قمت أيضًا باستخدام مُرشّح التاريخ لأبين لك كيف يمكن أن تعرض تواريخ UTC. اطلع على المُرشدات التي توفرها Angular لتتعرف على القدرات الكاملة للربط التصريحي. بهذا نكون قد عرفنا كيف نصل البيانات بين الخادوم وطريقة العرض. وظائف المجال (Scope functions)تعتبر وظائف المجال الخطوة التالية في بناء وظائف التطبيق واستكمالاً للربط التصريحي. فيما يلي وظيفة بسيطة تحذف إحدى الرسائل: myApp.controller('MainCtrl', ['$scope', function ($scope) { $scope.deleteEmail = function (index) { $scope.emails.messages.splice(index, 1) }; }]);تنويه: من المهم أن تفكر في حذف البيانات من النموذج، لا تحذف العناصر أو أي شيئ من الصفحة، دع Angular يتولى هذا بربطه ثنائي الجانب للبيانات، فقط فكر بذكاء واكتب شفرة برمجية تستجيب لبياناتك. ربط الوظائف مع طريقة العرض يمر عبر المُرشدات، هذه المرة نستخدم مُرشد ng-click: <a ng-click="deleteEmail($index)">Delete email</a>هذا يختلف تمامًا عن مستقبلات النقر التقليدية في JavaScript، لأسباب عديدة سنشرحها لاحقًا. لاحظ أنني أيضًا أمرر فهرس العنصر $index، إذ يعرف Angualr ما العنصر المُراد حذفه (كم يوفر هذا من العناء؟) النتيجة دوال DOM التصريحيةننتقل الآن لدوال DOM، وهي أيضًا مُرشدات تؤدي وظيفة ضمن الصفحة بدونها كنا سنكتب شفرات برمجية طويلة. أحد الأمثلة المناسبة لإيضاح الفكرة هنا هو إظهار أو إخفاء قسم التنقل ضمن الصفحة باستخدام ng-show وng-click، لنرَ بساطة هذا: <a href="" ng-click="toggle = !toggle">Toggle nav</a> <ul ng-show="toggle"> <li>Link 1</li> <li>Link 2</li> <li>Link 3</li> </ul>هنا ندخل عالم MVVM (اختصار Model-View-View-Model)، لاحظ أننا لم نستخدم متحكمًا، وسنشرح فكرة MVVM بعد قليل. الناتج (جرب الإظهار والإخفاء): النتيجة التعابير (Expressions)من أفضل ما يقدمه Angular، يقدم بديلاً عن الحاجة لكتابة الكثير من JavaScript والنصوص المكررة. هل قمت يومًا ما بكتابة شيء كهذا؟ elem.onclick = function (data) { if (data.length === 0) { otherElem.innerHTML = 'No data'; } else { otherElem.innerHTML = 'My data'; } };ربما يكون هذا استدعاءً راجعًا عن طلب GET، ونحتاج لنغير محتوى في الصفحة بناء على البيانات، يقدم Angular هذا بدون الحاجة لكتابة حرف JavaScript! <p>{{ data.length > 0 && 'My data' || 'No data' }}</p>سيقوم هذا بتحديث الصفحة تلقائيًا دون استدعاءات عند وصول البيانات أو ما شابه. إن لم تتوفر البيانات، سيظهر هذا واضحًا، وإن وجدت فسيظهر كذلك. هناك حالات كثيرة جدًا يُمكن فيها لـAngular أن يتولاها عبر ربطه ثنائي الجانب للبيانات الذي يعمل بشكل رائع. النتيجة طرق العرض الديناميكية والتوجيه (Routing)هي ما تقوم عليه فلسفة تطبيقات الويب (والمواقع) أحادية الصفحة: لديك قسم الترويسة وقسم التذييل وشريط جانبي ثم المحتوى الذي يُحدث تلقائيًا بناءً على الرابط الحالي. يجعل Angular إعداد هذا الأمر في منتهى السهولة. تحقن طرق العرض الديناميكة دوالا مُعينة بناء على الرابط، عبر استخدام $routeProvider. فيما يلي إعداد بسيط: myApp.config(['$routeProvider', function ($routeProvider) { /** * $routeProvider */ $routeProvider .when('/', { templateUrl: 'views/main.html' }) .otherwise({ redirectTo: '/' }); }]);لاحظ أنه عندما (when) يكون الرابط / فقط (الصفحة الرئيسية)، ستعرض الصفحة main.html. من المفيد تسمية طريقة العرض الأساسية main.html وليس index.html لأنه سيكون لدينا مسبقاً الصفحة index.html وهي الصفحة التي تحوي طرق العرض الديناميكية وبقية الأجزاء. يمكن ببساطة إضافة المزيد من طرق العرض: myApp.config(['$routeProvider', function ($routeProvider) { /** * $routeProvider */ $routeProvider .when('/', { templateUrl: 'views/main.html' }) .when('/emails', { templateUrl: 'views/emails.html' }) .otherwise({ redirectTo: '/' }); }]);بإمكاننا الآن تحميل الصفحة emails.html ببساطة لتقوم بعرض قائمة الرسائل الإلكترونية. الخلاصة أننا استطعنا أن نبني تطبيقًا معقدًا للغاية بجهد ضئيل جدًا. توفر الخدمة $routerProvider المزيد من الخيارات، لكن ما تعلمناه عنها كافٍ في البداية. هناك أيضًا أمور أخرى مثل مُعترِضات $http التي تبدأ أحداثًا خلال مسير طلب AJAX، فتتيح لنا عرض مقدار التقدم على سبيل المثال أثناء جلب البيانات. البيانات الثابتة العامةفي تطبيق Gmail للويب، تُكتب بيانات كثيرة بصيغة JSON ضمن الصفحة (انقر باليمين واختر عرض المصدر في صفحة Gmail). إن قمنا بخطوة مشابهة، أي كتابة البيانات ضمن الصفحة، فهذا سيجعل وقت عرضها أقل وسيبدو التطبيق أسرع. عندما أطور تطبيقات مؤسستنا، تُدرج وسوم Java ضمن الصفحة وعندما تُعرض، تُرسل البيانات من الخادوم (لا خبرة لدي في Java لذا سأكتب فيما يلي تصريحات وهمية، يمكنك استخدام أي لغة على الخادوم إن أحببت). النصوص التالية توضح كيف يمكنك كتابة JSON ضمن الصفحة ثم تمريرها إلى المتحكم لربطها مباشرة: <!-- ضمن index.html (في نهاية الصفحة بالطبع) --> <script> window.globalData = {}; globalData.emails = <javaTagHereToGenerateMessages>; </script>سيُنشئ وسم Java الذي اختلقته البينات بينما سيعالج Angular الرسائل فورًا. كل ما عليك هو إعطاؤه البيانات عبر المتحكم: myApp.controller('EmailsCtrl', ['$scope', function ($scope) { $scope.emails = {}; // Assign the initial data! $scope.emails.messages = globalData.emails; }]);تقليص الملفات (Minification)سنتحدث قليلاً عن تقليص حجم الشفرات البرمجية التي كتبناها. ربما تكون قد جربت تقليص شفراتك البرمجية التي كتبتها لـAngular وصادفت خطأ. ليس هناك أمور خاصة يتطلبها تقليص حجم هذه الملفات، باستثناء الحاجة لإدراج أسماء المتطلبات ضمن مصفوفة قبل الدالة المُصرّح عنها، لنوضح أكثر: myApp.controller('MainCtrl', ['$scope', 'Dependency', 'Service', 'Factory', function ($scope, Dependency, Service, Factory) { // code }]);بعد التقليص: myApp.controller('MainCtrl', ['$scope', 'Dependency', 'Service', 'Factory', function (a,b,c,d) { // a = $scope // b = Dependency // c = Service // d = Factory // $scope alias usage a.someFunction = function () {...}; }]);عليك أن تحافظ على ترتيب المتطلبات المحقونة في المصفوفة ['_one', '_two'] وضمن مُعاملات الدالة function(_one, _two)، وإلا فإنك ستسبب لنفسك ولفريق العمل معك مشاكل كثيرة! الاختلافات بين MVC وMVVMسننهي مقالتنا العملاقة الآن بشرح سريع يشمل الفروق بين MVC وMVVM: MVC: التواصل يعتمد على المتحكم (Controller)، لذلك نقول Model-View-ControllerMVVM: يشمل ربط البيانات التصريحي الذي يتواصل، بالمفهوم التقني، مع نفسه؛ أي Model-View-View-Model. يتواصل النموذج مع طريقة العرض، وتتواصل هذه الأخيرة مع النموذج ثانية. يسمح هذا للبيانات بأن تبقى محدّثة على الجانبين دون الحاجة لفعل أي شيء. لا داعي هنا للمتحكم. مثال على ذلك: إنشاء حلقة ng-repeat دون أن نعتمد على بيانات يُرسلها متحكم:<li ng-repeat="number in [1,2,3,4,5,6,7,8,9]"> {{ number }} </li>يبدو هذا مناسبًا للتجارب السريعة، ولكنني أنصح دومًا باستخدام متحكم للحفاظ على تنظيم النص البرمجي. مثال مكونات الويب في HTML5قد تبدو هذه الفكرة مُكررّة، ولكنني سأعيدها هنا لنتحدث عن مكونات الويب. يسمح Angular بإنشاء عناصر (elements) مخصصة مثل: <myCustomElement></myCustomElement> في الحقيقة هذا أشبه ما يكون بمستقبل HTML5 التي تقدم فكرة جديدة تُسمى مكونّات الويب (Web Components)، والتي تتركب من عناصر مخصصة ضمن HTML مترافقة مع نص JavaScript ديناميكي، وهذا أمر مثيرٌ للغاية - والأكثر إثارة أنه أمر ممكن اليوم باستخدام Angular. فريق Angular بعيد النظر - شكرًا لكم! تعليقات المجال (Scope)أعتقد أن تعليقات المجال إضافة جميلة لسياق العمل، فبدل الحاجة لكتابة التعليقات ضمن HTML بالطريقة التالية: <!-- header --> <header> Stuff. </header> <!-- /header -->أصبحنا نتحدث عن طرق العرض والمجالات بدل الصفحة، البيانات ضمن مجال ما لا تُشارك مع مجالات أخرى إلا إن قمت بفعل ذلك عن عمدٍ. لنستغل هذا في تحسين كتابة النص البرمجي بتقسيمه إلى مناطق تسبقها تعليقات: !-- scope: MainCtrl --> <div class="content" ng-controller="MainCtrl"> </div> <!-- /scope: MainCtrl -->تصحيح العلل في Angularتتوفر إضافة جميلة للغاية لمتصفح Chrome ينصح بها فريق Angular، وتسمى Batarang. برمجة سعيدة! ترجمة -وبتصرف- للمقال: Ultimate guide to learning AngularJS in one day لصاحبه Todd Motto (الذي -بطبيعة الحال- يعود عليه ضمير المُتكلم في هذا المقال).1 نقطة
-
تحدثت من قبل عن أوهام SEO، وقلت بأن أغلب الخدمات التجارية المقدمة تحت ذلك المسمى مجرد نصب واحتيال، وبأن الأهم والأكثر أهمية في عملية تحسين الظهور في محركات البحث هو ”المحتوى“. كثيرون يجدون صعوبة في تصديق ذلك، ولذلك أكرر اليوم الحديث عن ذات الموضوع. لكن هذه المرة سأستعين بكلام جوجل نفسها. أشار Matt Cutts، رئيس قسم Webspam في جوجل، في معرض رده على استفسار أحد مدراء المواقع (شاهد الفيديو أدناه)، إلى أن المحتوى الجيد هو الأساس. أن تكون محترفا في قواعد SEO وتنفذ كل خطوة من الخطوات التي ينصح بها خبراء SEO، لا يعني بالضرورة أنك تملك المحتوى الأفضل ولا يعني بأنك ستحصل بالضرورة على ترتيب متقدم في نتائج بحث جوجل. من جهة أخرى، إذا لم تقم بأي شيء من قواعد SEO ولا تتوفر حتى على تصميم سليم للصفحة، لكنك تقدم محتويات جيدة ومميزة فإن محرك جوجل يمنحك ميزة أفضل ويعود دائما لموقعك لأرشفة المحتويات الجديدة. الأهم في البداية والنهاية هو المحتوى، وجوجل تطور باستمرار من خوارزمياتها لتظهر دائما المحتوى الأفضل أولا، بغض النظر عن من ينفذ قواعد SEO أم لا. لا بأس بإتقان أساسيات SEO لاكتساب ميزات إضافية، لكن لا تضيع وقتك ولا مالك في إعطاء SEO أكثر مما يستحق الأمر. ركز في البداية وفي النهاية على المحتوى. المحتوى كما يقولون هو الملك.1 نقطة
-
في سلسلة من عدة أجزاء سنناقش موضوعًا نظريًّا يُعتبر من أساسيّات هندسة البرامج، وهو أنماط التصميم (Design Patterns)، وسنعتمد لغة JavaScript في نقاشنا لتصاعد شعبيّتها ومرونتها التي تسمح لنا ببناء مشاريعنا وفق أنماط متنوّعة مما سيُسهّل علينا شرح موضوع السّلسلة ما هي أنماط التصميم؟عندما تبدأ بتعلّم البرمجة، فغالبًا ما يكون اهتمامك مُنصبًّا على أن يكون البرنامج قادرًا على إنجاز المهمّة الّتي تريدها قبل كل شيء، أمّا بعد أن تتطوّر مهاراتك، فسينتقل اهتمامك إلى مواضيع أكثر عمقًا، وستبدأ بطرح بعض الأسئلة على نفسك، حتّى قبل أن تبدأ بكتابة البرنامج، من هذه الأسئلة: كيف أبني برنامجي بحيث يسهُل تحسينه فيما بعد؟كيف أتأكّد أن برنامجي سيبقى يؤدّي ما يُتوقّع منه حتّى وإن قمت بتعديل أجزاء منه بعد زيادة تعقيده؟كيف أبني برنامجي بحيث أستطيع إعادة استخدام أجزاء منه في برامج أخرى في المستقبل؟كيف أجعل برنامجي يستخدم أجزاء من مشاريع أخرى كتبها مطوّرون آخرون؟الإجابة على هذه الأسئلة هي واحدة دومًا: اختر نمط التصميم المناسب لمشروعك. لم نُعرِّف بعدُ مفهوم نمط التّصميم، لكنّنا بدأنا نُكوّن فكرة عنه. نمط التّصميم هو وصف لطريقة مُعيّنة في حلّ مشكلة برمجيّة ما، فالعديد من المُشكلات البرمجيّة يمكن حلّها بأكثر من طريقة، ولكلّ طريقة مساوئ ومحاسن، وبعضها قد يكون أكثر مُناسبةً للمشروع الحاليّ، واختيار نمط التصميم المُناسب سيضمن استمرار تطوّر المشروع بسهولة وربّما يُفيدنا في عزل أجزاء منه لإعادة استخدامها في مشاريع أخرى بحيث لا نُضطَّر لكتابتها مرارًا. أغلب الظنّ أنّك تستخدم واحدًا أو أكثر من أنماط التّصميم وإن لم تعرف ما هي أنماط التّصميم بمعناها النّظريّ، فإنشاء أصناف (classes) لمفاهيم مُجرّدة في اللّغات الكائنيّة التّوجّه (object-oriented) وإنشاء نُسخ عنها (instances) وتوزيع هذه الأصناف في ملفّات مستقلّة، هو في الواقع نمط من أنماط التّصميم. يُرجى الانتباه إلى أن التّطبيق العمليّ لأنماط التّصميم يفرض على المطوّر دمج أكثر من نمط معًا وشرحنا لأحدها لا يمكن أن يخلو من استخدام لأنماط أخرى كما سيتبيّن لك بعد انتهاء السّلسلة، إذ يمكن مثلًا إنشاء وحدة (module) تُصدِّر صنفًا (class) وهذا يعني أنّنا استخدمنا نمطين اثنين (نمط الوحدات، ونمط مُشيّد الكائنات constructor) في وقت واحد. نمط الوحدات (Module Pattern)بغرض تبسيط الأمور، سنبدأ بتوضيح أحد أنماط التّصميم الشّائعة في JavaScript، وهو ما يُعرف بنمط الوحدات (module pattern)، والتي ازدادت شعبيّة بعد ظهور Node.js وما أحدثته من تأثير انتقل حتّى إلى أساليب بناء وتصميم المكتبات البرمجيّة الّتي تستهدف المُتصفّحات. الوحدات هي أجزاء مُستقلّة ومعزولة من النّص البرمجيّ للمشروع توفّر مهمّة مُعيّنة، الأمر الّذي يجعل الهدف من كل وحدة واضحًا ومحدّدًا ويُجنّب المشروع الفوضى التي تنتج عن كتابة كامل النّصّ البرمجيّ في كتلة واحدة متداخلة يصعب معها تنقيحه وصيانته. فصل الأجزاء هذا ليس الفائدة الوحيدة الّتي يُقدّمها نمط الوحدات، إذ من خلاله يمكن مُحاكاة مفهوم المكوّنات السّرّيّة (private) والعلنيّة (public) وحماية بعض محتويات الوحدة من الوصول إليها من خارجها في JavaScript، وذلك بإخفائها ضمن الوحدة والامتناع عن تصديرها الأمر الذي يجعل الوصول إليها من خارج الوحدة مستحيلًا كما سنوضّح بعد قليل. تتوفّر في عالم JavaScript أشكال مختلفة لتصميم الوحدات، منها: الكائنات الحرفيّة (object literals)الدّوالّ المغلقة المجهولة (anonymous closures)وحدات CommonJSوحدات AMDوحدات ECMAScript 6الشّكل الأول ربّما هو أبسط الأشكال وأكثرها بدائيّة، وهو يعني ببساطة إنشاء كائن باستخدام صياغة القوسين المعكوفين {} يضمّ خصائص ووظائف متعلّقة بمهمّة واحدة لعزلها وتسهيل استخدامها: var userSettings = { preferences: { privacy: "strict", language: "ar", showEmail: false, available: true, }, updatePreferences: function(newPrefs) { this.preferences = newPrefs; } }بعض خبراء JavaScript لا يعتبرون هذا النّمط وحدةً حقيقيّة لبساطته الشّديدة، فمن الواضح أنّ هذا النّمط أبسط من حاجات التّطبيقات المعقّدة، فغالبًا ما يكون توزيع الوحدات على ملفّات منفصلة أمرًا مرغوبًا أثناء تطوير التّطبيقات ولهذا نحتاج إلى وسيلة لاستيراد هذه الملفّات وتصديرها بما يسمح باستخدام وحدة واقعة في ملفّ من ملفّ آخر، ولهذا الغرض طوّر مجتمع JavaScript خلال الأعوام الماضية أساليب قياسيّة اتّفق على استخدامها على الرّغم من أن اللّغة ذاتها لم تقدّم مفهوم الوحدات إلّا في الإصدار الأخير (ES6)، والذي استلهم من الأساليب السّابقة أصلًا؛ كما أنّنا قد نرغب بحماية كائن مثل preferences في مثالنا السّابق من تعديله بصورة مباشرة. الشّكل الثّاني هو أسلوب أكثر تطوّرًا لإنشاء الوحدات، ويحتاج فهمه إلى فهم معنى الدّوال المُغلقة (closures)، فإذا كانت لدينا دالّة تُعيد عند استدعائها دالّة أخرى، فإنّنا ندعو الدّالة الأخيرة دالّة مُغلقة، ويتاح لهذه الدّالة الوصول إلى المتّغيّرات الّتي كانت مفروضة في الدّالة الأولى حتّى عندما تُستدعى من خارجها: function addNumberToN(n) { return function(number) { return n + number; } } var addTo2 = addNumberToN(2); var five = addTo2(3); // 5هذه الخاصيّة في JavaScript تسمح لنا بعزل المتّغيّرات (encapsulation) ضمن الدّالة الخارجيّة مع الاحتفاظ بإمكانيّة الوصول إليها من الدّوال والكائنات الفرعيّة، الأمر الذي يحاكي مفهوم خصوصيّة المتغيّرات في لغات البرمجة الأخرى (access modifiers). لنفترض مثلًا أنّنا نريد أن نقوم بإنشاء عدّاد لعدد النّقرات على زرّ معيّن في تطبيقنا، ولا نريد الاحتفاظ بهذه القيمة في النّطاق العامّ لأنّ هذا قد يعرّضها للتّعارض من أسماء مُتغيّرات أخرى أو يجعلها قابلة للتّعديل من إضافات خارجيّة في المتصفّح، لهذا نقوم بإنشاء دالّة مُغلقة تُحيط بهذه القيمة: function() { var counter = 0; return { increaseCounter: function() { counter++; } } }وبهذا نكون قد قيّدنا إمكانيّة تعديل قيمة المتغيّر بزيادته فقط، وعبر الدّالة increaseCounter() فقط. لا يمكن استخدام الدّالّة increaseCounter() إلا بعد استدعاء الدّالة المجهولة (anonymous) الّتي تُحيط بها، ويتمّ هذا كما يلي: (function() { var counter = 0; return { increaseCounter: function() { counter++; } } })()لتُصبح الدّالة increaseCounter() مُتاحة في النّطاق العامّ، وبهذا نكون حصلنا على شكل بدائي لفكرة "تصدير الوحدات" (module exports). لنستعرض الآن الأساليب الأخرى لإنشاء الوحدات، ولعلّ أكثر هذه الأساليب شيوعًا أسلوب CommonJS المُعتمد في Node.js، والذي يُتيح استيراد الوحدات باستخدام الدّالّة require(): var UrlMaker = require("./url-maker"); var url_maker = new UrlMaker("Hello World!"); var url = url_maker.make(); console.log(url); // hello-world;وأمّا تصدير الوحدات لإتاحة استخدامها، فيتم بإسناد الخصائص إلى الكائن module.exports، كما في الملفّ url-maker.js الموجود في مسار العمل الحالي: module.exports = function UrlMaker(string) { return { make: function() { return string.toLowerCase().replace(/\s+/gi, "-").replace(/[!?*%$#@`]/gi, "") } } }لا يقتصر استخدام أسلوب CommonJS على بيئة Node.js، بل يمكن نقله إلى المتصفّحات باستخدام برامج مثل Browserify. من الأساليب الشائعة لإنشاء الوحدات كذلك نمط وحدات AMD (اختصارًا لـAsynchronous Module Definition) ولعلّه يُستخدم بكثرة مع مكتبة require.js في المتصفّحات والّتي تسمح بتحميل الوحدات (الموزّعة كلّ منها على ملفّ منفصل) عند الحاجة إليها، إذ يتمّ التّصريح عن كلّ وحدة وما تعتمد عليه من وحدات أخرى وتقوم require.js بتلبية هذه المتطلبات بتحميل ملفّات الوحدات المنفصلة. في المثال التّالي، نُصرّح عن حاجة موقعنا لمكتبتي jQuery وUnderscore ووحدة أخرى قمنا بإنشائها بأنفسنا: require(["jquery", "underscore", "user_profile"], function($, _, UserProfile) { var user = new UserProfile(); user.firstName = $("#form input[name='first']").text(); user.lastName = $("#form input[name='last']").text(); user.username = $("#form input[name='username']").text(); // ... })ويتمّ التّصريح عن الوحدة user_profile في ملفّ منفصل باسم موافق: define(function() { function Profile() { /* ... */ } return Profile; })يوفّر الإصدار الجديد من JavaScript (ES6) دعمًا أساسيًّا لتعريف الوحدات واستيرادها وتصديرها، وسنتطرّق له بالتّفصيل في الجزء القادم من سلسلة التّعريف بميزات ES6 الجديدة، لكنّ لا بأس من أن نتعرّف عليه سريعًا: import { jQuery as $ } from "/jquery.js"; import { Profile as UserProfile } from "/user.js"; var user = new UserProfile(); user.firstName = $("#form input[name='first']").text(); // ...وتُنشئ الوحدة وتُصدَّر في الملفّ user.js: class Profile { constructor() { // ... } validate() { // ... } } export { Profile };فوائد استخدام الوحداتلنُلخِّص إذن فوائد الوحدات: تنظيم النّصّ البرمجيّ للمشاريع الضّخمة بحيث يسهل فهم بنية البرنامج وتنقيحه ومتابعة صيانته في المستقبل.إدارة المُتطلّبات (dependencies): توضيح العلاقة بين مكوّنات المشروع، بحيث نستطيع إدارة ما تتطلّبه كلّ وحدة وتحميل هذه المتطلّبات آليًّا بالتّرتيب الصّحيح بدل الحاجة إلى التّصريح عن روابط المكتبات الخارجيّة في الصّفحة الرئيسيّة للموقع وإعادة ترتيبها كلّ ما تطلّب الأمر إضافة مكتبة جديدة تعتمد على أخرى.العزل (encapsulation): حماية أجزاء من المشروع من العبث بها سهوًا أو من نصوص برمجيّة خارجيّة، وذلك بعزلها ضمن نطاق فرعيّ خلافًا لتركها في النّطاق العامّ. ففي الحالة الطّبيعيّة تكون متغّيرات JavaScript المفروضة في النّطاق العامّ مُتاحة لأي دالّة، وأما عند فرض هذه المُتغيّرات ضمن الوحدات، فإنّ الوصول إليها يُصبح محدودًا بما هو داخل الوحدة ذاتها، ويتمّ ذلك باستغلال مفهوم النّطاقات (scopes) في JavaScript وإحاطة هذه المتغيّرات بدالّة تُغلّفها بنطاق فرعيّ ثمّ إعادة كائن يحوي فقط الخصائص الّتي نريد إتاحتها للعموم.متى أستخدم هذا النّمط؟يُنصح باستعمال هذا النّمط في المشاريع الضّخمة كتطبيقات الويب المُعقّدة الّتي تعمل في المتصفّح، إذ تكون الحاجة مُلحّة لتجزئة المشروع وتطوير كلّ جزء بصورة مستقلّة ثم ربط هذه الأجزاء مع بعضها إمّا بهدف تسهيل تطوير المشروع أو إدارة المتطلّبات بحيث تُجلَب عند الحاجة إليها نظرًا لكبر حجمها أو تأثيرها على أداء التّطبيق، كما يُنصح باستخدامه عند الحاجة لعزل تفاصيل الوحدة عن النّطاق العامّ. المصادر: كتاب JavaScript Design Patterns لمؤلّفه Addy OsmaniJavaScript Module Pattern: In-Depthوثائق require.jsوثائق Node.js1 نقطة
-
بعد قراءة هذاالدرس سوف تُصبح قادرًا على رسم رجل ثلج ثلاثي الأبعاد باستخدام Inkscape ، وفي النهاية سوف نحصل على فهم واضح وكامل لكيفية رسم الظلال والانعكاسات بالطريقة الصحيحة. يعدّ برنامج Inkscape حديث نسبيًّا، ويتطور بشكل متصاعد وهو محرر للرسوم المُتّجهة ويصنف مع برامج Adobe Illustrator و Corel DRAW. ويعمل على أنظمة Linux وWindows وMac، وهو برنامج مفتوح المصدر ومجاني، وينتج رسومات وتصميمات بصيغة SVG. سوف نرى طريقة عمل هذا البرنامج الرائع لنتمكن من رسم وتشكيل الصور ثلاثية الأبعاد، وسوف نستخدم رجل الثلج كمثال توضيحي لنعمل عليه. في البداية، سوف نرسم الأشكال الأساسية ونتحكم ونعدل عليها. يمتلك برنامج Inckscape أدوات لرسم العناصر الهندسية الأساسية مثل الدوائر والقطوع والمستطيلات والنجوم والخطوط المتعددة، ولكن إن أردنا للرسوم أن تبدو أكثر وضوحًا من الأفضل أن نحدد الشكل (ctrl+shift+c) ونضفي عليها بعض الانحناء. يُفضّل رسم الأشكال الأكثر تعقيدًا باستخدام القلم Bezier curve tool، أقوم عادة برسم خط منحنٍ ثم أثنيه، ثم أحسن مواقع العقد وأغير شكلها (نتوء، أو مستوية) نبدأ برسم كرات الثلج والعيون بدءًا من شكل دائرة ثم نستخدم أقواس الدائرة لصنع الحواف السّفلية والعلوية للدّلو الذي سأضعه على الرأس، وأما لرسم الأنف يمكن استخدام انحناءات Bezier curve tool، وأخيرًا باستخدام نفس الأداة ننهي صنع الدلو ونقوم بتوحيد الأجزاء المرسومة باستخدام تعليميةunion ، نصل إليها على الشكل التالي: Path > Union لنتابع الرسم، بعد أن انتهينا من رسم الأشكال الأساسية، لنجعلها الآن تبدو ثلاثية الأبعاد. من أجل خلق تدرج سلس بين الضوء والظل، نستخدم التدرجات اللونية، وأمّا الحالات الأكثر تعقيدًا سنجمع بين التدرجات والتمويه الضبابي Gaussian blur. إحدى الطرق لتطبيق التعبئة المُتدرّجة Gradient Fill هي القيام بملئه أولًا ومن ثم الانتقال إلى أداة التعبئة المتدرجة، ومن شريط خيارات الأداة يمكن أن نختار بين "التعبئة الخطية" أو "التعبئة القطرية"، وتنفيذها فوق الشكل المُحدّد. وفي هذه الحالة سوف يسقط اللون المختار للتعبئة تدريجياً إلى أن يصل إلى درجة التعتيم 0%. ومن شريط الأدوات نفسه يمكن النقر فوق زر التحرير Edit من أجل فتح مربع حوار حيث يمكنك التّحكم بتوقف تدرج اللون المستخدم حاليًّا. في معظم الحالات سوف نحتاج إلى توقيف سحب اللون وتغييره، وللقيام بذلك ما علينا سوى اختيار أداة تعبئة متردة ومن ثم النقر على شكل جديد. وما سيظهر على الشاشة هي المساعدات التي يمكنك استخدامها لتغيير الموقع والتوجيه والخط الطويل وحجم التدرج وإيقاف تحويل الألوان وخيار للإضافة ( نقرة مزدوجة على الخط) أو خيار الحذف (استخدام زر "Delete" على لوحة المفاتيح). وبإمكانك أيضا الضغط على زر Shift من أجل نقل تركيز شعاع التدرج بعيدًا عن المركز. تظهر لنا مقابض التّدرج اللوني (Gradient handles) عند تعديل مكان أي عقدة، الأمر الذي يجعل تعديل شكل العناصر أكثر مرونة، ولكن في هذه الحالة لن تكون قادرًا على إضافة أو إزالة حد الألوان، سنتمكن فقط من تحريكهم. عند النقر لتحديد الحد اللوني في مربع الحوار (Fill in – stroke) سنرى فقط اللون الناتج عن ذلك الحد اللوني، الأمر الذي قد يكون غير متوقعًا، ولكنه في النّهاية سيجعل التّحكم في تدرجات الألوان أسهل من الطريقة السّابقة. تأكّد من أن تجرب نماذج مختلفة من الألوان بشكل كافٍ لاختيار المفضل لديك أو للوصول إلى اللون الذي يلائم الشكل على أحسن وجه. من أجل العمل على الألوان غالبًا ما نستخدم HSL وذلك للحصول على أفضل دقّة نظرًا لقدرته على ضبط السطوع وصفاء الألوان والفروقات الانتقائية بين الألوان التي نريدها. داخل المستند غالبا ما تحفظ القيم اللونية بصيغة RGB بالإضافة إلى قناة Alpha لذلك لا يوجد جدوى من استخدام تقنية CMYK عند تبديل وتغيير الألوان إن كنت تريد طباعة الرسوم لأمور تجارية لاحقًا. لسوء الحظ هناك بعض القيود الأخرى فعلى سبيل المثال، التعبئة اللونية المخروطية لشكلي الدلو والجزرة كانت لتكون أفضل، ولكن بما أن SVG يفتقر إلى هذا النوع من التعبئة فإن البرنامج يفتقر إليها أيضًا ولذلك سوف نحاول التغلب على هذه المشكلة بأفضل الطرق. وعليه، أبسط ما يمكننا فعله هو استيفاء شريحة رقيقة أو مستطيل من نفس اللون من أجل العمل على نسخة لها نفس الشكل ويمكن التحكم باستدارتها. من أجل القيام بذلك علينا تحديد مسار الشكل ومن ثم القيام بالخطوات التالية: Extensions > Generate from the path> Interpolate الآن يمكننا طمس جميع الشرائح التي أنشأها التأثير، وبالتالي جعل الخطوات الوسيطة أقل وضوحاً بكثير. الشيء الذي يمكننا التنويه إليه هنا أنه من الأفضل وضع كل المسارات الوسيطة في مجموعة واحدة عن طريق اتّباع الخطوات التالية: Ctrl+G أو Object> Group ومن ثم طمس معالمها معاً وإلا سوف يتم طمس معالم كل شكل على حدة وبالتالي فإن النتيجة النهائية لن تكون جيدة. وأسهل طريقة يمكن اتّباعها لتطبيق هذه العملية هي سحب الطمس المنزلق Blur slider إلى مربع حوار Fill'n'Stroke. لكنني لا أحبذ هذه الطريقة في الاستيفاء، لذلك سوف نقوم بمحاكاة التدرج الزاوي باستخدام دائرة نصف قطرها من الأشكال الضبابية، نقوم بسحبها من قمة رأس المخروط إلى قاعدته وأما لصنع مناطق الضوء والظلام سوف نكرر مسار الجزرة السابق، متبعين الخطوات التالية: Ctrl + D أو Edit- duplicate ولتطبيق استدارة حول قمة الرأس المخروطي نقرر عليه بشكل مزدوج لتوزيع التدرجات اللونية لأشكال غير واضحة على طول المخروط. ولكن بالتأكيد لا يمكننا ترك أي شيء خارج حدود شكل الجزرة لذلك سوف نقوم باقتصاص الزيادات عن طريق تطبيق مسار القطع،Clipping Path، وبما أننا أتممنا شكل الجزرة بشكل ممتاز سوف نقوم بتكرار ذلك مرة أخرى ومن ثم سنجمع كل أجزائها باستثناء مسار القطع وسنقوم بتطبيقه في مجموعة جديدة نقوم إنشائها متتبّعين الخطوات التالية: Object – Clipping path - apply ولإتمام ذلك بمثالية نقوم بملء مسار القطع بلون مختلف ليبرز عن الأشكال الأخرى لتجنب اختلاطه معهم. ولكن لا يمكننا رؤية مسار القطع بعد أن نقوم بتنفيذ الخطوات السابقة ولكن يكون بإمكاننا تعديل الأشكال التي تم قصها. دعونا الآن ننهي عملنا على الجزرة وإضافة بعض الانحناءات الخفيفة على الأنف وبعض انعكاسات الثلج من الأسفل، ثم نستخدم Calligraphic pen أو Pencil tool لرسم ما يشبه العين على الجزرة. أما الانعكاسات فهي توازي في أهميتها الظلال والأضواء حيث أن كافة الأشكال تعكس الضوء الذي بدوره ينعكس على أشكال أخرى في الرسم ويسلط عليها بعض الإضاءة ويجب العمل على هذين الأمرين سوية. إضافة إلى ما سبق، يجب علينا مراعاة تلوين الأشكال التي تحيط بالأشكال الأخرى ذات الألوان المشبعة كالجزرة في رسمنا السابق بألوان باهتة. وهذا هو السبب الذي لا يمكننا من رؤية الثلج ببياضه الناصع أو ورقة بيضاء بشكل كامل، وإنما نرى انعكاسات الألوان عليهما. وعليه فقد رسمنا منذ البداية كرات ثلج زرقاء قليلًا على افتراض أن رجل الثلج سوف يكون تحت سماء زرقاء نظيفة في مكان ما، ونحن الآن بحاجة إلى إضافة بعض الظلال والانعكاسات فقط. عند العمل على الظلال السفلية يجب أن نأخذ بعين الاعتبار أنّ المزيد منها سوف يسقط على الشكل، ولذلك يجب أن تكون أكثر ضبابية كما أنّ حدة الظل تعتمد بشكل كبير على مصدر الإضاءة. لننتقل إلى العمل على الدلو وكما نلاحظ أنّ تدرجات الألوان جيدة جدًا على الرغم من أنها كانت خطية، ولذلك سوف نقوم بإصلاحها قليلا الآن. بداية سوف نسلط على الدّلو ضوء الشمس عن طريق استخدام شريحة بيضاء ناصعة ومن ثم سوف نحدد المخروط بمساعدة الظل الذي هو عبارة عن الخطوط الداكنة الأكثر وضوحًا. وأخيرًا، سوف نضع بعض التدرجات الضّوئية الشفّافة التي تمثل انعكاسات الثلوج والضوء من الأعلى، وهكذا نكون قد أنشأنا ضوءً وظلالًا على شكل الدلو عن طريق إزالات متتالية للأجزاء التي لم نكن بحاجتها، ويبقى من الأفضل استخدام قلم رصاص Pencil لرسم الأشكال الواضحة. وبهذا نكون قد استخدمنا مسارات القطع المتعددة لكل من الدلو وكرات الثلج كما نكون قد استخدمناها لقص الأشياء غير الواضحة مثلما فعلنا سابقًا مع الجزرة. الخطوات التّالية تكمن في إضافة ثقب للدلو وتشكيل أخدود عن طريق نسخ الدوائر والقطوع التي استخدمت لبناء هيكل الدلو، ومن ثم نقل اثنين من هذه الدوائر إلى جانب بعضهما البعض اعتمادًا على عرض الحافة، عن الطريق الضغط إما على Ctrl+ - أو Path>Difference. ومن أجل تشكيل العينين، فإن تطبيقهما سهل للغاية ويمكن فعل ذلك عن طريق تسليط ضوء مع انعكاس خفيف إلى البؤبؤ بالإضافة إلى بعض التظليل فوق العين لجعلها تبرز قليلاً. ويمكن رؤية العينين دون تأثير الفلتر عليهما عن طريق تطبيق الخطوات التالية: View > Display Mode > No filters على الرغم من أنها صورة شعاعية إلا أن الخطة كانت أن نرسم نسخة نقطية منها ولهذا يجب تحديد حجم العينين منذ البداية، وأخذ هذا الأمر بعين الاعتبار عند رسم كل التفاصيل الصغيرة. ولذلك يجب تطبيق العينين وخطوط الدلو الدقيقة والأصابع باستخدام شبكة بيكسل. لجعل الصورة النهائية تبدو واضحة ونضرة بهذا الشكل. يدي رجل الثلج عبارة عن خطوط منحنية بشكل خفيف. لذلك قمنا بتعبئتها بتقنية ال Flat fill وأضفنا لها انعكاسات ضوئية للحصول على شكل ثلاثي الأبعاد لليدين. يتم رسم معظم الأوراق الخضراء رسم بأداة Calligraphic pen والخطوط الناتجة تم توحيدها باستخدام تعليمة boolean operation وتم تعبئتها لونياً باستخدام التدرج الخطي. تنحصر استخدامات أداة Calligraphic pen على الأغلب في: الترقيق : -60 يجعل الخطوط أرفع كلما انخفضت سرعة استخدامه. Caps: يجعل الخطوط نافرة قليلاً. التثبيت: 0 يكون القلم عموديًا على الخط. الزاوية: 0 ليس ذات أهمية كبيرة من أجل التثبيت. لقد قمت باستخدام القلم لتمكين خيار حساسية الضغط، وهذا ما يجعل الخطوط والأشكال المحدبة تبدو أكثر طبيعية. الأعواد هي عبارة مسارات مملوءة ب Flat fill ، معلمة وموضحة بنسخها الفاتحة والضبابية. تكفي بعض البقع الضبابية لجعل قاعدة الجزرة تأخذ أبعادًا واضحة أكثر. يجب ألا ننسى الظلال والانعكاسات على الثلج، حيث أن السماء تعطينا ظلاً مزرق والنباتات الخضراء للجزرة ستعطي ظلاً مخضر وبقع برتقالية. هذا هو كل شيء، الصورة في الأسفل هي الصورة النهائية دون تأثير الفلاتر. ترجمة -وبتصرّف- للمقال Drawing snowman in 3D with Inkscape لصاحبه Yuriy Apostol1 نقطة
-
بالرغم أن طبيعة العمل الحر علي خمسات تتيح للبائع الحرية المطلقة في اختيار وقبول الأعمال، إلا أنها تفرض عليه في نفس الوقت ضرورة الإلتزام بتسليم العمل في الوقت المحدد سلفاً، حيث أنه من أبرز صفات البائع الناجح الإلتزام في مواعيده بينما يتسبب عكس ذلك في خلافات ومشاكل مع العملاء. فإذا كنت تعاني من ضغط العمل وضيق الوقت فلا تقلق، سنقدم لك اليوم مجموعة من الحلول التي قد تمكنك من تخطي هذه المشكلة وتساعدك علي تسليم أعمالك في الموعد المحدد. 1- أعط لنفسك الوقت الكافي للتنفيذالقاعدة الأولى في عالم العمل الحر والتي دائما ما ينصح الاخرون بها في هذا المجال، أنت مدير عملك والذي تقوم بوضع الوقت المناسب للعمل وتسليمه ولا أحد يجبرك على وقت محدد، لا داعي لأن تضغط نفسك من أجل أمور تنافسية أو الحصول على عدد كبير من الأعمال، تسليم العمل بشكل مريح ودقيق أفضل ألف مرة من عشرات الفرص التي لا تستطيع تنفيذها في الوقت المطلوب، فاحرص دائما علي هذه النقطة. 2- لا تستنزف الوقت الإضافي الذي قد يتاح لكنعم، أحياناً أثناء العمل قد يتاح لك وقت مبكر إضافي عن الموعد المحدد للتسليم وقد يحدث معك عدة مرات، من أكثر الاخطاء الشائعة التي قد يقع فيها من يعمل في العمل الحر هو أنه حينما يتوفر له بعض الوقت الزائد في التنفيذ يقوم على الفور بتقليل وقت تسليم العمل بهدف المنافسة، فهو لا يدري أنه أحياناً قد يكون هذا الوقت جاء نتيجة أمور استثنائية، لذلك لا ينصح ان تقوم بتقليل موعد تسليم العمل إلا بعد ان تجرب الأمر عدة مرات، وإذا وجدت أن هذا الوقت الإضافي يتكرر كثيرا فيمكنك التفكير في تغييره. 3- استخدم دائماً وسائل تساعدك على تنظيم وقتكلا شك ان أحد أسرار دقة التوقيت وتسليم العمل في موعده هو التنظيم، تنظيم المهام وظبط الوقت المناسبة لكل مهمة يساعدك كثيرا على العمل بشكل مريح ويجعل العمل جاهزاً في وقته المحدد، هناك الكثير من الأدوات التي تساعدك على ذلك مثل : برامج تحديد المهام وضبطها وأشهرها ( Wunderlist – Asana – إلخ)، برامج تدوين الملاحظات (evernote وغيرها) برامج لحفظ وتنظيم ملفاتك (dropbox – Google drive – إلخ)، وسنقوم لاحقا في تدوينة منفصلة بشرح تفصيلي لأشهر هذه الادوات وتعريفها بشكل كامل. 4- أعط لنفسك راحة إجبارية بين الأعمال المنفذةعندما ترسل إليك إعمال جديدة، احرص تماما على أخذ فترة راحة بينهما ولا ينصح مطلقاً بأن يتم تنفيذ الأعمال بشكل متتالٍ إلا إذا كان هذا العمل لا يستغرق منك مجهودا كبيرا، القيام بتنفيذ الأعمال بشكل متتال قد يصيبك بالإرهاق أو الملل مما قد يؤثر علي أدائك ويؤدي إلى استنزاف الكثير من الوقت، وقد يسبب لك الكثير من الضغط لاحقا عند تسليم العمل، العميل قد لا يتأثر كثيرا بتأجيل موعد استلام العمل قليلا ضمن الوقت المتفق عليه، على عكس موعد التسليم الذي يهتم به أغلب العملاء والذي قد يؤثر علي التقييم النهائي للعمل أو قد يحدث لك مشاكل بسبب التأخير عن الموعد المحدد. 5- فكر دائما في الظروف الاستثنائيةمن أهم وأخطر المشاكل التي يتعرض لها من يعمل في مجال العمل الحر حدوث ظروف استثنائية قد تستهلك منه وقتا كبيرا أو تعطله عن أداء عمله، ولعل أشهر هذه الظروف هو مشكلة انقطاع الكهرباء أو انقطاع الانترنت أو حدوث مشاكل فنية في الحاسوب وغيرها، البائع الذكي هو الذي يفكر دائما في هذه الظروف ويضعها في الحسبان، حتى وإن كانت الظروف المحيطة بك طبيعية ولا توحي بوجود مشاكل فيجب أيضا ان يضع البائع بعض من الوقت تحسبا لأي ظروف طارئة، الإهمال في هذه النقطة سيحدث لك عبئا كبيرا في الوقت غير المرغوب فيه. 6- لا تورط نفسك في مشاكل جانبيةدائما ما تظهر للبائع بعض المشاكل الجانبية والتي قد تعطله عن المهام الأساسية وتستهلك قدرا كبيرا من الوقت، في مثل هذه الحالات حاول أن تعمل على تأجيلها لحين الانتهاء من المهام الأساسية المطلوبة، حتى تضمن أن هذه المهام تم تنفيذها على أكمل وجه، التقصير في المهام الثانوية بالتأكيد لا يقارن بالمهام الاساسية، بالإضافة إلى أن الكثير من هذه المشكلات قد يتم حلها بشكل سريع ومتتالي على عكس المهام الأساسية قد تحتاج منك قدرا كبيرا من التركيز. تم نشر هذا المقال لأوّل مرة على مُدونة خمسات1 نقطة
-
إنّ أي مُطوّر أو مُصمّم يُحب كتابة الشيفرة البرمجية، ستكون تقسيمات الصفحة layouts المُعتمدة على أوراق الأنماط المُتتالية هي صميم وجوهر عمله. فيما قد تكون هذه المقالة مُراجعة للبعض، أو حتّى تصحيح بعض المفاهيم للبعض الآخر، سيتمّ تناول خاصّيّة التَمَوْضُع position، وكيفيّة استخدامها في تصميم تقسيمات صفحة layouts مُسايرة ومُتوافقة مع المعايير القياسيّة، ولا تعتمد على الجداول. يُساء فهمُ خاصّيّة التَمَوْضُع، ممّا يؤدي في بعض الأحيان عند تصحيح علّة مُعينة في شيفرةٍ ما من المُمْكن أنّ يتمّ استخدام قيم مُختلفة بأسلوب التجربة والخطأ للخاصّيّة position لمُحددٍ ما حتّى يتمّ الحصول على القيمة المطلوبة. إنّ هذه الطريقة المُملّة قد تفي بالغرض، ولكن من المُفترض على المُطوّر معرفة بالتحديد لماذا القيمة position: relative قد استطاعت إصلاح مُشكلة ما في تقسيم الصفحة دون قيمة أُخرى. هدف هذا الشرح هو تعلّم دلالات قيمة الخاصّيّة position وتأثيرها على الصفحة، وبالأخصّ، كيف سوف تؤثّر هذه القيم على بقية أجزاء الصفحة (markup). يُقدم بَيان specification أوراق الأنماط المُتتالية خمس خواصٍّ وهي: ساكن: staticنسبيّ: relativeكامل أو مُطلق: absoluteثابت: fixedمَوروث: inheritكما تمّ إضافة قيم جديدة ولكنها مازالت في مرحلة "مسودة عمل". يُستفاد من كل خاصّيّة لغرضٍ مُعينٍ، لذلك فَهمُ الغرض من كلٍ منها هو الطريق الأمثل لاحتراف تقسيمات الصفحة المُعتمدة على CSS. الخطوات الأولى مع أليّة عمل خواصّ التَمَوْضُعسيتمّ العودة إلى الأساسيّات لفهم الأمور بشكلٍ صحيحٍ. في CSS وبطبيعة الحال، يتمّ العمل ضمن حدود وقواعد ما يهم هُنا هو ما يُدعى بـ "التدفّق الطبيعيّ" normal flow. في العودة إلى بيان مُنظمة رابطة الشبكة العالميّة W3C سيكون تعريف التدفّق الطبيعيّ بالشكل التّالي: يُمكن اعتبار الصندوق المَذكور في البيان السابق كالصندوق الخشبي، والتدفّق الطّبيعيّ كما لو أنّه قانون كما هو قانون الجاذبيّة، التدفّق الطّبيعيّ للمُستند يُعبر عن اصطفاف العناصر فوق بعضها البعض تدريجيًّا من الأعلى إلى الأسفل، لكي تَظهر بالشّكل المُفترض لها أنّ تظهر عليه. يُمكن تشبيه التدفّق الطّبيعيّ بصناديق (مُكعبات) الأحرف الأبجديّة الّتي يُبنى منها ذلك البرج الضخم -الّذي يبنيه الأطفال بشكل مُتسلسل للأحرف- حيثُ أنّ هذه الصناديق الخشبيّة مُقيّدة بفعل الجاذبيّة الأرضيّة، ولا يُمكن إعطائها خصائص تُعارض قانون الجاذبيّة. في الجهة المُقابلة تتبع العناصر بعضها البعض في ترتيب عناصر الصفحة الخاصّة بمُستند HTML. ولكن من المُمكن إعطاء هذه العناصر خصائص لتُعرض بشكلٍ مخالفٍ لترتيبها الطبيعيّ. الخاصيّتان static و relativeتشبه خاصِّيَّات التَمَوْضُع "ساكن" static و "نسبيّ" relative سلوك صناديق الأبجديّة، حيثُ أنّها تصطفّ فوق بعضها البعض كما هو مُتوقعٌ لها. مع الانتباه إلى أنّ الخاصّيّة static هي القيمة الافتراضيّة للخاصّيّة position لأي عنصر. وعندما يكون هناك ثلاثة عناصر تحمل الخاصّيّة static فإنّها سوف تصطفّ فوق بعضها البعض. في المثال التّالي يوجد ثلاثة عناصر جميعها تحمل القيمة static. #box_1 { position: static; width: 200px; height: 200px; background: #ee3e64; } #box_2 { position: static; width: 200px; height: 200px; background: #44accf; } #box_3 { position: static; width: 200px; height: 200px; background: #b7d84b; } يُلاحظ من المثال السابق كيف أنّ هذه الصناديق تصطفّ فوق بعضها البعض. هذه الفكرة على بساطتها تعتبر أساسيات بناء الكتل block building ومن المُهم جدًا إدراكُها. يُمكن استخدام القيمة static لإنشاء تقسيمات صفحة مُبسّطة بعمود واحد single-column، حيثُ كل عنصر يتموضع فوق العنصر الّذي يليه. وعند الرغبة في نقل هذه العناصر فيما بينها باستخدام خواصّ الإزاحة offset مثل: الأعلى top، اليمين right، الأسفل bottom، اليسار left ستكون النتائج غير مُرضيةٍ أبدًا، حيثُ لا تؤثر هذه الخواصّ على عنصر ساكن static (أي يقوم بتجاهلها). كما لا يستطيع العنصر الساكن إنشاء نسق إحداثيَّات جديد للعنصر الابن. ولكن ما هو نسق الإحداثيَّات، هذا ما سيتمّ توضيحه باستخدام القيمة نسبيّ relative. تتصرّف العناصر المُتموضعة بشكل نسبيّ relative كما هي العناصر المُتموضعة بشكل ساكن static، حيثُ تتوافق فيما بينها بشكل مُتناسق، من دون أنّ تسبب أي مشاكل. قد يبدو الأمر غريبًا، ولكن عند تطبيق القيمة relative على المثال السابق ستكون النتائج مُشابهة للمثال السابق: #box_1 { position: relative; width: 200px; height: 200px; background: #ee3e64; } #box_2 { position: relative; width: 200px; height: 200px; background: #44accf; } #box_3 { position: relative; width: 200px; height: 200px; background: #b7d84b; } يُبرهن المثال السابق كيف أنّ العناصر المُتموضعة بشكل نسبيّ relatively تسلك سلوك العناصر المُتموضعة بشكل ساكن statically. لكن ما هو غير واضح أنّ هذه العناصر الّتي تحمل القيمة relative تختلف بمَيْزة هامة جدًا عن العناصر الّتي تحمل القيمة static. يكمُن الاختلاف الأوَّليّ في أنّ العناصر المُتموضعة بشكل نسبيّ من المُمكن تعديل مَوضعها باستخدام خاصِّيَّات الإزاحة: top و right و bottom و left. سيتمّ استخدام المثال السابق، ولكن بإضافة تَمَوْضُع الإزاحة على الصندوق الثاني “box_2”: #box_2 { position: relative; left: 200px; width: 200px; height: 200px; background: #44accf; } يُظهر المثال السابق التَمَوْضُع النسبيّ بشكلٍ عمليٍّ. حيثُ أنّ الصناديق الثّلاثة مُتموضعة فوق بعضها ماعدا الصندوق الثّاني فقد تمّ دفعه 200px من اليسار. في هذا المثال قد تمّ كسر قانون الجاذبية بناءً على رغبتنا. ومازال الصندوق الأزرق ينتمي إلى التدفّق العام الخاصّ بمُستند HTML، حيثُ أنّ الصندوق الأخضر يأتي أسفل الصندوق الأزرق على الرغم من أنّ الصندوق الأزرق ليس فوقه بشكل مُباشر. عند استخدام خاصِّيَّات الإزاحة لنقل عنصر مُتموضع بشكلٍ نسبيٍّ، فإن ذلك لا يؤثّر على العنصر أو العناصر التّالية، حيثُ أن الصندوق الأخضر مازال مُتموضعًا كما لو كان الصندوق الأزرق غير مُزَاح. وهو أمرٌ لا ينطبق على التشبيه الخاصّ بصناديق الأبجديّة. يُعتبر إنشاء نسق إحداثيَّات للعنصر الابن مَيْزةً أُخرى من ميزات خاصيّة التَمَوْضُع النسبيّ. حيثُ يُمثل هذا النسق نقطةً مرجعيّةً لخاصِّيَّات الإزاحة. سيتمّ العودة إلى المثال السابق لتوضيح هذه الفكرة، حيثُ أنّ الصندوق الأزرق لا يتموضع داخل أيًا من العناصر، لذلك نسق الإحداثيَّات المُستخدم لإزاحة نفسه 200px من جهة اليسار يعود إلى المُستند نفسه. ولو تمّ وضع الصندوق الثّاني داخل الصندوق الأول، سيتمّ الحصول على نتائج مُختلفة، حيثُ أنّ الصندوق الثّاني سيتموضع نِسْبَة إلى نسق الإحداثيّات من الصندوق الأول (الأحمر). في المثال التّالي سيتمّ التعديل على مُستند HTML دون التعديل على التنسيق CSS، وذلك بنقل الصندوق الثّاني داخل الصندوق الأول: <div id="box_1"> <div id="box_2"></div> </div> يُظهر المثال السابق ترميز مُستند HTML الجديد. وبسبب نسق الإحداثيّات الجديد، يقيس الصندوق الأزرق إزاحته 200px من جهة اليسار نسبةً إلى المكان الّذي كان سيكون عليه الصندوق الأزرق لو لم يكن مُتموضعا بشكلٍ نسبيٍّ. القيمة Absoluteتُمثّل القيمة absolute درجة عالية من الأهمية وأكثر من سابقتها relative، حيثُ التخصيص هو ما يُميز هذه القيمة. يُسحب العنصر المُتموضع بشكلٍ نسبيٍّ من التدفّق الطّبيعيّ، وذلك عكس ما يتمّ في العناصر الّتي تحمل القيمة relative و static. ويمكن التحكم بالعنصر بطريقةٍ مرنة عندما يتمّ سحبه من التدفّق الطّبيعيّ، حيثُ يُمكن وضعه في أي مكان من دون أنّ يؤثّر أو يتأثّر بباقي العناصر المُنتمية إلى هذا التدفّق. يُمكن التفكير بهذه العناصر كما لو أنّ لها على الجهة الخلفية قطعة كبيرة من مشبك velcro، حيثُ يُمكن إلصاق هذه العناصر في أي مكان حسب الرغبة والحاجة. تَستجيب العناصر المُتموضعة بشكل مُطلق (كامل) absolutely إلى خاصِّيَّات الإزاحة. حيثُ يُمكن تحديد القيم top: 100px و left: 200px للعنصر ليتوضع العنصر بالضَّبط 100px من الجهة العلوية و200px من الجهة اليُسرى للمُستند. سيتمّ التوضيح بالمثال التّالي وباستخدام أربعة صناديق: #box_1 { position: absolute; top: 0; left: 0; width: 200px; height: 200px; background: #ee3e64; } #box_2 { position: absolute; top: 0; right: 0; width: 200px; height: 200px; background: #44accf; } #box_3 { position: absolute; bottom: 0; left: 0; width: 200px; height: 200px; background: #b7d84b; } #box_4 { position: absolute; bottom: 0; right: 0; width: 200px; height: 200px; background: #ebde52; } يُظهر المثال السابق أربعة صناديق تتموضع في زَوايا المُتصفّح الأربع، وذلك بسبب أنّ كل صندوق يحمل القيمة absolute للخاصيّة position، بكلماتٍ أُخرى تمّ إلصاق هذه الصناديق في كل زاوية من زوايا نافذة المُتصفّح. ستبقى هذه الصناديق بالزاوية الخاصّة بها عند تغيير حجم المُتصفّح. وإنّ تصغير حجم المُتصفّح بحيثُ تتداخل أو تتشابك هذه الصناديق مع بعضها لن يُحدث أي تفاعل فيما بينها على الإِطْلاق، أي لن يزيح أحدها الآخر، وكأنّ كل صندوق في طبقةٍ مُختلفة، وذلك لأنّ هذه الصناديق قد أصبحت خارج التدفّق الطبيعيّ للمُستند. تُنشئ العناصر المُنسّقة بالقيمة absolute نسق إحداثيَّات جديد للعناصر الأبناء الخاصّة بها. المثال التّالي يوضّح كيف أنّ الصناديق البرتقاليّة الصغيرة تتموضع داخل الصناديق الآباء الخاصّة بها، وإحداثيّات الإزاحة مُرتبطة بالعناصر الآباء لا بنافذة المُتصفّح. <div id="box_1" class="box"> <div class="orange"></div> </div> <div id="box_2" class="box"> <div class="orange"></div> </div> <div id="box_3" class="box"> <div class="orange"></div> </div> <div id="box_4" class="box"> <div class="orange"></div> </div>} .box { position: absolute; width: 200px; height: 200px; } #box_1 { background: #ee3e64; top: 0; left: 0; } #box_2 { background: #44accf; top: 0; right: 0; } #box_3 { background: #b7d84b; bottom: 0; left: 0; } #box_4 { background: #ebde52; bottom: 0; right: 0; } .orange { background: #f95b34; position: absolute; top: 39%; left: 41%; width: 40px; height: 40px; } تُقدم القيمة absolute خصائص مُميّزة عند استخدام قيم الإزاحة معها، حيثُ سيُصبح من المُمْكن تَمْديد العنصر من دون تحديد أيًا من أبعاد العَرض width أو الارتفاع height، والّتي ستكون مُختلفة بناءً على حجم نافذة المُتصفح أو قياس الشاشة. وعليه فإنّ العنصر الابن سيكون مُقيّدًا بالعنصر الأب الخاصّ به، أو المُستند نفسه. المثال التّالي سيُوضح الفكرة: a { position: absolute; top: 10px; right: 10px; bottom: 10px; left: 10px; background: #44accf; } #box_b { position: absolute; top: 20px; right: 20px; bottom: 20px; left: 20px; background: #ff9c34; } يُوضّح المثال السابق كيف أنّ العناصر قد أصبحت أكثر مُرونة fluid، حيثُ يَتغيّر حجمها مع تَغيّر حجم الصفحة. ويوضّح المثال التّالي كيفيّة إنشاء صفحة بعمودين وبارتفاع الصفحة بالكامل. #box_1 { position: absolute; top: 0; right: 20%; bottom: 0; left: 0; background: #ee3e64; } #box_2 { position: absolute; top: 0; right: 0; bottom: 0; left: 80%; background: #b7d84b; } يُظهر المثال السابق تقسيم صفحة بعمودين، والّذي يُوضّح ما يُمكن عمله باستخدام القيمة absolute. أخذًا بعين الاعتبار أنّ هذا الأسوب ليس أفضل طريقة في إنشاء تقسيم صفحة بعمودين. يُمكن استخدام بعض الحِيَل في إيجاد تطبيقات عمليّة لهذه الخاصّيّة. على سبيل المثال: #box_1 { width: 200px; height: 200px; background: #ee3e64; } #box_2 { position: absolute; left: 100px; width: 200px; height: 200px; background: #44accf; } عند التركيز في المثال السابق والصندوق الثّاني بالتحديد، سيتمّ مُلاحظة كيفيّة استخدام قيمة إزاحة واحدة left: 100px;، وهذا ما يَسمح للصندوق الثّاني في الحفاظ على حافته العلوية في مكانها مع مقدرته على الانتقال 100px من جهة اليسار، ولكن عند تطبيق قيمة إزاحة ثانية إلى الجهة العلوية، سيتمّ سحب الصندوق الأزرق إلى أعلى المُستند: #box_2 { position: absolute; top: 0; left: 100px; width: 200px; height: 200px; background: #44accf; } القيمة ثابت Fixedيُشارك العنصر الّذي يحمل التنسيق position: fixed جميع الأحكام والقواعد الّتي يحملها العنصر المُتموضع بشكل مُطلق absolutely، حيثُ أنّ العنصر يُسحب من التدفّق الطّبيعيّ للمُستند. ويكمُن الاختلاف في أنّ العنصر الثّابت fixed يتمَوضع نسبة إلى المُستند، وليس إلى عنصر أب مُعيّن. كما لا يتأثر العنصر الثابت بالتدرّج، فيبقى في مجال الرؤية مهما تمّ النزول أو الصعود في الصفحة. #box_2 { position: fixed; top: 0; left: 0; right: 0; } يُظهر المثال السابق شريطًا عُلويًّا يحتوي على نصّ، وذلك كعنصر fixed، من المُلاحظ عدم تحرك هذا الشريط عند التدرّج في الصفحة. أيضًا من المُلاحظ أنّ خاصِّيَّات الإزاحة left وright تحمل القيمة صفر. باعتبار أنّ القيمة fixed تنتهج سلوكًا مشابهًا لسلوك القيمة absolute، فمن المُمكن أنّ يتمّ تمديد عرض العنصر ليتناسب مع مجال الرؤية عند تثبيت العنصر أعلى الصفحة باستخدام top: 0;. القيمة Inheritتمّ في بداية المقالة الإشارة إلى وجود خَمس قيم مُتوفّرة للخاصيّة position. القيمة الخامسة هي مَوروث inherit والأقل أهميّة. تعمل هذه القيمة كما يدلّ الاسم الخاصّ بها، حيثُ أنّ العنصر يرث القيمة الخاصّة بالعنصر الأب. علمًا أنّه في الأساس، عناصر الخاصّيّة position لا ترث قيمتها من العنصر الأب الخاصّ بها، وتكون القيمة static هي القيمة الافتراضيّة. الفرق بين relative وabsoluteيُظهر هذا التشبيه الفرق بين التنسيقين "نسبيّ" و "مُطلق". يُزاح دائمًا العنصر الّذي يحمل التنسيق "نسبيّ" نسبةً إلى موضعه الأصليّ في التدفّق الطّبيعيّ، بمعنى أنّ هذا العنصر يتحرك نسبة إلى المكان الّذي كان سيكون عليه في الظروف العاديّة. وهذا الانتقال لا يؤثّر على تقسيم الصفحة أو العناصر المُحيطة، أي كأنّ هذا العنصر قد أصبح شبحًا قد ترك جسمه خلفه. هذا الجسم له عرض وارتفاع ويؤثّر على محيطه ولكنه غير ظاهر. ويستطيع الصندوق الشبح التحرك ولكنه مازال مُرتبطًا بجسمه القديم، بمعنى أنّ موقعه الحاليّ يُقاس بناءً على موقعه القديم. أمّا العنصر الّذي يحمل التنسيق "مُطلق" فهو لا يؤثّر على محيطه أبدًا، وذلك لأنّه قد تمّ سحبه من التدفّق الطّبيعيّ. وبذلك فهو أيضًا شبح ولكنه لم يترك جسمه خلفه كما فعل الشبح النسبيّ. وبالنسبة للعناصر المُحيطة فإنّ هذا العنصر غير موجود. يحصل الشبح المُطلق على موضعه بعد النظر عبر جميع الآباء الخاصّة به حتّى يجد واحدًا منها يتموضع إما بشكلٍ "نسبيّ" أو "مُطلق" ليكون نسق إحداثيَّات لهذا العنصر. وعندما لا يجد هذا الشبح أيًا من الآباء يتموضع بشكلٍ "نسبيّ" أو "مُطلق"، ستكون نقطته المرجعيّة هي المُستند العام. تطبيقٌ عمليّسيتمّ تَوظيف الشرح السابق في مثالٍ عمليّ يجعل من الأمور أكثر وضوحًا لهذه الخاصِّيَّات. المثال هو للتوضيح فقط، ولا يُعتبر تطبيقًا مثاليًا لاستخدامه في الواقع العمليّ. <div id="container"> <div id="nav"> <a href="#">Link</a> <a href="#">Link</a> <a href="#">Link</a> <a href="#">Link</a> <a href="#">Link</a> </div> <div id="content"> <div id="callout"> <p>...</p> </div> <p>...</p> <p>...</p> <p>...</p> <p>...</p> <p>...</p> <p>...</p> <p>...</p> <p>...</p> <p>...</p> </div> <div id="footer"> <p>Copyright © 2015 - webtuts Web Sites</p> </div> </div> تُظهر الصورة السابقة تقسيم صفحة شائع الاستخدام في الكثير من المواقع، شريط تنقل علوي navigation، المحتوى content، ذيل الصفحة footer. سيتمّ مُناقشة كل عنصر، وخاصيّة التَمَوْضُع الخاصّة به، ولماذا تمّ اختيار كلٍ منها. سيتمّ استخدام #container لجعل بقية العناصر مُتمركزة في المُنتصف. العنصر #nav سيكون العنصر الأول داخل العنصر #container. لم يتمّ تخصيص العنصر #nav بالخاصيّة position، لذلك ستكون القيمة static هي المُعَيَّنة. وستفي القيمة الافتراضيّة بالغرض على اعتبار أنّه لن يتمّ إزاحة هذا العنصر، أو استخدامه في إنشاء نسق إحداثيَّات جديد. على الجهة الأُخرى سيتمّ تخصيص العنصر التّالي وهو #content بخاصيّة التَمَوْضُع position بالقيمة relative. لا تؤثر قيمة التَمَوْضُع position على العنصر #content عند عدم استخدام أيًا من قيم الإزاحة، ولكن قد تمّ تخصيصها بالتنسيق position: relative; لتُكوّن نقطة الإحداثيَّات للعنصر #callout. كما تمّ تنسيق العنصر #callout بالتنسيق position: absolute. أخذًا بعين الاعتبار أنّ العنصر الأب وهو #content الخاصّ بهذا العنصر قد تمّ تنسيقه بشكل نسبيّ relative، فإنّ خاصِّيَّات الإزاحة المُطبقة على العنصر #callout ستكون مُعتمدة على الإحداثيَّات المُنشأة من قبل العنصر الأب #content. كما تمّ تخصيص العنصر #callout بإزاحته -80px إلى جهة اليمين بهدف سحبه خارج العنصر الأب. علاوةً على ذلك، تمّ تخصيص العنصر #callout بإزاحته من الجهتين العلويّة والسفليّة بالقيمة 100px، وبذلك سيحافظ هذا العنصر على ارتفاع شبه كامل منقوصًا 200px مهما كان حجم الصفحة. لا يؤثّر العنصر #callout على باقي العناصر بما أنّ له القيمة absolute، ولذلك يجب إضافة بعض الحشو padding للعنصر #content وذلك كي لا تختفي الفَقْرات paragraphs أسفل العنصر #callout. كما سيتمّ تخصيص ذيل الصفحة بخاصيّة التَمَوْضُع مع القيمة fixed مما يجعله ثابت ضمن مجال الرؤية viewport عند التدرّج في الصفحة نزولًا أو صعودًا. كما سيتمّ إضافة حشو إلى العنصر #content ومن الناحية السفلية وبقيمة 60px وذلك لعدم اختفاء الفقرة الأخيرة تحت ذيل الصفحة. الخاتمةتُعتبر خواصّ التَمَوْضُع من المواضيع الّتي لا بُد على أي مُطوّر الإلمام بها بشكل مُعمّق، وذلك كي لا يتمّ الاعتماد على أسلوب التجربة والخطأ trial and error في التعامل مع هذه الخاصّيّة. يعطي فهم هذه الخاصّيّة احترافيّة عالية للمُطوّر ويزيد من إنتاجيّته عن باقي المُطوّرين الّذين يعتمدون على أسلوب التجربة والخطأ. ترجمة -وبتصرّف- للمقال CSS Positioning 101 لصاحبه Noah Stokes1 نقطة
-
هناك اعتقاد خاطئ بين العديد من مطوّري الويب أن CSS هي الطريقة الوحيدة للقيام بالتحريك Animations. برزت CSS بقوة كأكثر نظام مُدلّل خلال سنوات وحتى الآن، وتحدّث المطوّرون باستمرار حول متانتها وتوافقها مع الهواتف. CSS جيدة لكنها ليست أفضل من جافاسكربت. هناك بعض الأساطير حول CSS قادت المطوّرين بشكل استباقي لتبنّي هذا النظام (أي CSS) والتخلي عن كلٍّ من جافاسكربت والتحريك الخاصّ بها. ما يحيّر المطوّرين هو الاستخدام الفعّال لـ CSS، فبينما يقومون بإدارة التفاعل بين العناصر من داخل CSS، يُجبرون أنفسهم أيضًا على جعل مشروعهم متوافقًا مع Internet Explorer 8 و 9، وأخيرًا، يتجنّبون التحريك الجاهز الذي لا يتوفر إلا عن طريق جافاسكربت. يهدف هذا المقال لدحض بعض الأساطير حول CSS وكشف جميع المشكلات الأساسية التي بالكاد يتحدث الناس عنها بسبب إعجابهم بـ CSS. يهدف المقال إلى رفع معرفتك ووعيك بفوائد استخدام جافاسكربت، حتى يمكنك بسهولة التخلص من المواقف التي تثير غضبك. لذا، دون مزيد من الإطالة دعونا نتناقش حول كل منهم بالتفصيل. 1. jQueryدعونا نبدأ بالأساسيات، يتم الربط بين جافاسكربت ومكتبة jQuery بشكل خاطئ . فالتحريك المُصمَّم بجافاسكربت سريع ومرن، بينما المُصمَّم بـ jQuery بطيء. السبب أنه -وبرغم مواصفات jQuery القوية- إلّا أنها لم تهدف بشكل رئيسي لتنفيذ التحريك. هناك العديد من الأسباب لدعم هذا: لا يمكن لمكتبة jQuery ببساطة أن تتوقف عن تحطيم التنسيق (layout thrashing) نظرًا لهيكلتها البرمجية التي تخدم عددًا من الأغراض غير التحريك. هذا بشكل عام يسبب تقطّعًا في المراحل الأولى من التحريك.الذاكرة التي تستهلكها jQuery دومًا تُحفّز جمع القمامة (Garbage Collection) مما يؤدي إلى تجمّد التحريك. ونظرًا لـ جمع القمامة، يمكن للمرء أن يواجه تقطّعًا أثناء التحريك.تم تصميم jQuery لتستخدم set_interval() وليس طلب إطار الحركة (Request Animation Frame - RAF). عندما لا يكون طلب إطار الحركة موجودًا فيمكن أن ينتج عن ذلك تحريكات بعدد إطارات منخفض (جودة ودقة الحركة تعتمد على عدد الإطارات التي تظهر في الثانية، العدد المثالي هو 60 إطار في الثانية).2. فقر التحكم بالتدوير وتحديد الموقعمن الميزات الأساسية الضرورية أثناء تنفيذ التحريك استخدام المُتحكّمات لـ: التحريك animation، التدوير rotation، وتحديد المواقع positioning. في CSS، تم تكديس جميع هذه الدوالّ في خاصية معروفة هي tranform. هذه الخاصية تُسبب مشاكل عند تحريك شيء ما بطريقة فريدة عن طريق عنصر مشترك. على سبيل المثال، إن أردت تحريك “التدوير” rotation و”التكبير” scaling بشكل منفصل، وباستخدام أزمنة مختلفة، فهذا مُمكن فقط عن طريق جافاسكربت ﻷنها تُمكّنك من استخدام حِيل متنوعة، وهذه غير مسموحة في CSS. هذه إحدى مساوئ CSS. هي جيدة من أجل مشاريع تتطلب تحريكاتٍ بسيطة وليس من أجل المشاريع التي تتطلب اندماج تصميمٍ بتحريكاتٍ كبيرة. 3. الأداء مع مكتبتيّ Velocity وGSAPVelocity وGSAP هما المكتبتان الرائدتان والأكثر شعبية في جافاسكربت. كلاهما يعمل مع jQuery أو بدونها. عندما يتم استخدام أيّ من هاتين المكتبتين جنبًا إلى جنب مع jQuery فلا يحدث أي تدهورأو تباطؤ في الأداء لأنهما تعملان بشكل منفصل عن تحريكات jQuery الأساسية. ويمكن أيضًا استخدام هاتين المكتبتين بسهولة عندما لا تكون مكتبة jQuery موجودة في الصفحة. وهذا يبين بوضوح أنه بدلًا من ربط جميع أنواع استدعاءات التحريك في عنصر jQuery مشترك يمكنك بشكل مباشر تمرير العنصر المراد إلى استدعاء الحركة كما هو مبين أدناه. /* Working without jQuery */ Velocity(element, { opacity: 0.4 }, 900); // Velocity TweenMax.to(element, 1, { opacity: 0.4 }); // GSAP في المثال السابق، يمكنك ملاحظة أن Velocity تستخدم نفس الصيغة حتى عندما لا يتم استخدام jQuery. قامت فقط بإزاحة جميع العناصر تجاه اليمين لترك مساحة للعناصر المستهدفة. بالمقابل، في GSAP تم استخدام تصميم كائني التوجه (عن طريق استدعاء كائن يمثّل صنف Class) جنبًا إلى جنب مع دالّة بسيطة ثابتة. بهذه الطريقة المستخدم يملك تحكم كامل بعملية الحركة. 4. معامل وحدة معالجة الرسوم (GPU)عندما تكون وحدة معالجة رسوم GPU مُحسّنة بشكل كامل، عندها ستكون عظيمة لأداء مهام متنوعة كالتعامل مع مصفوفات التحويل transform والشفافية opacity، لهذا السبب أول ما تفعله جميع المتصفحات المتطورة هو تفريغ هذه المهام من وحدة المعالجة المركزية CPU إلى وحدة معالجة الرسوم GPU. الهدف الأساسي هو فصل جميع العناصر المتحركة إلى طبقات خاصة بها في وحدة معالجة الرسوم ﻷنه فور انتهاء النظام من إنشاء طبقات وحدة معالجة الرسوم لا يُظهر النظام أي اهتمام بتحريك البكسلات وجمعهم معًا. لهذا لا يوجد حاجة بتاتًا لحساب كل بكسل بشكل مستمر. بدلًا من ذلك يمكن تحريك بكسل واحد فوق الآخر وتوفير كثير من الوقت. ملاحظة: لا حاجة لإعطاء كل عنصر طبقته الخاصة نظرًا لذاكرة الفيديو المحدودة في وحدة معالجة الرسوم. فإذا نفدت الذاكرة سيفسد كل شيء. من ناحية أخرى، إذا قمتَ بتعريف التحريك في CSS عندئذ ستكون مهمة المتصفح أن يحدد طبقة وحدة معالجة الرسوم لكل عنصر وسيحصل انقسام بسبب ذلك. مع ذلك، يمكنك عمل هذا الأمر عن طريق جافاسكربت أيضًا. كل ما تحتاجه هو تحديد التحويل transform مع خاصية 3D (تمامًا مثل translate3d() و matrix3d()) لجعل المُتصفح يعلم عن عملية إنشاء طبقات وحدة معالجة الرسوم للعنصر المستهدف. لذا، فمن الواضح أن وحدة معالجة الرسوم لا توفّر زيادة السرعة لـ CSS فقط بل لجافاسكربت أيضًا. 5. قوة تحريك جافاسكربتلدى جافاسكربت كل الإمكانيات للفوز بمقارنة الأداء مع CSS. جافاسكربت هي أسرع. لكن إلى أي حدّ يمكن أن تكون أسرع؟ بدايةً هي مرنة بما فيه الكفاية لإنشاء عرض تحريك ثلاثيّ الأبعاد 3D ملفت للنظر، الذي يمكن أن تراه عبر WebGL. وجافاسكربت سريعة بشكلٍ كافٍ لبناء دعاية وسائط متعددة، والتي كان من الممكن تطويرها باستخدام Flash أو After Effects. وبالتأكيد بناء عالم افتراضي باستخدام جافاسكربت بمساعدة Canvas. بقدر ما تكون مكتبات التحريك هي المعنية في هذا المقال، فإن الحديث الآن عن توثيق مكتبتيّ Transit و Velocity غير مبرر على الإطلاق. لمزيد من التوضيح لهذه النقطة، قمنا بطرح قائمة تحسينات يمكن فقط للتحريك المبنيّ بجافاسكربت أن يؤديها: مزامنة DOMالتخزين المؤقت للخصائص عبر سلسلة من الاستدعاءات، للتخفيف من استعلامات DOMالتخزين المؤقت لنسب تحويل الواحداتخلاصةنجد بوضوح كيف أن النقاط المذكورة أعلاه تسلط الضوء على براعة التحريك المبنيّ على جافاسكربت بالمقارنة مع المبنيّ على CSS. ولكن هل هذا يعني أن تحريك CSS “سيّء”؟ بالتأكيد لا. هو جيّد لأداء تحريك بسيط. لكن لمرونة وقدرات فريدة أعلى، يجب أن تأخذ جافاسكربت بعين الاعتبار. ترجمة -وبتصرفّ- للمقال CSS Vs JavaScript Myths Fall to Pieces1 نقطة