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

البحث في الموقع

المحتوى عن 'ember'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

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

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

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

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

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

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 5 نتائج

  1. سنتعرف في هذا المقال على التوجيه Routing أو الترشيح المستند إلى عنوان URL كما يشار إليه في بعض الأحيان، والذي سنستخدمه لتوفير عنوان URL فريد لكل عرض من عروض المهام الثلاثة: "جميع المهام All" و"المهام النشطة Active" و"المهام المكتملة Completed"، كما سنتطرق إلى كيفية استكشاف الأخطاء وإصلاحها. المتطلبات الأساسية: الإلمام بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة استخدام سطر الأوامر أو الطرفية، إذ يُعَدّ فهم ميزات جافاسكربت الحديثة مثل الأصناف Classes والوحدات Modules وما إلى ذلك مفيدًا للغاية، لأن إطار العمل Ember يستخدمها بكثرة. الهدف: التعرف على كيفية تطبيق التوجيه في إطار العمل Ember، وتوفير مزيد من الموارد لتعلم إطار عمل Ember ومعلومات استكشاف الأخطاء وإصلاحها. الترشيح المستند إلى عنوان URL يأتي إطار عمل Ember مع نظام التوجيه ذي التكامل الوثيق مع عنوان URL الخاص بالمتصفح، إذ يجب عند كتابة تطبيقات الويب تمثيل الصفحة بعنوان URL بحيث إذا كانت الصفحة بحاجة إلى تحديث، فلن يُفاجَأ المستخدِم بحالة تطبيق الويب، وسيتمكّن من الانتقال مباشرةً إلى عروض التطبيق المهمة. لدينا حاليًا صفحة "جميع المهام All" إذ لن نطبّق ترشيحًا فيها في الوقت الحالي، لكن يجب إعادة تنظيمها قليلًا للتعامل مع عرض مختلف للمهام النشطة والمهام المكتملة، كما يحتوي تطبيق Ember على مسار تطبيق افتراضي مرتبط بالقالب app/templates/application.hbs الذي يُعَدّ نقطة الدخول إلى تطبيق قائمة المهام، لذلك يجب إجراء بعض التغييرات للسماح بالتوجيه Routing. إنشاء المسارات لننشئ ثلاثة مسارات جديدة هي: "Index" و "Active" و "Completed" من خلال إدخال الأوامر التالية في الطرفية ضمن المجلد الجذر لتطبيقك: ember generate route index ember generate route completed ember generate route active لا ينتج عن الأمرَين الثاني والثالث ملفات جديدةً فحسب، وإنما يُعدَّل الملف app/router.js الموجود مسبقًا الذي يحتوي على المحتويات التالية: import EmberRouter from '@ember/routing/router'; import config from './config/environment'; export default class Router extends EmberRouter { location = config.locationType; rootURL = config.rootURL; } Router.map(function() { this.route('completed'); this.route('active'); }); يتصرّف الملف router.js بوصفه خريطة موقع sitemap للمطورين ليتمكنوا من رؤية كيفية تنظيم التطبيق بأكمله بسرعة، كما أنه يخبر إطار العمل Ember بكيفية التفاعل مع مسارك عند تحميل بيانات عشوائية أو التعامل مع الأخطاء أثناء تحميل تلك البيانات أو تفسير الأجزاء الآلية لعنوان URL مثلًا، وبما أنّ بياناتنا ساكنة، فلن نصل إلى أيّ من هذه الميزات الرائعة، لكننا سنظل نتأكد من أنّ المسار يوفِّر الحد الأدنى من البيانات المطلوبة لعرض الصفحة. لم يضِف إنشاء المسار "Index" سطر تعريف مسار إلى الملف router.js، لأن "Index" هي كلمة خاصة تشير إلى المسار الافتراضي للتصيير والتحميل وغير ذلك كما هو الحال مع التنقل باستخدام عنوان URL وتحميل وحدة جافاسكربت JavaScript. يمكنك تعديل طريقتنا القديمة في تصيير تطبيق قائمة المهام من خلال استبدال الاستدعاء {{outlet}} باستدعاء المكون TodoList من قالب التطبيق ب، مما يعني تصيير أيّ مسار فرعي في المكان نفسه دون الانتقال إلى تبويب جديد. انتقل إلى الملف todomvc/app/templates/application.hbs وضَع مكان السطر التالي: <TodoList /> ما يلي: {{outlet}} يمكننا الآن إدخال استدعاء المكوّن TodoList في قوالب index.hbs و completed.hbs و active.hbs الموجودة أيضًا في مجلد القوالب. ضَع مكان السطر التالي: {{outlet}} ما يلي: <TodoList /> إذا جرّبت التطبيق مرةً أخرى وزرتَ أيًّا من المسارات الثلاثة: localhost:4200 localhost:4200/active localhost:4200/completed فسترى الشيء نفسه بالضبط، إذ سيصيَّر القالب الذي يتوافق مع المسار المحدد ("Active" أو "Completed" أو "Index") في كل عنوان URL للمكون <TodoList /‎>. يُحدَّد الموقع في الصفحة حيث يُصيَّر المكوّن <TodoList /‎> باستخدام {{ outlet }} في المسار الأب وهو في هذه الحالة application.hbs، ولدينا الآن مساراتنا في مكانها الصحيح، لكننا بحاجة إلى طريقة للتمييز بين كل من هذه المسارات لتظهِر ما يفترض منها أن تظهِره. ارجع مرةً أخرى إلى الملف todo-data.js الذي يحتوي مسبقًا على تابع جالب getter يعيد جميع المهام وتابع جالب آخر يعيد المهام غير المكتملة، ولكنه لا يحتوي على تابع جالب يعيد المهام المكتملة فقط، لذا لنضفه بعد التوابع الجالبة الموجودة مسبقًا: get completed() { return this.todos.filter(todo => todo.isCompleted); } النماذج يجب الآن إضافة نماذج Models إلى مسارات ملفات جافاسكربت للسماح بسهولة بإعادة مجموعات بيانات معينة لعرضها في تلك النماذج، إذ يُعَدّ النموذج model بأنه خطاف Hook دورة حياة تحميل بيانات، ولكن ليست قدرات النموذج مهمةً لنا في تطبيق TodoMVC، كما سنوفر الوصول إلى الخدمة كما فعلنا مع المكوّنات. نموذج المسار index عدِّل أولًا الملف todomvc/app/routes/index.js ليبدو كما يلي: import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default class IndexRoute extends Route { @service('todo-data') todos; model() { let todos = this.todos; return { get allTodos() { return todos.all; } } } } يمكننا الآن تعديل الملف todomvc/app/templates/index.hbs بحيث إذا تضمّن المكوّن <TodoList /‎>، فإنه يفعل ذلك صراحة مع النموذج المتاح، ويستدعي التابع الجالب allTodos()‎ للتأكد من ظهور جميع المهام. عدِّل السطر التالي في هذا الملف: <TodoList /> إلى ما يلي: <TodoList @todos={{ @model.allTodos }}/> نموذج المسار completed عدِّل الملف todomvc/app/routes/completed.js ليبدو كما يلي: import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default class CompletedRoute extends Route { @service('todo-data') todos; model() { let todos = this.todos; return { get completedTodos() { return todos.completed; } } } } يمكننا الآن تعديل الملف todomvc/app/templates/completed.hbs بحيث إذا تضمّن المكوّن ‎<TodoList /‎>‎، فإنه يفعل ذلك صراحةً مع النموذج المتاح، ويستدعي التابع الجالب completedTodos()‎ للتأكد من ظهور المهام المكتملة فقط. عدِّل السطر التالي في هذا الملف: <TodoList /> إلى ما يلي: <TodoList @todos={{ @model.completedTodos }}/> نموذج المسار active عدِّل الملف todomvc/app/routes/active.js ليبدو كما يلي: import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default class ActiveRoute extends Route { @service('todo-data') todos; model() { let todos = this.todos; return { get activeTodos() { return todos.incomplete; } } } } يمكننا الآن تعديل الملف todomvc/app/templates/active.hbs بحيث إذا تضمّن المكوّن <TodoList /‎>، فإنه يفعل ذلك صراحةً مع النموذج المتاح، ويستدعي التابع الجالب activeTodos()‎ للتأكد من ظهور المهام النشطة أو غير المكتملة فقط. عدِّل السطر التالي في هذا الملف: <TodoList /> إلى ما يلي: <TodoList @todos={{ @model.activeTodos }}/> لاحظ أننا نعيد كائنًا له تابع جالب بدلًا من كائن ساكن أو قائمة مهام ساكنة مثل this.todos.completed في خطافات نماذج المسار، والسبب في ذلك هو أننا نريد أن يكون للقالب مرجع آلي لقائمة المهام، فإذا أعدنا القائمة مباشرةً، فلن يُعاد حساب البيانات أبدًا، مما يؤدي إلى ظهور تنقلات فاشلة وعدم ترشيح فعلي، ويمكن إعادة البحث عن المهام من خلال تحديد تابع جالب في كائن الإعادة من بيانات النموذج بحيث تُمثَّل التعديلات التي أجريناها على قائمة المهام في القائمة المُصيَّرة. تشغيل روابط التذييل أصبحت وظائف المسار الآن في مكانها الصحيح، لكن لا يمكننا الوصول إليها من تطبيقنا، لذا لنفعِّل روابط التذييل بحيث يؤدي النقر عليها إلى الانتقال إلى المسارات المطلوبة. ارجع إلى الملف todomvc/app/components/footer.hbs وابحث عمّا يلي: <a href="#">All</a> <a href="#">Active</a> <a href="#">Completed</a> وعدِّله إلى ما يلي: <LinkTo @route='index'>All</LinkTo> <LinkTo @route='active'>Active</LinkTo> <LinkTo @route='completed'>Completed</LinkTo> يُعَدّ <LinkTo> بأنه مكوّن Ember مبني مسبقًا يعالِج جميع تغييرات الحالة عند التنقل بين المسارات، ويضبط الصنف active على أيّ رابط يطابق عنوان URL في حالة وجود رغبة في تنسيقه تنسيقًا مختلفًا عن الروابط غير النشطة. تحديث عرض المهام ضمن قائمة المهام أحد الأشياء الصغيرة الأخيرة التي نحتاج إلى إصلاحها هو أننا كنا ندخل سابقًا إلى خدمة todo-data مباشرةً ونكرّر جميع المهام ضمن الملف todomvc/app/components/todo-list.hbs كما يلي: {{#each this.todos.all as |todo| }} بما أننا نريد أن يعرض مكوّن قائمة المهام قائمةً مُرشَّحةً، فيجب تمرير وسيط إلى مكوِّن قائمة المهام يمثِّل قائمة المهام الحالية من todos كما يلي: {{#each @todos as |todo| }} يجب أن يحتوي تطبيقك الآن على روابط فعّالة في التذييل تعرض مسارات "Index" أو المسارات الافتراضية و"النشطة Active" و"المكتملة Completed". هناك الكثير مما يجب تنفيذه قبل أن يتطابق ما نفّذناه حتى الآن مع تطبيق TodoMVC الأصلي مثل تعديل المهام وحذفها واستمرارها عبر عمليات إعادة تحميل الصفحة، كما يمكنك مشاهدة تطبيق Ember المكتمل من خلال التحقق من مجلد التطبيق النهائي في مستودع شيفرة تطبيقنا للحصول عليها أو شاهد الإصدار المباشر. ادرس الشيفرة لمعرفة المزيد حول إطار عمل Ember، وراجع الفقرة التالية التي توفِّر مزيدًا من الموارد وبعض نصائح استكشاف الأخطاء وإصلاحها. استكشاف الأخطاء العامة وإصلاحها وبنى gotcha والمفاهيم الخاطئة كان آخر تحديث للقائمة التالية في شهر 6 من عام 2020. كيف يمكنني تنقيح الأخطاء التي يظهرها إطار العمل؟ توجد الإضافة ember-inspector بالنسبة للأشياء الخاصة بإطار العمل والتي تسمح بفحص ما يلي: المسارات Routes والمتحكِّمات Controllers. المكوِنات. الخدمات. الوعود Promises. البيانات وهي بيانات من واجهة برمجة تطبيقات بعيدة مثل ember-data افتراضيًا. معلومات الإهمال Deprecation Information. تصيير الأداء. اطّلع على أدوات المطوِّر التي تفيدك في تنقيح الأخطاء، وتعرّف على كيفية استخدام أدوات المطوِّر DevTools في كروم Chrome. بوجد ملفان رئيسيان من ملفات جافاسكربت هما: vendor.js و ‎{app-name}.js في أيِّ مشروع Ember افتراضي، ويُنشَآن هذان الملفان باستخدام خرائط الشيفرة البرمجية Sourcemaps، لذلك ستُحمَّل خريطة الشيفرة البرمجية وستُوضَع نقطة التوقف في شيفرة مُترجَمة مسبقًا لتسهيل الارتباط بشيفرة مشروعك باستخدام منقّح أخطاء عند فتح الملف vendor.js أو الملف ‎{app-name}.js للبحث عن الشيفرة البرمجية ذات الصلة. هل سأحتاج إلى واجهة ember-data المثبتة مسبقا؟ لن تحتاجها على الإطلاق، إذ تحل واجهة ember-data المشاكل الأكثر شيوعًا التي سيعمل بها أيّ تطبيق يتعامل مع البيانات بحيث يمكن تشغيل عميل بيانات واجهتك الأمامية، وهناك بديل شائع لأيّ عميل بيانات واجهة أمامية كامل الميزات هو Fetch API، إذ سيبدو المسار Route باستخدام fetch()‎ كما يلي باستخدام أنماط التصميم التي يوفرها إطار العمل: import Route from '@ember/routing/route'; export default class MyRoute extends Route { async model() { let response = await fetch('some/url/to/json/data'); let json = await response.json(); return { data: json }; } } لماذا لا يمكنني استخدام جافاسكربت فقط؟ هذا هو السؤال الأكثر شيوعًا الذي يسمعه مجتمع Ember من الأشخاص الذين لديهم خبرة سابقة في React، إذ يمكن استخدام صيغة JSX أو أيّ شكل آخر من أشكال إنشاء نموذج DOM، ولكن ليس هناك شيء قوي مثل نظام قوالب Ember، حيث يفرض الحد الأدنى منه قرارات معينة، ويسمح بشيفرة برمجية أكثر تناقسًا مع الحفاظ على القالب أكثر هيكلية بدلًا من ملئه بشيفرة برمجية حسب الرغبة. ما هي حالة المساعد mut؟ انتقل المساعد mut مع إطار العمل Ember عند انتقاله من البيانات ذات الاتجاهين إلى مجرى البيانات الأكثر شيوعًا والأسهل ذي الاتجاه الواحد، إذ يمكن عدّ المساعدmut بمثابة تحويل وقت البناء الذي يغلّف وسيطه بتابع ضابط setter، إذ يسمح استخدام المساعدmut بالتصريح عن دوال إعدادات القالب فقط كما يلي: <Checkbox @value={{this.someData}} @onToggle={{fn (mut this.someData) (not this.someData)}} /> بينما ستكون هناك حاجة إلى صنف مكوّن بدون استخدام المساعدmut: import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; export default class Example extends Component { @tracked someData = false; @action setData(newValue) { this.someData = newValue; } } سيُستدعَى هذا الصنف بعد ذلك في القالب كما يلي: <Checkbox @data={{this.someData}} @onChange={{this.setData}} /> يمكن أن يكون استخدام mut مرغوبًا نظرًا لاختصاره، ولكنه يحتوي على دلالات غريبة يمكن أن تتسبّب في الكثير من الارتباك لمعرفة المقصود منها. كانت هناك بعض الأفكار الجديدة التي وُضِعت معًا في شكل إضافات تستخدِم واجهات برمجة تطبيقات ember-set-helper و ember-box، ويحاول كلاهما حل مشاكل mut من خلال تقديم مفاهيم أوضح، وتجنب تحولات وقت البناء وسلوك آلة Glimmer الافتراضية الضمني. باستخدام ember-set-helper: <Checkbox @value={{this.someData}} @onToggle={{set this "someData" (not this.someData)}} /> باستخدام ember-box: {{#let (box this.someData) as |someData|}} <Checkbox @value={{unwrap someData}} @onToggle={{update someData (not this.someData)}} /> {{/let}} لا تُعَدّ أيّ من هذه الحلول شائعةً بين أعضاء المجتمع، ولا يزال الأشخاص يحاولون اكتشاف واجهة برمجة تطبيقات مريحة وبسيطة لضبط البيانات في سياق القالب فقط دون أصناف جافاسكربت الداعمة. ما هو الغرض من المتحكمات؟ المتحكِّمات Controllers هي أنماط مفردة Singletons يمكن أن تساعد في إدارة تصيير السياق الخاص بالمسار النشط، وتعمل إلى حد كبير مثل أصناف جافاسكربت الداعمة للمكوّن، والمتحكِّمات هي -من شهر 1 عام 2020- الطريقة الوحيدة لإدارة محدّدات استعلام عناوين URL، إذ يجب أن تكون المتحكِّمات خفيفةً إلى حد ما في مسؤولياتها وفي تفويض المكوّنات والخدمات حيثما أمكن ذلك. ما هو الغرض من المسارات؟ يمثِّل المسار Route جزءًا من عنوان URL عندما ينتقل المستخدِم من مكان إلى آخر في التطبيق، فالمسار له المسؤوليات التالية فقط: تحميل الحد الأدنى من البيانات المطلوبة لتصيير المسار أو عرض الشجرة الفرعية. يُعَدّ بوابة الوصول إلى المسار وإعادة التوجيه إذا لزم الأمر. التعامل مع حالات التحميل والخطأ في الحد الأدنى من البيانات المطلوبة. يحتوي المسار على ثلاثة خطّافات لدورة الحياة فقط وجميعها اختيارية وهي: beforeModel: بوابة الوصول إلى المسار. model: مكان تحميل البيانات. afterModel: للتحقق من الوصول. يتمتع المسار بالقدرة على التعامل مع الأحداث الشائعة الناتجة عن إعداد الخطاف model: loading: ما يجب تطبيقه عند تحميل الخطّاف model. error: ما يجب فعله عند حدوث خطأ في الخطّاف model. يمكن لكل من loading و error تصيير القوالب الافتراضية بالإضافة إلى القوالب المخصَّصة المحددة في مكان آخر في التطبيق، مما يوحِّد حالات التحميل أو حالات الخطأ، كما يمكن العثور على مزيد من المعلومات حول ما يمكن للمسار تنفيذه في توثيق واجهة برمجة التطبيقات API. أخيرًا، إذا احتجت إلى أي مساعدة، فأضف سؤالك ضمن قسم الأسئلة والأجوبة في أكاديمية حسوب أو ضمن مجتمع البرمجة في حسوب IO وستصل إلى إجابتك من مجتمع المطورين العرب. ترجمة -وبتصرّف- للمقالين Routing in Ember وEmber resources and troubleshooting. اقرأ أيضًا المقال السابق: تنفيذ التفاعل في تطبيق Ember: وظيفة التذييل والعرض الشرطي مقدمة إلى إطار العمل Ember بنية تطبيق إطار العمل Ember وتقسيمها إلى مكونات
  2. حان الوقت الآن لمعالجة وظيفة التذييل Footer في تطبيقنا، إذ سنحدِّث عدّاد المهام لإظهار العدد الصحيح للمهام التي يجب إكمالها، وسنطبّق التنسيق بصورة صحيحة على المهام المكتملة من خلال تحديد مربع الاختيار، كما سنفعِّل زر "مسح المهام المكتملة Clear completed"، وسنتعرّف على استخدام التصيير أو العرض الشرطي Conditional Rendering في قوالبنا (التصيير والعرض والإخراج هي مترادفات لكلمة rendering). المتطلبات الأساسية: الإلمام بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة استخدام سطر الأوامر أو الطرفية، إذ يُعَدّ فهم ميزات جافاسكربت الحديثة مثل الأصناف Classes والوحدات Modules وما إلى ذلك مفيدًا للغاية، لأن إطار العمل Ember يستخدمها بكثرة. الهدف: مواصلة تعلّم أصناف المكوّنات من خلال التعرّف على التصيير الشرطي وتفعيل بعض وظائف التذييل. توصيل السلوك بالتذييل يجب تطبيق الوظائف الثلاث التالية لكي يعمل التذييل: عدّاد المهام المعلَّقة. مرشحات لجميع المهام والمهام النشطة والمهام المكتملة. زر لمسح المهام المكتملة. أولًا، يجب إنشاء صنف Class للتذييل بما أننا نحتاج إلى الوصول إلى الخدمة من مكوّن التذييل، لذلك أدخِل الأمر التالي في الطرفية: ember generate component-class footer ثانيًا، ابحث بعد ذلك عن الملف todomvc/app/components/footer.js وعدّله إلى ما يلي: import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; export default class FooterComponent extends Component { @service('todo-data') todos; } ثالثًا، يجب الآن العودة إلى الملف todo-data.js وإضافة بعض الوظائف التي ستسمح بإعادة عدد المهام غير المكتملة لمعرفة عدد المهام المتبقية، ووظيفة مسح المهام المكتملة من القائمة التي يحتاجها زر "مسح المهام المكتملة Clear completed"، لذلك أضِف في الملف todo-data.js التابع الجالب Getter التالي بعد الجالب all()‎ الموجود سابقًا لتحديد المهام غير المكتملة: get incomplete() { return this.todos.filterBy('isCompleted', false); } يمكننا باستخدام التابع Array.Proxy.filterBy()‎ في Ember ترشيح الكائنات في المصفوفة بسهولة بناءً على شروط مساواةٍ بسيطة، إذ نريد في جزء الشيفرة السابق الحصول على جميع عناصر المهام عندما تكون الخاصية isCompleted مساوية للقيمة false، وسيُعاد حساب هذا التابع الجالب عندما تتغير قيمة الكائن في المصفوفة لأن الخاصية isCompleted مُميَّزة بالمزخرِف ‎@tracked في الكائن Todo. رابعًا، أضف بعد ذلك ما يلي بعد الدالة add(text)‎ الموجودة مسبقًا: @action clearCompleted() { this.todos = this.incomplete; } يُعَدّ ذلك رائعًا لمسح المهام، إذ نحتاج فقط إلى ضبط المصفوفة todos لتساوي قائمة المهام غير المكتملة. خامسًا، أخيرًا، يجب الاستفادة من هذه الوظيفة الجديدة في قالب footer.hbs، لذلك انتقل إلى هذا الملف الآن. سادسًا، ضَع أولًا مكان السطر التالي: <strong>0</strong> todos left ما يلي، إذ يُملَأ عدد المهام غير المكتملة بطول المصفوفة incomplete: <strong>{{this.todos.incomplete.length}}</strong> todos left سابعًا، ثم ضع مكان السطر التالي: <button type="button" class="clear-completed"> ما يلي: <button type="button" class="clear-completed" {{on 'click' this.todos.clearCompleted}}> إذا نقرتَ على الزر الآن، فسيُشغَّل الإجراء clearCompleted()‎ الذي أضفناه سابقًا، ولكن إذا حاولت النقر على زر "مسح المهام المكتملة Clear Completed"، فلن يبدو التطبيق أنه يفعل أيّ شيء بسبب عدم وجود طريقة لإكمال المهام حاليًا، كما يجب توصيل القالب todo.hbs بالخدمة، بحيث يؤدي تحديد مربع الاختيار المتعلق به إلى تغيير حالة كل مهمة. مشكلة كتابة todos بدلا من todo لدينا مشكلة صغيرة أخرى نتعامل معها، إذ تشير العبارة "todos left" إلى وجود عدد من المهام المتبقية بالرغم من وجود مهمة واحدة متبقية أحيانًا، وهذا سيء قواعديًا. يمكن حل هذه المشكلة من خلال تعديل هذا الجزء من القالب ليحتوي على التصيير الشرطي، إذ يمكنك في Ember تصيير أجزاء من القالب شرطيًا باستخدام المحتوى الشرطي مثل الكتلة البسيطة التالية: {{#if this.thingIsTrue}} Content for the block form of "if" {{/if}} ضع مكان الجزء التالي من footer.hbs: <strong>{{this.todos.incomplete.length}}</strong> todos left ما يلي: <strong>{{this.todos.incomplete.length}}</strong> {{#if this.todos.incomplete.length === 1}} todo {{else}} todos {{/if}} left سيؤدي ذلك إلى إعطاء خطأ، ولكن لا تستطيع عبارات if البسيطة هذه في Ember حاليًا اختبار تعبير معقد مثل الموازنة، وإنما تستطيع اختبار قيمة الصواب أو الخطأ فقط، لذلك يجب إضافة جالب getter إلى الملف todo-data.js لإعادة النتيجة this.incomplete.length === 1 ثم استدعاؤها في القالب. أضف الجالب الجديد الآتي إلى الملف todo-data.js بعد التوابع الجالبة الموجودة مسبقًا مباشرةً، ولاحظ أننا نحتاج إلى this.incomplete.length وليس this.todos.incomplete.length لأننا نطبّق ذلك ضمن الخدمة حيث يتوفر الجالب incomplete()‎ مباشرةً، كما أنّ محتويات الخدمة متوفرة في القالب مثل المهام todos عبر التعليمة ‎@service('todo-data') todos;‎ ضمن صنف التذييل، وبالتالي سيكون this.todos.incomplete.length هناك. get todoCountIsOne() { return this.incomplete.length === 1; } ارجع بعد ذلك إلى footer.hbs وعدِّل قسم القالب السابق الذي عدّلناه إلى ما يلي: <strong>{{this.todos.incomplete.length}}</strong> {{#if this.todos.todoCountIsOne}} todo {{else}} todos {{/if}} left احفظ الملف واختبره، وسترى الكلمة الصحيحة المُستخدَمة عندما يكون لديك عنصر واحد لتنفيذه. لاحظ صيغة كتلة if في Ember، ويمكنك استخدام الشكل المضمَّن التالي: {{if this.todos.todoCountIsOne "todo" "todos"}} استكمال المهام يجب استخدام صنف للوصول إلى الخدمة كما هو الحال مع المكونات الأخرى. إنشاء الصنف todo أولًا، شغّل الأمر التالي في الطرفية: ember generate component-class todo ثانيًا، انتقل الآن إلى الملف todomvc/app/components/todo.js وعدّل محتوياته لتبدو كما يلي لمنح المكوّن todo إمكانية الوصول إلى الخدمة: import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; export default class TodoComponent extends Component { @service('todo-data') todos; } ثالثًا، ارجع مرةً أخرى إلى ملف الخدمة todo-data.js وأضف الإجراء التالي بعد الإجراءات السابقة مباشرةً، مما سيسمح بتبديل حالة الاكتمال لكل مهمة: @action toggleCompletion(todo) { todo.isCompleted = !todo.isCompleted; } تحديث القالب لإظهار الحالة المكتملة أخيرًا، سنعدّل القالب todo.hbs بحيث ترتبط قيمة مربع الاختيار بالخاصية isCompleted في المهمة، حيث يُستدعَى التابع toggleCompletion()‎ في خدمة المهمة عند التعديل. أولًا، ابحث أولًا عن السطر التالي في الملف todo.hbs: <li> وضَع مكانه ما يلي، إذ ستلاحظ أننا نستخدم المحتوى الشرطي لإضافة قيمة الصنف إذا كان ذلك مناسبًا: <li class="{{ if @todo.isCompleted 'completed' }}"> ثانيًا، ابحث بعد ذلك عمّا يلي: <input aria-label="Toggle the completion of this todo" class="toggle" type="checkbox" > وضَع مكانه ما يلي: <input class="toggle" type="checkbox" aria-label="Toggle the completion of this todo" checked={{ @todo.isCompleted }} {{ on 'change' (fn this.todos.toggleCompletion @todo) }} > ملاحظة: يستخدِم جزء الشيفرة السابق كلمةً مفتاحيةً جديدةً خاصةً بإطار عمل Ember هي fn التي تسمح بالتطبيق الجزئي Partial Application، وهو مشابه للتابع bind لكنه لا يغير سياق الاستدعاء، ويكافئ استخدام التابع bind مع الوسيط الأول null. أعِد تشغيل خادم التطوير وانتقل إلى المضيف المحلي localhost:4200 مرةً أخرى، وسترى أنه لدينا عدّاد "المهام المتبقية todos left" وزر "المسح Clear": يمكن أن تسأل نفسك لماذا لا نطبّق التبديل على المكوِّن فقط؟ نظرًا لأن الدالة قائمة بذاتها ولا تحتاج على الإطلاق إلى أيّ شيء من الخدمة، وبما أننا في النهاية سنرغب في الاستمرار أو مزامنة جميع تغييرات قائمة المهام مع التخزين المحلي (اطّلع على الإصدار الأخير من التطبيق)، فستكون جميع عمليات تغيير الحالة المستمرة في المكان نفسه. الخلاصة يمكننا الآن وضع علامة على المهام المكتملة ومسحها أيضًا، والشيء الوحيد المتبقي لتفعيل التذييل هو عمليات ترشيح "جميع المهام All" و"المهام النشطة Active" و"المهام المكتملة Completed"، إذ سنطبّق ذلك في المقال التالي باستخدام التوجيه Routing. ترجمة -وبتصرّف- للمقال Ember Interactivity: Footer functionality, conditional rendering. اقرأ أيضًا المقال السابق: تنفيذ التفاعل في تطبيق Ember: الأحداث والأصناف والحالة بنية تطبيق إطار العمل Ember وتقسيمها إلى مكونات مقدمة إلى إطار العمل Ember
  3. سنبدأ في هذا المقال بإضافة بعض التفاعل إلى تطبيقنا مما يوفر القدرة على إضافة وعرض عناصر مهام جديدة، كما سنتعرّف على استخدام الأحداث في إطار العمل Ember، وإنشاء أصناف مكوّنات لتحتوي على شيفرة جافاسكربت JavaScript للتحكم بالميزات التفاعلية وإعداد خدمة لتتبّع حالة بيانات تطبيقنا. المتطلبات الأساسية: الإلمام بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة استخدام سطر الأوامر أو الطرفية، إذ يُعَدّ فهم ميزات جافاسكربت الحديثة مثل الأصناف Classes، والوحدات Modules، وما إلى ذلك مفيدًا للغاية لأن إطار العمل Ember يستخدمها بكثرة. الهدف: معرفة كيفية إنشاء أصناف المكوّنات واستخدام الأحداث للتحكم في التفاعل وتتبع حالة التطبيق باستخدام خدمة. إضافة التفاعل لدينا الآن نسخة من تطبيق قائمة المهام todo app مقسَّمة إلى مكوّنات ومُعاد بناؤها، ولنتعرَّف على كيفية إضافة التفاعل الذي نحتاجه ليعمل التطبيق، إذ يجب التصريح عن أهداف ومسؤوليات كل مكوّن عند البدء في التفكير في التفاعل كما سنوضّح فيما يلي، ثم سنوجّهك لتتعلم كيفية تنفيذ ذلك. إنشاء المهام نريد أن نتمكن من إرسال المهمة المكتوبة في حقل إدخال المهام عندما نضغط على مفتاح Enter لتظهر في قائمة المهام، ويجب أن نكون قادرين على التقاط النص المكتوب في حقل الإدخال لتعرف شيفرة جافاسكربت ما كتبناه، كما يمكننا حفظ مهامنا وتمرير هذا النص إلى مكوّن قائمة المهام لعرضه، ويمكننا التقاط الحدث keydown باستخدام المُعدِّل on الذي يُعَدّ صيغةً مبسَّطةً في Ember للتابعَين addEventListener و removeEventListener. أضف السطر الجديد الموضَّح أدناه إلى الملف header.hbs: <input class='new-todo' aria-label='What needs to be done?' placeholder='What needs to be done?' autofocus {{on 'keydown' this.onKeyDown}} > توضَع هذه السمة الجديدة بين أقواس مزدوجة معقوصة، ويدل ذلك على أنها جزء من صيغة قالب آلي في إطار عمل Ember، فالوسيط الأول المُمرَّر إلى on هو نوع الحدث الذي يجب الاستجابة له keydown، والوسيط الأخير هو معالِج الحدث أي الشيفرة المُشغَّلة استجابةً لإطلاق الحدث keydown، في حين تشير الكلمة المفتاحية this إلى سياق Context أو نطاق Scope المكوّن الذي سيختلف بين مكوّن وآخر. يمكننا تحديد ما هو متاح ضمن this من خلال إنشاء صنف مكوّن ليتماشى مع مكوّنك، وهو صنف بلغة جافاسكربت الصرفة Vanilla JavaScript وليس له معنًى خاصًا في إطار عمل Ember باستثناء وراثة أو توسعة الصنف الأب Component. يمكنك إنشاء الصنف header ليتوافق مع مكوّن الترويسة من خلال كتابة الأمر التالي في الطرفية: ember generate component-class header مما يؤدي إلى إنشاء ملف الصنف الفارغ التالي في الملف todomvc/app/components/header.js: import Component from '@glimmer/component'; export default class HeaderComponent extends Component { } سننفّذ في هذا الملف شيفرة معالج الحدث، لذلك عدّل محتواه إلى ما يلي: import Component from '@glimmer/component'; import { action } from '@ember/object'; export default class HeaderComponent extends Component { @action onKeyDown({ target, key }) { let text = target.value.trim(); let hasValue = Boolean(text); if (key === 'Enter' && hasValue) { alert(text); target.value = '' } } } يُعَدّ المزخرِف ‎@action الشيفرة الوحيدة الخاصة بإطار العمل Ember هنا بغض النظر عن وراثة الصنف الأب Component والعناصر الخاصة بإطار العمل Ember التي نستوردها باستخدام صيغة وحدة جافاسكربت، بينما باقي الملف مكتوب بلغة جافاسكربت الصرفة Vanilla JavaScript ويمكن أن يعمل في أيّ تطبيق آخر، كما يصرِّح المزخرِف ‎@action عن أن الدالة هي إجراء action، مما يعني أنها نوع من الدوال التي ستُستدعَى من حدث وقع في القالب، كما أنّ ‎@action يربط this الخاص بالدالة بنسخة من الصنف. ملاحظة: يُعَدّ المزخرِف Decorator دالة تغليف تغلِّف وتستدعي دوالًا أو خاصيات أخرى مما يوفر وظائفًا إضافيةً، إذ يشغّل المزخرِف ‎@tracked مثلًا الشيفرة المُطبَّقة عليه، ويتتبّعه ويحدّث التطبيق تلقائيًا عند تغيير القيم. عُد إلى تبويب متصفحك مع تشغيل التطبيق، إذ يمكننا كتابة ما نريد وستظهر رسالة تنبيه تخبرنا بما كتبناه بالضبط عندما نضغط على مفتاح Enter. نحتاج الآن لمكان لتخزين المهام لتتمكن المكوّنات الأخرى من الوصول إليها. تخزين المهام باستخدام خدمة يملك إطار عمل Ember إدارة حالة مبنية مسبقًا على مستوى التطبيق يمكننا استخدامها لإدارة تخزين مهامنا، والسماح لكل مكوّن من مكوّناتنا الوصول إلى البيانات من تلك الحالة على مستوى التطبيق، إذ يستدعي إطار Ember خدمات البناء التي تبقى قيد التشغيل طوال عُمر الصفحة، إذ سيؤدي تحديث الصفحة إلى مسحها. شغّل الأمر التالي في الطرفية لإنشاء خدمة لتخزين بيانات قائمة المهام: ember generate service todo-data يعطي تشغيل الأمر السابق خرجًا يشبه الخرج التالي: installing service create app/services/todo-data.js installing service-test create tests/unit/services/todo-data-test.js مما يؤدي إلى إنشاء الملف todo-data.js ضمن المجلد todomvc/app/services لاحتواء خدمتنا، كما يحتوي هذا الملف في البداية على عبارة استيراد وصنف فارغ كما يلي: import Service from '@ember/service'; export default class TodoDataService extends Service { } يجب أولًا تتبّع كل من نص المهمة وما إذا كانت مكتملة أم لا، لذا أضف تعليمة الاستيراد التالية بعد تعليمة الاستيراد الموجودة مسبقًا: import { tracked } from '@glimmer/tracking'; أضف الصنف التالي بعد السطر السابق الذي أضفته: class Todo { @tracked text = ''; @tracked isCompleted = false; constructor(text) { this.text = text; } } يمثل الصنف السابق مهمَّة، لأنه يحتوي على الخاصية ‎@tracked text التي تحتوي على نص المهمَّة، ويحتوي على الخاصية ‎@tracked isCompleted التي تحدِّد ما إذا كانت المهام مكتملةً أم لا، فإذا أنشأنا نسخةً من هذا الصنف، فسيكون للكائن Todo قيمة text أولية تساوي النص المعطَى له عند إنشائه، وتُعطَى الخاصية isCompleted القيمة false. الجزء الوحيد الخاص بإطار عمل Ember من هذا الصنف هو المزخرِف ‎@tracked الذي يرتبط بنظام التفاعل ويسمح لإطار Ember بتحديث ما تراه في تطبيقك تلقائيًا إذا تغيرت الخاصيات المُتتبَّعة tracked، وحان الوقت الآن لإضافة شيء ما إلى جسم الخدمة، لذا أضِف أولًا تعليمة استيراد import أخرى بعد التعليمة السابقة لإتاحة الإجراءات actions ضمن الخدمة: import { action } from '@ember/object'; عدّل الكتلة export default class TodoDataService extends Service { … }‎ كما يلي: export default class TodoDataService extends Service { @tracked todos = []; @action add(text) { let newTodo = new Todo(text); this.todos = [...this.todos, newTodo]; } } ستحتفظ الخاصية todos في الخدمة بقائمة مهامنا الموجودة ضمن مصفوفة، وسنميّزها بالمزخرِف ‎@tracked لأننا نريد تحديث واجهة المستخدِم أيضًا عند تحديث قيمة الخاصية todos. يُضاف المزخرِف ‎@action إلى الدالة add()‎ التي يستدعيها القالب لربطها بنسخة الصنف. يمكن أن يكون ذلك مألوفًا في لغة جافاسكربت، ولكن لاحظ استدعاء التابع pushObject()‎ في المصفوفة todos، والسبب أن إطار عمل Ember يوسّع نموذج المصفوفات في لغة جافاسكربت افتراضيًا، مما يمنحنا توابعًا ملائمة لضمان معرفة نظام التعقّب في إطار Ember بهذه التغييرات. هناك العشرات من هذه التوابع مثل pushObject()‎ أو insertAt()‎ أو popObject()‎ التي يمكن استخدامها مع أيّ نوع وليس مع الكائنات فقط. يمنحنا التابع ArrayProxy الخاص بإطار عمل Ember توابعًا سهلة الاستخدام مثل isAny()‎ وfindBy()‎ وfilterBy()‎ لتسهيل الأمور. استخدام الخدمة من مكون الترويسة يمكننا الآن بعد أن تحديد طريقة لإضافة المهام التفاعل مع هذه الخدمة من مكوّن الإدخال في الملف header.js لبدء إضافتها فعليًا، إذ يجب أولًا حقن الخدمة في القالب باستخدام المزخرِف ‎@inject الذي سنعيد تسميته إلى ‎@service. أضف تعليمة الاستيراد التالية إلى الملف header.js بعد تعليمتَي الاستيراد الموجودتَين مسبقًا: import { inject as service } from '@ember/service'; يمكننا الآن توفير الخدمة todo-data ضمن الصنف HeaderComponent عبر الكائن todos باستخدام المزخرِف ‎@service، لذلك أضف السطر التالي بعد سطر التصدير export‎ الأول مباشرةً: @service('todo-data') todos; يمكن الآن استبدال سطر النص البديل alert(text);‎ باستدعاء الدالة add()‎ الجديدة كما يلي: this.todos.add(text); إذا جربنا ذلك في تطبيق المهام في متصفحنا من خلال كتابة الأمر npm start ثم الانتقال إلى المضيف المحلي localhost:4200، فلن يحدث أيّ شيء بعد الضغط على مفتاح Enter، إذ يُعَدّ بناء التطبيق بدون أيّ أخطاء علامةً جيدةً، ولكن يمكننا رؤية إضافة مهامنا باستخدام الفاحص Ember Inspector كما يلي: عرض المهام يجب أن تكون هناك طريقة لوضع المهام التي ننشئها فعليًا مكان مهامنا الساكنة "Buy Movie Tickets"، إذ يجب في المكوّن TodoList إخراج المهام من الخدمة وتصيير Render المكوّن Todo لكل مهمة، كما يمكن استعادة المهام من الخدمة، ولكن يحتاج المكوّن TodoList أولًا إلى صنف داعم للمكوّن لاحتواء هذه الوظيفة، لذلك اضغط على الاختصار Ctrl + C لإيقاف خادم التطوير وأدخِل الأمر التالي في الطرفية: ember generate component-class todo-list يؤدي ذلك إلى إنشاء صنف المكوّن الجديد في المجلد todomvc/app/components/todo-list.js. املأ هذا الملف بالشيفرة التالية بحيث يمكن لقالبنا الوصول إلى الخدمة todo-data باستخدام الخاصية todos، ويمكن الوصول إليها باستخدام this.todos ضمن كل من الصنف والقالب: import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; export default class TodoListComponent extends Component { @service('todo-data') todos; } تتمثّل إحدى المشاكل هنا في أن الخدمة تسمَّى todos وتُسمَّى قائمة المهام todos أيضًا، لذلك يمكننا حاليًا الوصول إلى البيانات باستخدام this.todos.todos. لا يُعَد هذا أمرًا سهلًا، لذلك سنضيف تابعًا جالبًا getter إلى الخدمة this.todos.todos بالاسم all سيمثِّل جميع المهام. ارجع إلى الملف todo-data.js وأضِف ما يلي بعد التعليمة ‎@tracked todos = [];‎: get all() { return this.todos; } يمكننا الآن الوصول إلى البيانات باستخدام this.todos.all، إذ يُعَدّ ذلك أسهل. انتقل إلى المكوّن todo-list.hbs، وضع مكان استدعاءات المكوّن الساكنة التالية: <Todo /> <Todo /> كتلة ‎#each الآلية، وهي صيغة مُبسطَّة من تابع جافاسكربت forEach()‎، إذ تنشئ كتلة ‎#each المكوّنَ <Todo /‎> لكل مهمة متوفرة في قائمة المهام التي يعيدها التابع الجالب all()‎ الخاص بالخدمة: {{#each this.todos.all as |todo|}} <Todo @todo={{todo}} /> {{/each}} لنتعرّف على محتويات الشيفرة السابقة: this: سياق التصيير أو نسخة المكوّن. todos: خاصية this التي عرّفناها في المكوّن todo-list.js باستخدام التعليمة ‎@service('todo-data') todos;‎، وهي مرجع إلى الخدمة todo-data، مما يسمح بالتفاعل مع نسخة الخدمة مباشرةً. all: جالب الخدمة todo-data الذي يعيد جميع المهام. جرّب تشغيل الخادم مرةً أخرى وانتقل إلى التطبيق، وستجده يعمل، ولكن كلما أدخلت عنصر مهمة جديد، فسيظهر عنصر قائمة جديد تحت حقل إدخال النص، وستظهر العبارة "Buy Movie Tickets" دائمًا للأسف، لأن عنوان النص في كل عنصر قائمة مضمَّنٌ في ذلك النص كما هو موضَّح في الملف todo.hbs: <label>Buy Movie Tickets</label> عدِّل السطر السابق كما يلي لاستخدام الوسيط ‎@todo الذي سيمثل المهمة التي مررناها إلى المكوّن عند استدعائه ضمن الملف todo-list.hbs في السطر <Todo @todo={{todo}} /‎>: <label>{{@todo.text}}</label> جرّبه مرةً أخرى، ويجب أن تجد الآن أنّ النص المُرسَل من حقل الإدخال <input> يظهر بصورة صحيحة في واجهة المستخدِم كما يلي: الخلاصة يمكننا الآن إضافة عناصر المهمات إلى تطبيقنا، كما يمكن تتبّع حالة البيانات باستخدام الخدمة، وسننتقل في المقال التالي إلى تشغيل وظائف التذييل Footer بما في ذلك عدّاد المهام، كما سنتعرّف على التصيير الشرطي وتصميم المهام بصورة صحيحة عند تحديدها، وسنفعّل زر "مسح المهام المكتملة Clear completed". ترجمة -وبتصرّف- للمقال Ember interactivity: Events, classes and state. اقرأ أيضًا المقال السابق: بنية تطبيق إطار العمل Ember وتقسيمها إلى مكونات مقدمة إلى إطار العمل Ember
  4. سنخطط في هذا المقال بنية تطبيق TodoMVC في إطار العمل Ember، وسنضيف توصيف HTML له، ثم سنقسّم بنية HTML إلى مكونات. المتطلبات الأساسية: الإلمام بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة استخدام سطر الأوامر أو الطرفية. يُعَد فهم ميزات جافاسكربت الحديثة مثل الأصناف Classes والوحدات Modules وما إلى ذلك مفيدًا للغاية، لأن إطار العمل Ember يستخدِمها بكثرة. الهدف: تعلّم كيفية إنشاء بنية تطبيق Ember، ثم تقسيم هذه البنية إلى مكونات. التخطيط لتصميم تطبيق TodoMVC أنشأنا في المقال السابق مشروع Ember جديد ثم أضفنا وضبطنا أنماط CSS، وسنضيف الآن توصيف HTML وسنخطط بنية ودلالات تطبيق TodoMVC. يُعَدّ توصيف HTML لصفحة هبوط تطبيقنا مُعرَّفًا في المسار app/templates/application.hbs، وهو موجود مسبقًا وتبدو محتوياته حاليًا كما يلي: ‏{{!-- يعرض المكون التالي رسالة ترحيب‫ Ember الافتراضية. --}} <WelcomePage /> {{!-- لا تتردد في إزالتها --}} {{outlet}} المكوّن <WelcomePage /‎> هو مكون توفّره إضافة Ember التي تصيِّر Render صفحة الترحيب الافتراضية التي رأيناها في المقال السابق عندما انتقلنا لأول مرة إلى الخادم على المضيف المحلي localhost:4200، لكننا لا نريد ذلك، وإنما نريد أن يحتوي هذا المكون على بنية تطبيق TodoMVC، لذلك احذف محتويات الملف application.hbs واستبدلها بما يلي: <section class="todoapp"> <h1>todos</h1> <input class="new-todo" aria-label="What needs to be done?" placeholder="What needs to be done?" autofocus > </section> احفظ الملف application.hbs، إذ سيَعيد خادم التطوير الذي شغّلته سابقًا بناء التطبيق وتحديث المتصفح تلقائيًا، أي يجب أن يبدو الخرج المُصيَّر الآن كما يلي: لا يتطلب الأمر كثيرًا من الجهد لجعل توصيف HTML يبدو مثل تطبيق قائمة مهام كامل الميزات. عدِّل الملف application.hbs مرةً أخرى ليكون محتواه على النحو التالي: <section class="todoapp"> <h1>todos</h1> <input class="new-todo" aria-label="What needs to be done?" placeholder="What needs to be done?" autofocus > <section class="main"> <input id="mark-all-complete" class="toggle-all" type="checkbox"> <label for="mark-all-complete">Mark all as complete</label> <ul class="todo-list"> <li> <div class="view"> <input aria-label="Toggle the completion of this todo" class="toggle" type="checkbox" > <label>Buy Movie Tickets</label> <button type="button" class="destroy" title="Remove this todo" ></button> </div> <input autofocus class="edit" value="Todo Text"> </li> <li> <div class="view"> <input aria-label="Toggle the completion of this todo" class="toggle" type="checkbox" > <label>Go to Movie</label> <button type="button" class="destroy" title="Remove this todo" ></button> </div> <input autofocus class="edit" value="Todo Text"> </li> </ul> </section> <footer class="footer"> <span class="todo-count"> <strong>0</strong> todos left </span> <ul class="filters"> <li> <a href="#">All</a> <a href="#">Active</a> <a href="#">Completed</a> </li> </ul> <button type="button" class="clear-completed"> Clear Completed </button> </footer> </section> يجب أن يكون الخرج المُصيَّر الآن على النحو التالي: يبدو التطبيق مكتملًا، ولكن تذكّر أنه الآن مجرد نموذج أولي ساكن، لذلك يجب تقسيم توصيف HTML إلى مكونات آلية، إذ سنحوّله لاحقًا إلى تطبيق تفاعلي بالكامل. إذا نظرنا إلى الشيفرة الموجودة بجوار تطبيق المهام المُصيَّر في الشكل التالي، فهناك طرق متعددة يمكن من خلالها تحديد كيفية تقسيم واجهة المستخدِم UI، ولكن لنخطّط الآن لتقسيم توصيف HTML إلى المكونات التالية: مجموعات المكونات هي كما يلي: حقل الإدخال الرئيسي new-todo: باللون الأحمر في الشكل السابق. الجسم Body الذي يحتوي على قائمة المهام والزر الذي يضع علامة على جميع المهام المكتملة mark-all-complete: باللون الأرجواني في الشكل السابق. الزر mark-all-complete المميز بوضوح للأسباب التي سنوضّحها لاحقًا: باللون الأصفر في الشكل السابق. كل مهمة هي مكوّن لوحده: باللون الأخضر في الشكل السابق. التذييل Footer: باللون الأزرق في الشكل السابق. لاحظ أنّ مربع الاختيار mark-all-complete المميَّز باللون الأصفر يُصيَّر بجوار حقل الإدخال new-todo أثناء وجوده في القسم main لأن تنسيقات CSS الافتراضية تضع مربع الاختيار والعنصر label بقيم سالبة للإحداثيات العلوية واليسارية لتحريكهما بجوار حقل الإدخال، عوضًا عن وضعهما في القسم main. استخدام واجهة سطر الأوامر CLI لإنشاء المكونات نريد إنشاء أربعة مكونات لتمثيل تطبيقنا وهذه المكونات هي: الترويسة Header. القائمة List. عنصر المهمة Todo. التذييل Footer. استخدِم الأمر ember generate component متبوعًا باسم المكوّن لإنشائه، ولننشئ مكوّن الترويسة أولًا باتباع الخطوات التالية: أوقف تشغيل الخادم بالانتقال إلى الطرفية والضغط على الاختصار Ctrl + C. أدخِل الأمر التالي في الطرفية: ember generate component header سينشئ هذا الأمر بعض الملفات الجديدة، كما هو موضّح في ناتج الطرفية النهائي التالي: installing component create app/components/header.hbs skip app/components/header.js tip to add a class, run `ember generate component-class header` installing component-test create tests/integration/components/header-test.js يُعَدّ الملف header.hbs بأنه ملف القالب الذي سيتضمّن بنية HTML لمكوّن الترويسة فقط، وسنضيف لاحقًا الوظائف الآلية المطلوبة مثل روابط البيانات والاستجابة لتفاعل المستخدِم وما إلى ذلك. يُعَدّ الملف header-test.js ملفًا مخصَّصًا لكتابة الاختبارات الآلية للتأكد من أن تطبيقنا يستمر في العمل بمرور الوقت أثناء الترقية وإضافة الميزات وإعادة البناء وما إلى ذلك، ولن نتطرّق للاختبار في هذا المقال، ولكن يجب تطبيق الاختبار أثناء عملية التطوير وليس بعده، إذ يمكن أن تنساه لاحقًا. لننشئ شيفرة مساعِدة Scaffolding للمكوّنات الأخرى قبل إضافة أيّ شيفرة مكوّن، وبالتالي أدخِل الأوامر التالية في طرفيتك واحدًا تلو الآخر: ember generate component todo-list ember generate component todo ember generate component footer سترى الآن ما يلي في المجلد todomvc/app/components: بما أنه أصبح لدينا الآن جميع ملفات بنية المكونات، فيمكننا قص ولصق توصيف HTML لكل مكوّن من الملف application.hbs إلى كل مكوّن من هذه المكوّنات، ثم تعديل الملف application.hbs ليمثّل تجريداتنا الجديدة. أولًا، يجب تعديل الملف header.hbs ليحوي ما يلي: <input class="new-todo" aria-label="What needs to be done?" placeholder="What needs to be done?" autofocus > ثانيًا، كما يجب تعديل الملف todo-list.hbs ليحوي ما يلي: <section class="main"> <input id="mark-all-complete" class="toggle-all" type="checkbox"> <label for="mark-all-complete">Mark all as complete</label> <ul class="todo-list"> <Todo /> <Todo /> </ul> </section> ثالثًا، أضف ما يلي إلى الملف todo.hbs: <li> <div class="view"> <input aria-label="Toggle the completion of this todo" class="toggle" type="checkbox" > <label>Buy Movie Tickets</label> <button type="button" class="destroy" title="Remove this todo" ></button> </div> <input autofocus class="edit" value="Todo Text"> </li> رابعًا، يجب تعديل الملف footer.hbs بحيث يحوي ما يلي: <footer class="footer"> <span class="todo-count"> <strong>0</strong> todos left </span> <ul class="filters"> <li> <a href="#">All</a> <a href="#">Active</a> <a href="#">Completed</a> </li> </ul> <button type="button" class="clear-completed"> Clear Completed </button> </footer> خامسًا، أخيرًا، يجب تعديل محتويات الملف application.hbs بحيث تُستدَعى المكونات المناسبة كما يلي: <section class="todoapp"> <h1>todos</h1> <Header /> <TodoList /> <Footer /> </section> سادسًا، شغِّل الأمر npm start في الطرفية مرةً أخرى بعد إجراء هذه التعديلات، ثم توجَّه إلى المضيف المحلي http://localhost:4200 للتأكد من أنّ تطبيق المهام لا يزال يبدو كما كان قبل إعادة البناء. لاحظ كيف يعرض كلا عنصري المهام العبارة "Buy Movie Tickets" بسبب استدعاء المكوّن نفسه مرتين، ونَص المهمة ثابت فيه. الخلاصة يبدو كل شيء كما ينبغي، إذ نجحنا في إعادة بناء توصيف HTML إلى مكوّنات، وسنبدأ في المقال التالي بالتعرّف على إضافة التفاعل إلى تطبيق Ember. ترجمة -وبتصرّف- للمقال Ember app structure and componentization. اقرأ أيضًا المقال السابق: مقدمة إلى إطار العمل Ember
  5. سنلقي نظرةً في هذا المقال على إطار العمل Ember وآلية عمله وفوائده، وكيفية تثبيت سلسلة أدواته محليًا وإنشاء تطبيق نموذجي ثم إجراء إعداد أولي لتجهيز التطبيق للتطوير. المتطلبات الأساسية: الإلمام بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة استخدام سطر الأوامر أو الطرفية، كما يُعَدّ فهم ميزات جافاسكربت الحديثة مثل الأصناف Classes والوحدات Modules وما إلى ذلك مفيدًا للغاية، لأن إطار العمل Ember يستخدِمها بكثرة. الهدف: معرفة كيفية تثبيت إطار عمل Ember وإنشاء تطبيق بسيط. يُعَدّ Ember إطار عمل من النوع خدمة-مكونات Component-service يركّز على عملية تطوير تطبيقات الويب وإضفاء تجربة مميزة على واجهاتها ويقلل من الاختلافات بين التطبيقات، ويُعَدّ طبقةً حديثةً وخفيفةً فوق طبقة جافاسكربت الأصيلة Native، كما يتمتع بتوافق كبير مع الإصدارات السابقة واللاحقة لمساعدة الشركات على مواكبة أحدث إصدارات Ember وأحدث الاتفاقيات التي يقودها المجتمع. تُعَدّ المكونات حزمًا من شيفرات السلوك والتنسيق Style والتوصيف Markup التي تشبه إلى حد كبير ما توفره أطر عمل الواجهة الأمامية الأخرى مثل React و Vue و Angular، كما يوفر جانب الخدمة حالةً مشتركةً طويلة الأمد وسلوكًا وواجهةً للتكامل مع المكتبات أو الأنظمة الأخرى، إذ يُعَدّ الموجِّه Router الذي سنشرحه لاحقًا خدمةً مثلًا، وتشكّل المكونات والخدمات القسم الأكبر من تطبيق EmberJS. هذا المقال جزء من سلسلة تقديمية حول إطار العمل Ember وإليك فهرس كامل السلسلة: مقدمة إلى إطار العمل Ember بنية تطبيق إطار العمل Ember وتقسيمها إلى مكونات تنفيذ التفاعل في تطبيق Ember: الأحداث والأصناف والحالة تنفيذ التفاعل في تطبيق Ember: وظيفة التذييل والعرض الشرطي التوجيه Routing في إطار العمل Ember حالات الاستخدام يناسب إطار عمل EmberJS بناء التطبيقات التي تستهدف إحدى السمتين التاليتين أو كلتيهما: تطبيقات الصفحة الواحدة، بما في ذلك تطبيقات الويب الشبيهة بالتطبيقات الأصيلة وتطبيقات الويب التقدمية Progressive Web Apps أو PWA اختصارًا. يعمل إطار عمل Ember بصورة أفضل عندما يشكِّل الواجهة الأمامية الكاملة لتطبيقك. زيادة التماسك بين العديد من تقنيات الفرق البرمجية. تتيح أفضل الممارسات التي يدعمها المجتمع سرعة تطوير أكبر على المدى الطويل. يملك إطار عمل Ember اصطلاحات أو اتفاقيات واضحة ومفيدة لفرض التناسق ومساعدة أعضاء الفريق على العمل بسرعة. إضافات إطار عمل Ember يمتلك إطار العمل EmberJS معمارية الإضافات Plugin، مما يعني أنه يمكن تثبيت الإضافات Add-ons وتوفير وظائف إضافية دون كثير من الإعداد إذا وُجِد، ومن هذه الإضافات: PREmber: تصيير Rendering موقع ويب ساكن للمدونات أو المحتوى التسويقي. FastBoot: تصيير من طرف الخادم، بما في ذلك تحسين محركات البحث SEO، أو تحسين أداء التصيير الأولي لصفحات الويب المعقدة عالية التفاعل. empress-blog: تأليف منشورات المدونات باستخدام لغة ماركداون Markdown مع تحسين محركات البحث SEO باستخدام الإضافة PREmber. ember-service-worker: إعداد تطبيق ويب تقدمي PWA بحيث يمكن تثبيت التطبيق على الأجهزة المحمولة مثل تثبيته من متجر تطبيقات الجهاز نفسه. تطبيقات الجوال الأصيلة يمكن استخدام إطار عمل Ember مع تطبيقات الأجهزة المحمولة الأصيلة مع جسر بين تطبيقات الهاتف المحمول الأصيلة ولغة جافاسكربت مثل الجسر الذي توفره واجهة Corber. الآراء والأعراف يُعَدّ إطار العمل EmberJS أحد أكثر أطر عمل الواجهة الأمامية تشبثًا برأيه، وتُعَدّ الآراء في Ember مجموعةً من الاتفاقيات أو الأعراف التي تساعد على زيادة كفاءة المطورين، ولكن يجب تعلّم تلك الاتفاقيات، إذ تساعد الآراء التي تدعم الاتفاقيات في تقليل الاختلافات بين التطبيقات مثل اللغات المُستخدَمة والنظام المجتمعي بفضل تعريف هذه الاتفاقيات ومشاركتها، وهو هدف مشترك بين جميع الأطر المتشبثة برأيها، ويصبح المطورون بعدها أكثر قدرةً على التبديل بين المشاريع والتطبيقات دون الحاجة إلى إعادة تعلم المعمارية والأنماط والمصطلحات وما إلى ذلك، وستلاحظ خلال هذا المقال آراء إطار العمل Ember مثل اصطلاحات تسمية ملفات المكونات. ارتباط إطار عمل Ember مع لغة جافاسكربت الصرفة Vanilla JavaScript بُني إطار عمل Ember على تقنيات جافاسكربت، ويُعَدّ طبقةً رقيقةً فوق البرمجة التقليدية كائنية التوجه، مع السماح للمطورين باستخدام تقنيات البرمجة الوظيفية. يستخدِم Ember صيغتين رئيسيتين هما: جافاسكربت أو لغة TypeScript اختياريًا. لغة قوالب Ember الخاصة التي تعتمد على لغة Handlebars. تُستخدَم لغة القوالب Templating Language لتحسين عملية البناء ووقت التشغيل، وهي مجموعة شاملة من لغة HTML، وبالتالي يمكن لأيّ شخص يعرف لغة HTML تقديم مساهمات مهمة لأيّ مشروع من مشاريع Ember، كما يمكن للمصممين وغيرهم من غير المطورين المساهمة في قوالب الصفحات دون أي معرفة بلغة جافاسكربت، ثم يمكن إضافة التفاعل لاحقًا، كما تتيح لغة القوالب هذه حمولات أصول أخف نظرًا لتصريف القوالب في شيفرة ثنائية Byte Code يمكن تحليلها بسرعة أكبر من تحليل شيفرة جافاسكربت. كل شيء آخر في Ember هو جافاسكربت وخاصةً أصناف جافاسكربت التي تُعَدّ المكان الذي تعمل فيه معظم أجزاء إطار العمل حيث توجد الأصناف الأبناء، ويكون لكل نوع من الأشياء غرض مختلف وموقع متوقع مختلف ضمن مشروعك. يوضِّح الشكل التالي تأثير Ember على جافاسكربت في المشاريع النموذجية، إذ يوضِّح كيف أن أقل من 20% من شيفرة JS المكتوبة خاصةً بإطار العمل Ember. بدء استخدام Ember سننشئ أولًا نسخةً من نموذج تطبيق TodoMVC التقليدي لتعلُّم كيفية استخدام أساسيات إطار عمل Ember، إذ يُعَدّ تطبيق TodoMVC تطبيقًا أساسيًا لتتبّع المهام، ويُستخدَم في العديد من التقنيات المختلفة، وإليك نسخةً مكتملةً منه ليكون مرجع لك. إنشاء تطبيق جديد في Ember يحتوي مشروع TodoMVC على بعض المشاكل من حيث الالتزام بممارسات الويب التي يمكن الوصول إليها افتراضيًا، وهناك نوعان من مشاكل جيت هاب GitHub المفتوحة حول هذا الموضوع في مجموعة مشاريع TodoMVC هي: إضافة وصول مستخدِمي لوحة المفاتيح إلى العروض التوضيحية. إعادة تفعيل المخطط حول العناصر القابلة للتركيز. يهتم إطار Ember بموضوع إمكانية الوصول accessibility كثيرًا وأن تكون التطبيقات المبنية فيه سهلة الوصول لكامل المستخدمين حتى بمن فيهم أي إعاقة وقد وفر دليلًا شاملًا عنه، ولكن بما أنّ هذا المقال يركِّز على جانب جافاسكربت في إنشاء تطبيق ويب صغير، فإنّ قيمة TodoMVC تأتي من توفير ملفات CSS المبنيّة مسبقًا وبنية HTML الموصَى بها، مما يلغي الاختلافات بين التطبيقات، كما يسمح بإجراء موازنة أسهل بينها، وسنركِّز لاحقًا على إضافة شيفرة إلى تطبيقنا لإصلاح بعض أكبر أخطاء تطبيق TodoMVC. تثبيت أدوات Ember يستخدِم Ember واجهة سطر الأوامر CLI لبناء أجزاء من تطبيقك وإنشاء شيفرتها المساعدة Scaffolding. أولًا، ستحتاج إلى تثبيت أداة node ومدير الحزم npm قبل تمكّنك من تثبيت أداة ember-cli، كما يمكنك الانتقال إلى مقال دليل استخدام سطر الأوامر في عملية تطوير الويب من طرف العميل لمعرفة كيفية تثبيت node و npm إذا لم تكن مثبّتةً لديك مسبقًا. ثانيًا، اكتب الأمر التالي في طرفيتك لتثبيت أداة ember-cli: npm install -g ember-cli توفِّر هذه الأداة برنامج ember في طرفيتك، وتُستخدَم لإنشاء وبناء وتطوير واختبار تطبيقك وإنشاء شيفرته المساعِدة، كما يمكنك تشغيل الأمر ember --help للحصول على قائمة كاملة بالأوامر وخياراتها. ثالثًا، يمكنك إنشاء تطبيق جديد تمامًا من خلال كتابة الأمر التالي في طرفيتك، مما يؤدي إلى إنشاء مجلد جديد له الاسم todomvc ضمن المجلد الذي أنت فيه حاليًا، بحيث يحتوي على أدوات لبناء تطبيق Ember جديد، وتأكد من الانتقال إلى مكان مناسب في الطرفية مثل مجلد "سطح المكتب" أو مجلد "المستندات" لتعثر على مجلد تطبيقك بسهولة قبل تشغيل الأمر التالي: ember new todomvc أو شغّل الأمر التالي على نظام ويندوز: npx ember-cli new todomvc يؤدي هذا الأمر إلى إنشاء بيئة تطوير تطبيقات جاهزة للإنتاج تتضمن افتراضيًا الميزات التالية: خادم التطوير مع إعادة التحميل المباشر. معمارية الإضافات التي تسمح لحزم الطرف الثالث بتحسين تطبيقك. أحدث إصدار من جافاسكربت متكامل مع Babel و Webpack. بيئة اختبار آلية تدير اختباراتك في المتصفح، مما يتيح لك الاختبار مثل المستخدِم العادي. عملية التحويل Transpilation والتصغير Minification لكل من شيفرات CSS وجافاسكربت الخاصة بعمليات البناء للإنتاج. اتباع العرف السائد في كتابة الشيفرة مما يقلل الاختلافات بين التطبيقات ويسمح بتبديل السياق بسهولة. الاستعداد لبناء مشروع Ember ستحتاج إلى محرِّر شيفرات قبل الاستمرار بمشروعك الجديد، فإذا لم يكن لديك محرّر مُعَدّ مسبقًا، فإنّ Ember Atlas لديه بعض الإرشادات حول كيفية إعداد المحرّرات المختلفة. تثبيت الأصول المشتركة لمشاريع TodoMVC لا يُعَدّ تثبيت الأصول أو ملفات المشروع المشتركة خطوةً مطلوبةً للمشاريع الجديدة، لكنه يسمح باستخدام ملفات CSS المشتركة الحالية حتى لا نخمّن ما هو ملف CSS المطلوب لإنشاء أنماط أو تنسيقات مشروع TodoMVC. أولًا، انتقل أولًا إلى المجلد todomvc في الطرفية باستخدام الأمر cd todomvc في نظامَي macOS أو لينكس Linux مثلًا. ثانيًا، شغّل الأمر التالي لوضع ملف CSS المشترك الخاص بمشروع todomvc ضمن تطبيقك: npm install --save-dev todomvc-app-css todomvc-common ثالثًا، ابحث بعد ذلك عن الملف ember-cli-build.js في المجلد todomvc الموجود في المجلد الجذر، وافتحه في محرر الشيفرة الذي اخترته، إذ يُعَدّ الملف ember-cli-build.js مسؤولًا عن إعداد التفاصيل حول كيفية بناء مشروعك بما في ذلك تجميع كل ملفاتك مع بعضها البعض وتصغير الأصول وإنشاء خرائط الشيفرة البرمجية، لذلك ليس هناك داع للقلق بشأن هذا الملف، كما سنضيف سطورًا إلى الملف ember-cli-build.js لاستيراد ملفات CSS المشتركة، بحيث تصبح جزءًا من عملية البناء دون الحاجة إلى استيرادها ‎@import صراحةً في الملف app.css، إذ سيتطلب ذلك إعادة كتابة عنوان URL في وقت البناء وبالتالي سيكون أقل كفاءة وأكثر تعقيدًا في الإعداد. رابعًا، ابحث عن الشيفرة التالية في الملف ember-cli-build.js: let app = new EmberApp(defaults, { // أضف خيارات هنا }); خامسًا، أضف الأسطر التالية بعد ذلك قبل حفظ الملف: app.import('node_modules/todomvc-common/base.css'); app.import('node_modules/todomvc-app-css/index.css'); سادسًا، أخيرًا، ابحث عن الملف app.css الموجود في المسار app/styles/app.css، والصق ما يلي فيه: :focus, .view label:focus, .todo-list li .toggle:focus + label, .toggle-all:focus + label { outline: #d86f95 solid !important; } يعدِّل ملف CSS بعض الأنماط التي توفرها حزمة npm والتي هي todomvc-app-css، مما يسمح بظهور تركيز لوحة المفاتيح ويؤدي إلى حد ما إلى إصلاح أحد عيوب الشمولية الرئيسية لتطبيق TodoMVC الافتراضي. بدء تشغيل خادم التطوير يمكنك بدء تشغيل التطبيق في وضع التطوير عن طريق كتابة الأمر التالي في الطرفية أثناء وجودك ضمن المجلد todomvc: ember server ويجب أن يظهر لديك خرج مشابه لما يلي: Build successful (190ms) – Serving on http://localhost:4200/ Slowest Nodes (totalTime >= 5%) | Total (avg) -----------------------------------------+----------- BroccoliMergeTrees (17) | 35ms (2 ms) Package /assets/vendor.js (1) | 13ms Concat: Vendor Styles/assets/vend... (1) | 12ms يُشغَّل خادم التطوير على المضيف المحلي http://localhost:4200، والذي يمكنك زيارته في متصفحك للتحقق من عملك حتى الآن. إذا كان كل شيء على ما يرام، فسترى صفحةً تشبه الصفحة التالية: الخلاصة وصلنا إلى النقطة التي يمكننا فيها البدء في بناء نموذجنا لتطبيق TodoMVC في إطار عمل Ember، وسنتعرّف في المقال التالي على بناء بنية شيفرة توصيف تطبيقنا بوصفها مجموعة من المكونات المنطقية. ترجمة -وبتصرّف- للمقال Getting started with Ember. اقرأ أيضًا مقارنة بين أطر الواجهات الأمامية: Angular و React و Vue
×
×
  • أضف...