Professional Documents
Culture Documents
812436c2 Fbab 4adb Bc05 4746d501f520 Introduction To Vuejs Hsoub Academy Ar v1.0
812436c2 Fbab 4adb Bc05 4746d501f520 Introduction To Vuejs Hsoub Academy Ar v1.0
js
تأليف
حسام برهان
تحرير وإشراف
جميل بيلوني
جميع الحقوق محفوظة © 2021أكاديمية حسوب
الم ِّ
صنف -غري تجاري -الرتخيص َّ
مرخص بموجب رخصة المشاع اإلبداعيَ :نسب ُ هذا العمل
بالمثل 4.0دويل
عن النارش
ُأ نتج هذا الكتاب برعاية شركة حسوب وأكاديمية حسوب.
تهدف أكاديمية حسوب إلى توفير فصول وكتب عالية الجودة في مختلف المجاالت وتق دم دورات ش املة
ُّ
لتعلم البرمج ة بأح دث تقنياته ا معتم د ًة على التط بيق العملي ال ذي يؤه ل الط الب ل دخول س وق
العمل بثقة.
حسوب مجموعة تقنية في مهمة لطوير العالم العربي .تب ني حس وب منتج ات تركِّز على تحس ين مس تقبل
العمل ،والتعليم ،والتواصل .تدير حسوب أكبر منصتي عمل حر في العالم العربي ،مستقل وخمسات ويعم ل في
9 تقديم
15 األول
1.3إضافة مزايا جديدة لتطبيقنا ّ
17 1.4العمل على حاسوب محلي
6
أساسيات إطار العمل Vue.js جدول المحتويات
7
أساسيات إطار العمل Vue.js جدول المحتويات
8
تقديم
ً
بداية تختلف عن غيره من الكتب التي عملنا عليها ،إذ كنت أتخ ير كتا ًب ا عن إط ار بدأت حكاية هذا الكتاب
العم ل Vue.jsمن المراج ع األجنبي ة الح رة أو مفتوح ة المص در لترجمته ف وقعت ي دي على ك تيب
تأليف كتاب كامل يشمل أساسيات Vue.jsويكون مقدمة لمن يريد تعلم هذا اإلطار ،وهنا بدأت الحكاية وكتبن ا
سبب اختيارنا شرح إطار العمل Vue.jsهو أنه إط ار ش امل واعد س ريع األداء ذاع الص يت يس تعمل لبن اء
تطبيقات ويب ،توجهت أنظارنا إلضافة محتوى عربي مميز يشمله بع د أن اخترن ا كتا ًب ا لتغطي ة مكتب ة React
ً
مسبقا وكتابًا حول Angularفي خطة إلضافة مصادر تعليمي ة عالي ة الج ودة تش رح أش هر أط ر لغ ة الشهيرة
حرصنا في هذا الكتاب أن يك ون س هل الفهم والتط بيق يش مل أساس يات Vue.jsال تي س تمكنك من ب دء
العمل سريعً ا مع هذا اإلطار متبعين قاعدة ( 20/80التي ننتهجه ا ع اد ًة في كتبن ا وال تي تق ول تعلم %20من
تل ك المف اهيم ال تي تس تعمل في %80من ح االت االس تخدام) .اتبعن ا في الكت اب النهج العملي التط بيقي إذ
ستبني خالل فصول الكتاب عدة تطبيقات عملية وستتعلم كيفية نشرها وإطالقها على ال ويب ،واعتم دنا ً
أيض ا
األسلوب السهل البسيط المختصر فخير الكالم ما قل ودل مع إضافة تمارين وأفكار في نهاية كل فصل ما أمكن
لتطبيقها بنفسك.
أساسيات إطار العمل Vue.js تقديم
حتى تس تفيد أك بر اس تفادة من الكت اب ،يجب أن تمل ك معرف ة أساس ية مس بقة بلغ ة HTMLولغ ة CSS
ومعرفة جيدة بلغة جافاسكربت ،إذ يركز الكتاب على إطار العمل Vue.jsالذي هو أحد أط ر عم ل جافاس كربت
ولن يتطرق الكت اب إلى ش رح لغ ة جافاس كربت ،وق د تج د ص عوبة في فهم أج زاء الش يفرات واالس تفادة من
الكتاب دون تلك المعرفة المسبقة .انظر قسم الكتب البرمجية في أكاديمية حسوب لتنزيل مصادر لتلك اللغات.
يبدأ الكتاب فصوله األولى بشرح مفهوم إطار العمل والتعرف على Vue.jsوأخذك سريعً ا وباختص ار لب دء
استعماله ببناء أول تطبيق ع بره .س تبدأ من الفص ل الث اني في Vue.jsب التعرف على إط ار العم ل Vue.jsعن
قرب وعن آلية عمله وكيفية استعماله في بناء الوجهات األمامي ة ثم تنتق ل بع دها إلى التع رف على الموجه ات
الشرطية والتكرارية واستعمالها في قوالب الواجه ة األمامي ة ،يليه ا ال دخول إلى ع الم مكون ات Vue.jsوتعلم
كيفية بناءها .ستبدأ بعدها في الفصل السابع األمور المتقدمة إذ ستتعلم التعامل م ع س طر أوام ر Vue.jsلبن اء
المش اريع والتطبيق ات بس هولة ويس ر ثم س تتعرف بع د ذل ك على مف اهيم متقدم ة في Vue.jsوكيفي ة بن اء
تطبيقات ذات صفحة واحدة .ستتعلم في الفصول األخيرة من الكتاب كيفية رب ط تطبيق ك ب اإلنترنت وإض افة
قاعدة بيانات له وإطالق إلى العالم الخارجي متحرين استعمال أشهر منصات النشر وأيسرها تعاماًل .
نسعد بالسماع منك ألي رأي أو تصحيح أو مالحظة عبر بريد األكاديمية academy@hsoub.com
جميل بيلوني
16/06/2021
10
.1مدخل إىل Vue.js
ّ
سنتعلم فيه كيف سنتعامل مع إطار العمل .Vue.jsهذا اإلطار الواعد ال ذي مرح ًبا بك في هذا الكتاب التي
نتدرج في
ّ يُ سهّ ل العمل في تطوير الواجهة األمامي ة للتطبيق ات Frontend Applicationsإلى ح دّ بعي د .س
فص وله بش كل س لس ،حيث س نتناول موض وعات بس يطة في البداي ة ،ثم وم ع تق دّ منا في الفص ول س نغطي
ستالحظ وجود تطبيقات بسيطة في كل فصل ،نش رح من خالله ا فك رة أو أفك ار مح دّ دة .ولكن في نهاي ة
ً
مسبقا .الهدف من الكتاب ه و أن تمت تغطيتها الكتاب سنختم بتطبيقين عمليينّ ،
يوضحان معظم األفكار التي ّ
األول مع Vue.js
تطبيقك ّ •
األول
إضافة مزايا جديدة لتطبيقنا ّ •
ّ
محلي العمل على حاسوب •
يحتاج المبرمج أن يستخدم األسلوب التقليدي القديم في التعامل مع نموذج كائنات المستند DOMباستخدام
،JavaScriptحيث يمكن باستخدام إطار العمل التعامل مع العناص ر في DOMبش كل قياس ي ومج ّرد وس هل
المرحلة الثانية وهي المرحلة الحالية فكانت مع أطر عمل مثل Reactو Angularو .Vue
ٌتعدّ Vue.jsمن أحدث ُأ طر العم ل في ،JavaScriptوهي إط ار عم ل واع د ،يجم ع بين الس هولة والمرون ة
والقوة ،باإلضافة إلى صغر حجم الملف الخاص بها (فقط 26كيلو ب ايت) مم ا يجع ل تحمي ل ص فحات ال ويب
سهلة إلى حد بعيد .سنهتم باإلصدار 2من Vue.jsمع التأكي د ب أنّ م ا س نأخذه هن ا يمكن تطبيق ه بس هولة في
إصدارات الحقة ،إذ نزل اإلصدار 3بعد االنتهاء من الكتاب ولكن ُذ ِكر أنه عملية إع ادة كتاب ة لإلط ار وليس في ه
قبل البدء باستخدام Vue.jsعلينا أن نحصل على الملف الخاص به .لدينا عدّ ة خيارات لذلك ،سأختار أح د
أسهل الخي ارات وه و الحص ول على المل ف الخ اص بإط ار العم ل عن طري ق ش بكة تس ليم محت وى ،CDNثم
نتحدّ ث عن الخيارات األخرى فيما بعد .يمكنك استخدام رابط CDNالت الي للحص ول على Vue.js؛ الراب ط ه و
أي شيء على حاسوبك .ستحصل على شكل شبيه بما يلي:
12
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
انق ر على الراب ط URLال ذي يظه ر في القس م األيس ر في األعلى من الناف ذة الس ابقة ،بج وار
كلمة :Resources
بعد نقر الرابط السابق ستحصل على مربّع نص ،انسخ فيه رابط CDNالسابق ،ثم انق ر ال زر المج اور ال ذي
انسخ اآلن شيفرة HTMLالتالي إلى القسم الخاص بأكواد HTMLمن الصفحة الرئيسية لموقع :jsfiddle
>"<div id="app
}} {{ message
><\div
ثم انسخ ش يفرة JavaScriptالتالي ة والص قها ض من القس م الخ اص بش يفرات JavaScriptفي الص فحة
الرئيسية الموقع:
13
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
انقر اآلن زر التشغيل Runالموجود في الزاوية اليس رى العلي ا من الص فحة .إذا نف ذت الخط وات الس ابقة
بدق ة ،س تالحظ ظه ور العب ارة !Hello Vueفي القس م األيمن األس فل من الص فحة .مب ارك! لق د ب نيت
ّ
أتوقع أنّ شيفرة HTMLال تي كتبناه ا س هلة وواض حة ،حيث أنش أنا دعنا اآلن ّ
نحلل ما قمنا به حتى اآلن.
هذا التعبير هو األساس في ،Vue.jsسنتحدّ ث عنه بعد قليل .اآلن الحظ معي شيفرة JavaScriptالتالية:
أعتقد أنّ بداية هذه الشيفرة مألوف ة ،حيث أ ّنن ا نعم ل على إنش اء ك ائن من الن وع Vueباس تخدام الكلم ة
14
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
{
el: '#app',
{ data:
'!message: 'Hello Vue
}
}
المقطع السابق عبارة عن كائن آخر يُ سمى بكائن الخيارات ( )options instanceيحوي اإلع دادات ال تي
نريد أن تكون ضمن كائن Vue.jsالجديد .ففي الحقل ّ ( el
يمثل أول ح رفين من كلم ة elementأي العنص ر)
المس تَ هدف (في حالتن ا ه ذه ه و عنص ر divال ذي ُنسند القيمة ' '#appوال تي ّ
تمث ل مع ّرف عنص ر ُ HTML
أم ا الحق ل dataفيتم إس ناد ك ائن آخ ر إلي ه يحت وي على حق ل واح د وه و message
أنشأناه قب ل قلي ل)ّ ،
وقيمت ه '! .'Hello Vueالح ظ أنّ الكلم ة ' 'messageهي نفس ها الموج ودة ض من ُرم از HTMLالس ابق
الموض وعة بحاض نة مزدوج ة {{ .}} messageوهك ذا فعن د تنفي ذ البرن امج الس ابق س يعمل Vueعلى
استبدال التعبير {{ }} messageض من عنص ر HTMLال ذي يحم ل المع ّرف appب النص '!'Hello Vue
وهذا ّ
كل شيء.
العملية.
ّ يميز بين الكائن objectوالنسخة ،instanceإاّل أنني ال ّ
أفرق بينهما من الناحية رغم وجود من ّ
دوما.
لذلك تراني أستخدم "كائن" ً
حاول اآلن إجراء بعض التغييرات على النص السابق ،وأعد التنفيذ باستخدام الزر Runلتشاهد التغي يرات
مجهزة مس ً
بقا، ّ مجرد عملية استبدال تعبير برسالة
ّ في الحقيقة إنّ ما جرى في هذا المثال يتعدّ ى عن كونه
إن ما يجري من وراء الكواليس هو عملية ربط كامل بين الحقل messageالموجود ضمن شيفرة JavaScript
وبين التعبير {{ }} messageالموجود ضمن ُرماز HTMLوسنرى كيف ذلك في الفقرة التالية.
ّ
األول 1.3إضافة مزايا جديدة لتطبيقنا
حان ال وقت إلج راء بعض التحس ينات على تطبيقن ا األول .انتق ل إلى قس م HTMLوأض ف عنص ر إدخ ال
>"<div id="app
><input type='text' v-on:input="updateInfo"/
}} {{ message
></div
15
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
لقد وضعت عنصر اإلدخال فوق التعبير {{ }} messageمباشرة .الش يء الجدي د هن ا ه و الس مة (أي
حالتنا هذه فإ ّننا نرغب باإلنصات لحدث اإلدخال ( inputمعامل )parameterلعنصر اإلدخ ال النص ي .الح ظ
تم إج راء
الموجه updateInfo :وهي بكل بساطة اسم التابع الذي سيتم استدعاؤه في ح ال ّ
ّ المسندة
القيمة ُ
سنعرف هذا التابع اآلن.
ّ أي إدخال ضمن عنصر اإلدخال النصي من ِق َبل المستخدم.
بالشيفرة التالية:
الفرق الوحيد بين المقطعين الجديد والق ديم ،أ ّنن ا أض فنا القس م methodsال ذي يتم في ه تعري ف جمي ع
;this.message = event.target.value
جرب تنفيذ البرنامج اآلن بنقر زر ،Runثم ح اول كتاب ة أي ش يء ض من مرب ع النص ،س تالحظ أ ّن ه س يتم
ّ
تحديث الرسالة بشكل فوري بالنص الذي تكتبه!
16
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
أواًل تنزي ل Vue.jsعن طري ق الراب ط ( vuejs.org/js/vue.jsمن الممكن أن يظه ر محت وى
الشخص ي .علين ا ّ
الملف كاماًل ضمن صفحة عادية في المتصفح ،انسخ محتويات الصفحة واحفظها ضمن جديد ،س ّمه.)vue.js :
حص لت على النس ختين الس ابقتين من الموق ع الرس مي إلط ار العم ل Vue.jsمن الص فحة التالي ة:
vuejs.org/v2/guide/installation.html
ّ
المجل د مل ف vue.jsال ذي ّ
نزلت ه قب ل قلي ل. وسمه ،vuejs-first-appثم انس خ ض من ه ذا
ّ ّ
مجلدً ا أنشئ
محرر HTMLالمناسب لك ،أنش ئ مل ف جدي د واخ تر ل ه مثال االس م .index.htmlثم احفظ ه في
ّ باستخدام
ّ
المجل د الس ابق بج وار المل ف ،vue.jsوبع د ذل ك أض ف إلي ه المحت وى الت الي ال ذي قمت بتجميع ه من نفس
><!DOCTYPE html
>"<html lang="en" dir="ltr
><head
>"<meta charset="utf-8
><title>Vue.js</title
><script src="vue.js"></script
></head
17
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
><body
>"<div id="app
><input type='text' v-on:input="updateInfo"/
}} {{ message
></div
>"<script type="text/javascript
{(var app = new Vue
el: '#app',
{ data:
'!message: 'Hello Vue
},
{methods:
{)updateInfo:function(event
;this.message = event.target.value
}
}
)}
></script
></body
></html
ّ
المحلي عن طري ق وس م scriptض من القس م headمن الحظ معي أ ّننا ق د أض فنا مرجعً ا لمل ف vue.js
المستند ،وأضفنا شيفرة JavaScriptالمسؤولة عن تحديث خرج التطبيق ضمن القسم bodyمن المستند.
1.5ختام الفصل
تناولنا في هذا الفصل مقدّ مة س ريعة إلى إط ار العم ل الواع د Vue.jsحيث ّ
تعلمن ا كي ف نب دأ م ع Vue.js
ومتدرج.
ّ في الفصول الالحقة لنسبر أغوار Vue.jsبشكل سهل
1.6تمارين داعمة
بعد كل تمرين حل مقترح ،حاول أاّل تنظر إلى الحلول المقترحة قبل تقديم حلولك.
18
أساسيات إطار العمل Vue.js مدخل إىل Vue.js
1.6.1تمرين 1
الحل المقتـرح
الح ل في ه ذا التم رين بس يط .اس تبدل الوس يط inputبالوس يط clickedض من ُرم از HTMLثم وفي
;this.message = event.target.value
السطر:
;'!this.message = 'Clicked
1.6.2تمرين 2
في هذا التمرين ستُ نشئ تطبيق آلة حاسبة بسيط يقوم بعملية حسابية واح دة وهي جم ع ع ددين .أق ترح
الم يزة في ه ذا التط بيق أ ّن ه إذا ب دأ المس تخدم بالكتاب ة في أي مر ّب ع ،يجب أن يق وم التط بيق بإيج اد
ّ
بالتحقق من صحة إدخال المستخدم. المجموع بشكل فوري أثناء إدخاله األرقام .لن نقوم في هذا التمرين
الحل المقترح
لتخزين قيمتي المعاملين األيمن واأليسر لعملية الجمع .شيفرة HTMLالمقترحة هي:
>"<div id="app
><input type='text' v-on:input="updateLeftOper"/
><label>+</label
><input type='text' v-on:input="updateRightOper"/
><label>=</label
><label>{{result}}</label
></div
19
Vue.js أساسيات إطار العمل Vue.js مدخل إىل
ً
.الحقا سنتكلم المزيد عن هذه األمور،تماما فال بأس
ً إذا لم تستطع استيعاب الشيفرة السابقة
20
.2التعامل مع DOM
ّ
سنتعلم في هذا الفصل:
نتابع عملنا في هذا الفص ل وه و الفص ل الث اني وال ذي س نتعلم في ه ه ذه الم ّرة كيفي ة الوص ول والتعامل
وسنتوس ع في التعام ل م ع األح داث eventsباإلض افة إلى كيفي ة اس تخدام الرب ط ثن ائي االتج اه
ّ معه ا،
مع العناصر.
أساسيات إطار العمل Vue.js التعامل مع DOM
تعاملنا في الفصل السابق مع تطبيقات استخدمت مزايا بسيطة من ،Vue.jsوإذا كنت ت ذكر أ ّنن ا ق د كتبن ا
}} واس تخدمنا ً
أيض ا ثم اس تخدمنا االس تبدال النص ي {{ message
ش يفرة HTMLبس يطة ومن ّ
موجه v-onلالستجابة إلى دخل المستخدم.
ّ
،templateبع د ذل ك يتم إج راء عملي ة تص يير ( )renderingعلى نس خة من الق الب الس ابق ،باس تخدام
اآلن ،وعندما يُ حدَ ث أي تغيير جدي د في قيم ة أي حق ل مرتب ط من ك ائن ،Vue.jsس تُ جرى عملي ة تص يير
على المستخدم.
فعلي ا في
ً دائم ا بين ك ائن Vue.jsوبين ش يفرة .HTMLوه ذا م ا رأين اه
ارتباط ا ً
ً أي كم ا ل و أ ّنن ا أنش أنا
من باب التذكير ،نستخدم في هذا الكتاب الموقع jsfiddle.netبشكل افتراضي لتشغيل جميع
التطبيقات التي نكتبها .ونحتاج بالطبع إلى إدراج ملف إطار العمل Vue.jsلكي نستطيع تنفيذ هذه
التطبيقات .إذا أردت أن تعرف كيف ذلك ،يمكنك العودة إلى الفصل السابق.
شيفرة :)JavaScript
>"<div id="app
}} {{ title
></div
22
أساسيات إطار العمل Vue.js التعامل مع DOM
}
)}
قبل titleكما هو واضح .في الحقيق ة أنّ أي كلم ة ُتش ير إلى حق ل (مث ل )titleموج ودة ض من حاض نة
مزدوجة ،سيتم اعتبارها على أ ّنها حقل ضمن القسم dataفي كائن Vue.jsالموافق .اآلن عن د تنفي ذ التط بيق
ّ
متوقع. السابق سيؤدي إلى ظهور الجملة !Hello Vueكما هو
ّ
ليحق ق نفس الخ رج الس ابق وبالمثل ً
أيضا ،يمكننا في الواقع استخدام تابع مثل )(displayMessage
>"<div id="app
}} )({{ displayMessage
></div
نة من الحاض ابع )( displayMessageض رة الت ذه الم تخدمنا ه ا اس ظ أ ّنن الح
يُ كتب به ذه الطريق ة س ُيعتَ بر افتراض ًّيا على أ ّن ه ت ابع موج ود ض من القس م methodsمن ك ائن .Vue.js
ولكن ه ذا الس لوك االفتراض ي ال يس ري على ش يفرة JavaScriptالموج ودة ض من ك ائن Vue.jsحيث يجب
مرة أردنا فيها الوصول إلى أحد أعضاء كائن .Vue.js استخدام الكلمة thisفي ّ
كل ّ
ال يمكن اس تخدام تقني ة االس تبدال النص ي (باس تخدام الحاض نة المزدوج ة) إلدراج قيم ض من س مات
>"<div id="app
23
أساسيات إطار العمل Vue.js التعامل مع DOM
ّ
متوق ع ،ولكن إذا ج ربت النق ر على الراب ط لن ينقل ك إلى موق ع أكاديمي ة الحظ أ ّنه خ رج ّ
منس ق كم ا ه و
ّ
متوقع ،في الحقيق ة س ينقلك ه ذا الراب ط إلى ص فحة ض من نفس موق ع jsfiddle.netوه ذه حسوب كما هو
النصي ُت ِ
عامل محتويات الحق ل linkكنص مج ّرد ،يمكن ك مالحظ ة السبب في ذلك أنّ تقنية االستبدال ّ
الموج ه
ّ ويتمثل في تجنّب استخدام السمة hrefبهذا الشكل ،إ ّنما ينبغي استخدام
ّ الحل لهذه المشكلة بسيط،
'v-bind:href = 'link
حيث linkهو نفسه الحقل الموجود ضمن كائن .Vue.jsاس تبدل ب التعبير الس ابق الس مة hrefالقديم ة
الموجودة ضمن شيفرة HTMLالموجود في المثال السابق ،بعد االستبدال سيص بح ش كل ش يفرة HTMLعلى
النحو التالي:
>"<div id="app
><p> {{ message }} - <a v-bind:href = 'link'>Hsoub Academy</a ></p
></div
24
أساسيات إطار العمل Vue.js التعامل مع DOM
نحت اج في بعض األحي ان إلى كتاب ة ش يفرة HTMLخ ام مباش ر ًة في الص فحة .ق د يتب ادر إلى ذهن ك أن
>"<div id="app
}} {{ raw
></div
اله دف من التط بيق الس ابق ه و ع رض قائم ة غ ير مر ّتب ة عن طري ق العنص ر ُ ulتظه ر ثالث ة عناصر
فق ط First Item :و Second Itemو .Third Itemولكن عن د التنفي ذ لن تحص ل على م ا ه و متوق ع،
أي أ ّن ك ستحص ل على نص ع ادي دون أن يتع ّرف علي ه المتص ّفح على أ ّن ه ش يفرة .HTMLيمكن ه ذه
المشكلة بسهولة بإجراء تعديل على شيفرة HTMLفقط على النحو التالي:
>"<div id="app
>'<p v-html='raw
></p
></div
الحق ل rawكش يفرة HTMLنظامي ة وليس مج ّرد نص ع ادي (الح ظ أ ّن ني ق د تخلص ت من االس تبدال
25
أساسيات إطار العمل Vue.js التعامل مع DOM
أهمية عظيمة في تطوير التطبيقات التي تتفاعل مع المستخدم .ت دعم Vue.jsاألح داث
ّ لألحدث كما نعلم
جي د ،ولقد تعاملنا في الفصل السابق مع نوعين من األحداث :ح دث اإلدخ ال ض من مر ّب ع النص ،وح دث
بشكل ّ
ّ
نتعلم كي ف النقر بزر الفأرة على عنصر .HTMLسنتناول في هذا الفصل األحداث بشيء من التفص يل ،حيث س
ننصت إلى أحداث الفأرة ،باإلضافة إلى اإلنصات إلى أحداث لوحة المفاتيح.
نب دأ بالتعام ل م ع أح داث الف أرة ،لتُ نعش ذاكرت ك ،انظ ر معي إلى التط بيق البس يط الموج ود في
الفصل السابق:
>"<div id="app
><input type='text' v-on:input="updateInfo"/
}} {{ message
></div
الموجه ،v-on
ّ سبق وأن ذكرنا في الفصل السابق أ ّنه يتم اإلنصات إلى أي حدث ضمن عنصر ما باستخدام
بتغير نوع الح دث الم راد اإلنص ات ل ه .بع د تحدي د ن وع الوس يط
الموجه ّ
ّ مرر لهذا
الم ّ
حيث يتم تغيير الوسيط ُ
للموجه v-onيتم تحديد التابع ال ذي سيس تجيب (س يعالج) ه ذا الح دث ،وه و عب ارة عن ت ابع
ّ المراد تمريره
بالنسبة للتابع المعالج للحدث (التابع updateInfoفي المث ال الس ابق) س يتم تولي د ك ائن يحت وي على
مهم ة حول الحدث الذي وقع ،ويتم تمرير هذا الكائن بشكل تلقائي إلى التابع المعالج للحدث.
معلومات ّ
26
أساسيات إطار العمل Vue.js التعامل مع DOM
>'<div id='app
><button v-on:click="increase(2)">Increase!</button
><p>{{counter}}</p
></div
الشيفرة السابقة مألوفة ،مع مالحظتين جديدتين .األولى أ ّننا لم نكتفي بكتابة اس م الت ابع المع الج للح دث
(الح ظ ش يفرة .)HTMLبالمقاب ل ،إذا ت أملت ش يفرة JavaScriptض من تعري ف الت ابع increaseفي
Vue.jsهذا األمر ببساطة من خالل تمرير الكلمة المحجوزة $eventإلى الت ابع المع الج باإلض افة إلى القيم ة
الكيفي ة الم راد تمريره ا .إذا أردن ا تط بيق ذل ك على المث ال األخ ير فسيص بح تعري ف ال زر buttonعلى
النحو التالي:
وبالنسبة لتعريف التابع المعالج ضمن القسم methodsفسيصبح على النحو التالي:
27
أساسيات إطار العمل Vue.js التعامل مع DOM
كيفية االستجابة لألح داث ،فربم ا نحت اج في وقت م ا إلى إيق اف
ّ نحتاج في بعض األحيان أن ُنعدّ ل على
االستجابة لحدث ما ألحد العناصر دو ًنا عن العناصر األخرى في .HTMLلكي أضرب لك مث ااًل جمياًل ح ول ه ذا
ّ
مؤش ر الف أرة األمر ،اسمح لي أواًل أن أقدّ م لك حدث حركة الفأرة .mousemoveيُ ّ
ول د ه ذا الح دث عن د م رور
>"<div id="app
>'<p v-on:mousemove='updateCoordinates
)}}Mouse cursor at: ({{x}}, {{y
></p
></div
حرك الف أرة ف وق العنص ر الوحي د الظ اهر أمام ك .ستحص ل على
ثم ّ
جرب تنفيذ التطبيق البسيط السابقّ ،
ّ
28
أساسيات إطار العمل Vue.js التعامل مع DOM
ّ
لمؤش ر الف أرة (الفاص لة xوال تراتيب )yض من معي ً
أيض ا كي ف نحص ل على اإلح داثيات الحالي ة
التابع :updateCoordinates
;this.x = event.clientX
;this.y = event.clientY
اآلن إذا أردنا أن ننشئ منطقة "ميتة" (ضمن عنصر spanمثال) ضمن عنصر pال ذي يع رض اإلح داثيات،
ّ
مؤش ر الف أرة ف وق ه ذه المنطق ة إلى تولي د الح دث ،mousemoveفينبغي علين ا عن دها بحيث ال يؤدّ ي مرور
>"<div id="app
>'<p v-on:mousemove='updateCoordinates
Mouse cursor at: ({{x}}, {{y}}) -
><span v-on:mousemove='uncoveredArea'>Uncovered Area</span
></p
></div
بالنس بة للت ابع uncoveredAreaفق د أج ريت تع ديل على الح دث من خالل اس تدعاء
التابع )( stopPropagationمن الكائن .eventالمعنى الحرفي لهذا الت ابع ه و "إيق اف االنتش ار" أي أ ّنن ا
ّ
مؤشر الفأرة فوق العنصر .span سنمنع االستجابة لهذا الحدث عندما يمر
ّ
مؤشر الفأرة ف وق عنص ر .spanإذا جرب تنفيذ التطبيق السابق ،والحظ التغيير الذي سيحدث عندما يمر
ّ
أردت اإلحساس بالفرق ،يمكنك أن تحذف التعليمة )( event.stopPropagationثم أعد تنفي ذ التط بيق
29
أساسيات إطار العمل Vue.js التعامل مع DOM
ّ
مؤش ر الف أرة ف وق عنص ر spanه ذه الم رة. تتغير عن دما يم ر
ّ م ّرة أخ رى ،ل ترى كي ف أنّ اإلح داثيات س
يمكن استخدام صيغة أبسط للتعديل على األحداث ،فمن الممكن حذف الت ابع uncoveredAreaبالكام ل من
''=v-on:mousemove.stop
أي أ ّننا قد استغنينا عن الشيفرة الالزمة إليقاف انتش ار الح دث .mousemoveنس مي .stopهن ا بمع ِّدل
الحدث ( )event modifiersوهناك عدّ ة معدّ الت أحداث مفيدة سنستعرض بعضها في هذا الكتاب.
يشبه إلى حدّ كبير ما كنّا نفعله م ع أح داث الف أرة .إذا أردن ا مثاًل اإلنص ات إلى ح دث تحري ر مفت اح من لوح ة
'v-on:keyup='methodName
>"<div id="app
><input type='text' v-on:keyup='keyIsUp' /
><p
}}{{message
></p
></div
تم تحري ر مفت اح من لوح ة المف اتيح، يعم ل ه ذا التط بيق البس يط على تح ديث الحق ل ّ message
كلم ا ّ
وبالتالي سيؤدّ ي ذلك إلى تحديث محتويات عنصر pضمن الواجهة.
30
أساسيات إطار العمل Vue.js التعامل مع DOM
أي مفت اح يُ ح رِّ ره المس تخدم .الج واب ببس اطة ،ه و في اس تخدام مع دّ ل الح دث .spaceبع د
وليس عن د ّ
.keyupأضف فقط الكلمة .spaceإلى keyupإلى المثال السابق .أي على النحو التالي:
'v-on:keyup.space = 'keyIsUp
أع د تنفي ذ التط بيق ل ترى أنّ محتوي ات عنص ر pأص بحت ال ُتح دَّ ث إاّل بع د تحري ر المفت اح .space
تمث ل جمي ع المف اتيح على لوح ة المف اتيح ،فهن اك مثاًل enterو tab
يوجد بالطبع العديد من المعدّ الت التي ّ
ّ
يتمث ل أبس طها في إرس ال المحت وى ال ذي أدخل ه لمع دّ الت أح داث لوح ة المف اتيح الكث ير من الفوائ د،
المستخدم بمجرد ضغطه للمفت اح ،Enterأو إرس ال البيان ات مباش ر ًة بينم ا يكتبه ا المس تخدم للحص ول على
مقترحات أثناء عملية الكتابة (كما يفعل مح ّرك البحث غوغ ل أثن اء كتاب ة المس تخدم للمف ردات الم راد البحث
في معظم األمثلة السابقة عم دنا إلى اس تخدام رب ط باتج اه واح د ،من الش يفرة إلى عنص ر .HTMLوفي
بعض الحاالت استطعنا أن نعكس ه ذا األم ر .أي اس تطعنا تع ديل قيم ة الحق ل عن طري ق االنص ات إلى ح دث
مخصص لهذه الغاية .ولكن توجد طريقة مباشرة وس هلة إليج اد
ّ اإلدخال v-on:inputوبالتالي معالج حدث
>"<div id="app
><input type='text' v-model='name'/
}} {{ name
></div
31
أساسيات إطار العمل Vue.js التعامل مع DOM
التطبيق السابق بس يط ،وه و يعم ل على إج راء رب ط ثن ائي االتج اه بين الحق ل nameوبين عنص ر مر ّب ع
2.7ختام الفصل
كيفي ة التعام ل م ع ،DOMحيث تح دثنا عن الق والب ،وكي ف نص ل إلى البيان ات
ّ ّ
تعلمن ا في ه ذا الفص ل
ّ
وتعلمن ا كيفي ة الرب ط كيفية الربط مع السمات ،والتعامل م ع األح داث،
ّ والتوابع بشيء من التفصيل ،كما ّ
تعلمنا
2.8تمارين داعمة
2.8.1تمرين 1
يُ طلب في هذا التمرين تطوير تطبيق اآللة الحاسبة البسيط الذي بنين اه في الفص ل الس ابق .بحيث يس مح
التطبيق الجديد بإجراء العمليات الحسابية األرب ع ب داًل من عملي ة الجم ع الوحي دة ال تي ك ان ي دعمها التط بيق
الحسابية األربع.
32
أساسيات إطار العمل Vue.js التعامل مع DOM
أرجو أن يتمكن التطبيق من تمييز حالة القسمة على صفر ،وإظهار رسالة مناسبة للمستخدم.
2.8.2تمرين 2
ستحتاج بالطبع إلى التعامل مع أحداث لوحة المفاتيح ،ولكي يكون األمر أكثر سهولة بالنسبة إليك ،يمكن ك
[
',السعودية'
',البحرين'
',مصر'
',السودان'
',ليبيا'
',الجزائر'
',المغرب'
',تونس'
',موريتانيا'
',العراق'
',سوريا'
',لبنان'
',قطر'
',اإلمارات'
',الصومال'
',جزر القمر'
',الكويت'
ُمان'
',سلطنة ع
',األردن'
',اليمن'
'فلسطين'
]
33
.3الموجهات الشـرطية والتكرارية
ّ
سنتعلم في هذا الفصل:
ّ
سنتعلم فيه كيفية كتابة شفرات JavaScriptمباشر ًة ضمن نتابع عملنا في هذا الفصل وهو الفصل الثالث،
الق والب دون الحاج ة إلى االس تعانة ب التوابع كم ا كنَّا نفع ل من قب ل ،باإلض افة إلى اس تخدام
التص يير ( )renderingالش رطي باس تخدام v-ifوأخوات ه v-elseو .v-else-ifكم ا س نتحدّ ث عن
باستخدام .v-for
يمكننا في الكثير من األحيان أن نكتب شيفرة JavaScriptمباشر ًة ضمن القوالب ،دون الحاجة إلى إنش اء
تابع خاص ووضعه في قسم .methodsنلجأ إلى ه ذا األس لوب ،في ح ال ك انت الش يفرة قص يرة وال تحت وي
على الكثير من التعقيد ،باإلضافة إلى ضرورة أن يكون الناتج النهائي للشيفرة عبارة عن تعب ير (.)expression
>"<div id="app
<span>Current temperature:</span><input type='text' v-
>model='temperature' /
><p
'{{temperature > 35 ? 'Hot': temperature < 20 ? 'Cold' : 'Moderate
}}
></p
></div
يعمل التطبيق السابق على عرض مر ّب ع إدخال للمستخدم ،حيث يعرض عليه إدخال درجة الحرارة الحالية،
إذا كانت درجة الحرارة أكبر من ،35سيعرض التطبيق الرسالة Hot •
إذا كانت درجة الحرارة أصغر من ،20سيعرض التطبيق الرسالة Cold •
ّ
يتحق ق الش رطان الس ابقان س يعرض التط بيق الرس الة Moderateأي معت دل. إذا لم •
النصي:
إذا نظرت إلى قسم HTMLفستجد الشيفرة التالية ضمن االستبدال ّ
شيفرة JavaScriptهذه عبارة عن تعبير بسيط يستخدم العامل ( )operatorالثالثي ?:بشكل مت داخل
35
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
الحظ معي أ ّننا قد استخدمنا هن ا الرب ط ثن ائي االتج اه ' 'v-modelلرب ط قيم ة الحق ل temperature
مباشرة بدخل المستخدم (يمكنك العودة للفصل السابق لمراجعة هذا الموضوع) .الح ظ ً
أيض ا أنّ ك ائن Vue.js
الموجه v-ifلوحده:
ّ
>"<div id="app
>"<button v-on:click="show = !show
!Click this
></button
>"<p v-if="show
!Welcome to Hsoub Academy
></p
></div
التطبيق السابق بسيط ،تتكوّ ن الواجهة من زر عادي ورسالة .عند نقر هذا الزر بشكل متك ّرر ،تظه ر الرس الة
في األسفل أو تختفي ً
وفقا لذلك.
المعرف ضمن قسم ،dataوالذي أسندت إلي ه القيم ة ' 'trueافتراض ًيا .بالنس بة
ّ نالحظ أواًل الحقل show
36
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
الموجه v-ifض من عنص ر pال ذي س يحتوي على النص .Welcome to Hsoub Academy
ّ وضعت
الموجه قيمة الحقل .showفعندما تكون قيمة showتساوي trueس يظهر عنص ر pم ع الرس الة
ّ أسندت لهذا
المطلوبة للمستخدم ،وإاّل س يختفي عنص ر pبش كل كام ل ،ليس من أم ام المس تخدم فحس ب ،وإ ّنم ا من كامل
تلعبه عب ارة elseفي ،JavaScriptانظ ر إلى المث ال البس يط الت الي وه و تع ديل بس يط عن المث ال الس ابق،
>"<div id="app
>"<button v-on:click="show = !show
!Click this
></button
>"<p v-if="show
!Welcome in Hsoub Academy
></p
><p v-else
!Welcome in Vue.js
></p
></div
><p v-else
!Welcome in Vue.js
></p
الموج ه v-elseوهك ذا فعن دما ينق ر المس تخدم ال زر بش كل متك رر ،س تتناوب
ّ اس تخدمت
اوي tureيظهر ة showتس ون قيم دما تك ذلك بين trueو falseعن ال ة showتبعً قيم
الميزة في استخدام العنصر templateهو أ ّنه ال يظهر في DOMعند عرض الصفحة .فه و يلعب دور حاوي ة
ال ُت َّ
صير عند عرض الصفحة .سأعدّ ل المثال السابق ضمن قسم HTMLفقط:
>"<div id="app
>"<button v-on:click="show = !show
37
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
!Click this
></button
>"<template v-if="show
><h2
!Welcome to Hsoub Academy
></h2
><p
Here you can learn Vue.js.
></p
></template
></div
templateوهكذا س نتمكّن من إخف اء كام ل العنص ر templateم ع العناص ر الموج ودة ض منه ،أو إظه اره
مر معنا.
بعناصره ،وذلك بحسب قيمة الحقل showكما ّ
المناسب الحتياجاتك.
بالكامل من .DOM
>"<div id="app
>"<button v-on:click="show = !show
!Click this
></button
>"<p v-if="show
!Welcome to Hsoub Academy
></p
></div
38
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
انقر اآلن على الزر ،سيختفي النص ب الطبع .انظ ر إلى ناف ذة العناص ر م ّرة أخ رى ،لتج د أنّ عنص ر pال ذي
ّ
وحل مكانه رمز تعليق ( )commentكما في الش كل الت الي تماما من المستند،
يحتوي النص السابق قد اختفى ً
(الحظ المستطيل األحمر):
39
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
من الممكن توليد قائمة من العناصر اعتبا ًرا من بيانات موجودة على شكل مصفوفة وذلك بشكل تلقائي من
عموم ا .ليكن
ً الموجه ،v-forوهو يشبه إلى حدّ كبير حلقة forالتكراريّ ة في لغ ات البرمج ة
ّ خالل استخدام
لدينا مص فوفة اس مها fruitsتحت وي على العناص ر التالي ة Apple :و Bananaو Orangeو .Kiwiنري د
إظهار هذه البيانات ضمن قائمة غير مر ّتبة .يمكن استخدام البرنامج التالي:
>"<div id="app
><ul
><li v-for='fruit in fruits'>{{fruit}}</li
></ul
></div
'v-for='fruit in fruits
المعرف ضمن
ّ أما fruitsفهو نفس الحقل
المتغير fruitهنا كيفي ،يمكنك استخدام أي اسم آخرّ .
ّ اسم
ل fruitsمن خدمة من الحق ودة ض ات الموج ل على البيان الطبع أن نحص من الممكن ب
الموجه :v-for
ّ
40
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
اإلضافتين الجديدتين )fruit, i( :و ({{ .)}}iالحظ كيف وض عنا المتغ ير fruitأواًل ثم المتغ ير
ال ذي س يع ّبر عن ال دليل بع ده ،واالثن ان ض من قوس ين ع اديين ( )fruit, iوال ترتيب به ذه الص ورة مهم
بالطبع .عند التنفيذ سيظهر دليل كل عنصر بج واره بين قوس ين ع اديين ،م ع المالحظ ة أنّ ال ترقيم س يبدأ من
ّ
المتمث ل صفرا ،وهذا بديهي بالطبع .في الواقع ي ذكرني ه ذا األس لوب
ً األول سيكون
الصفر ،أي أنّ دليل العنصر ّ
في استخالص الدليل ،بأسلوب لغة البرمجة بايثون في ذلك.
الكائن التالي:
يمكنك بالطبع استخدام أي عنصر من HTMLلعرض هذه القيم .ستظهر كل قيمة ضمن عنصر pخاص بها.
إذا أردن ا تط وير المث ال البس يط الس ابق ،بحيث يص بح من الممكن أن يك ون ل دينا مجموع ة من
نمر على هذه المجموع ة ،م ع ع رض خص ائص ك ل ك ائن (زب ون) منه ا ،فإ ّنن ا
الزبائن ( )customersونريد أن ّ
41
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
>"<div id="app
>'<div v-for='customer in customers
>'<div v-for='value in customer
><p
}}{{value
></p
></div
><hr
></div
></div
الحظ كيف أجريت تعدياًل على اسم الحقل customerليصبح customersضمن القسم dataمن كائن
وجهي v-forالمت داخلين ،يم ّر الخ ارجي على ك ل عنص ر من عناص ر المص فوفة .Vue.jsالح ظ ً
أيض ا م ّ
،customersفي حين يم ّر ال داخلي على جمي ع قيم الخص ائص الموج ودة ض من ك ائن customerمح دّ د.
42
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
الخاصية دون اسمها .يمكن بأس لوب مش ابه لعملي ة الحص ول على
ّ في المثالين األخيرين حصلنا على قيمة
الخاصية باإلضافة إلى قيمته ا .أج ِر التع ديل البس يط الت الي
ّ دليل العنصر ضمن المصفوفة ،الحصول على اسم
الح ظ أن Vue.jsت راقب بعض تواب ع المص فوفة customersال تي تعاملن ا معه ا في المث ال الس ابق
Vue.jsإلى إحداث تغيير فوري على الخرج يتوافق مع التغيير الذي حدث .هذه التوابع هي:
)(push
)(pop
)(shift
)(unshift
)(splice
)(sort
)(reverse
43
أساسيات إطار العمل Vue.js الموجهات الشـرطية والتكرارية
تلقائيا رغم
ًّ بعد تنفيذ البرنامج ونقر هذا الزر ،ستالحظ أنّ الزبون الذي اسمه Hasanقد ُأ ضيف إلى الخ رج
3.6ختام الفصل
3.7تمارين داعمة
3.7.1تمرين 1
أجر تعدياًل على التطبيق الزبائن customersالسابق .في هذه المرة يجب أن تظه ر أس ماء الزب ائن فق ط،
ضمن عنصر القائمة المنسدلة selectوذلك باستخدام ً v-for
أيضا.
3.7.2تمرين 2
يُ طلب في هذا التمرين ،تط وير التط بيق الموج ود في التم رين 2من الفص ل الس ابق .ه ذه الم رة س تجعل
44
.4المزيد حول كائن Vue.js
ّ
سنتعلم في هذا الفصل:
المستَ هدَ ف
فصل القالب عن عنصر ُ HTML •
سنتعرف على المكوّ نات والحاجة إليها ،وسنبني تطبيق بسيط للغاية يعتمد على مكوّ ن يعم ل على التحوي ل من
ّ
من الممكن إنشاء أكثر من كائن Vue.jsضمن نفس التطبيق .حيث يمكن ربط كل كائن بعنصر divكما ك ّن ا
ً
مسبق ا .يمكن لكل كائن أن يعمل بصورة مستقلة عن الكائن اآلخر ،وفي ذلك فائدة كبيرة ،إذ يمكننا تقس يم نفعل
واجهة المستخدم الرئيسية إلى أجزاء متعدّ دة ،كل منها ّ
ينفذ وظيفة محدّ دة ،بدون أن تتداخل مع بعضها.
مهما في
في الحقيقة تقودنا هذه الميزة المهم ة إلى بن اء المكوّ ن ات ( .)Componentsيلعب المك وّ ن دو ًرا ًّ
البرمجية وفي عملية إعادة االستخدام للشيفرة من ِق َبلك ،أو من ِق َبل أي شخص آخر .سنتحدّ ث
ّ تنظيم الشيفرة
بسيطا ّ
يوضح كيفية إنشاء أكثر من كائن واحد بنفس الوقت: ً لنأخذ اآلن مثااًل
>"<div id="app1
}}{{title
></div
>"<div id="app2
}}{{title
></div
متغيرين منفصلين instance1و .instance2الكائنين متشابهين من حيث الشكل العام ولكنهم ا يختلف ان
46
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
عند تنفيذ التطبيق السابق ستحصل على شكل شبيه بما يلي:
من الواضح ظهور نصين مختلفين من كائنين مختلفين ،رغم أ ّنه لك ل منهم ا نفس اس م الخاص ية .title
يمكن ب الطبع وج ود أك ثر من ك ائنين ،ويمكن بديه ًة أن يك ون لك ل ك ائن عت اده الخ اص من الخص ائص
والدوال وغيرها.
مهمة لكائن ات ،Vue.jsوهي إمكاني ة الوص ول ألي ك ائن من ش يفرة JavaScriptعادي ة. توجد ً
أيضا ميزة ّ
انظر إلى المثال المعدّ ل عن المثال السابق (التعديل سيكون على شيفرة JavaScriptفقط):
التعديل الوحيد الذي حدث هو في السطر األخير .انظر كيف كتبت شيفرة JavaScriptعادية للوصول إلى
الخاصية titleللكائن .instance1بعد التنفيذ ستحصل على شكل شبيه بما يلي:
األول .استطعت تعديل النص من خ ارج الك ائن .وهن اك أم ر آخ رّ ،
لعل ك ق د الحظ معي كيف أصبح السطر ّ
انتبهت إلى الخاص ّية .$dataفي الحقيق ة ه و ك ائن ّ
يول ده Vue.jsبش كل تلق ائي لكي يس مح للم برمجين
هذا دليل واضح على أنّ Vue.jsمندمجة بشكل ممتاز مع JavaScriptوليست بدياًل عنها ،إ ّنما ّ
مكمل ة له ا.
ّ
المولدة بهذه الطريقة. سنشاهد عددً ا من هذه الكائنات والدوال
47
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
باستخدام المفت اح .refيس مح ه ذا المفت اح للم برمج بالوص ول إلى أي عنص ر HTMLبس هولة كب يرة .يمكن
>"<div id="app
>'<button v-on:click='changeText' ref='testButton
Old Text
></button
></div
الجديد هنا هو وضع الكلمة refكما لو أ ّنها س مة ض من العنص ر buttonوإس ناد القيم ة testButton
له ا .الكلم ة refليس ت س مة قياس ية في HTMLبالتأكي د ،إنم ا هي كلم ة تابع ة لـ .Vue.jsانظ ر اآلن إلى
الخاص بالجمع آخر كلمة ،$refsأل ّن ه من الممكن اس تخدام أك ثر من كلم ة refم ع عناص ر HTMLمختلف ة.
عند تنفيذ التطبيق السابق .ستحصل على زر وحيد يحمل النص .Old Textبعد نقر الزر ،ستحص ل على
نصح بتعديل خصائص عناصر HTMLبهذا األسلوب ،أنص ح باس تخدام ه ذا األس لوب فق ط
في الواقع ال يُ َ
لقراءة خصائص عناصر HTMLفي حال الحاجة.
48
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
سنتحدّ ث في هذه الفقرة عن مفه وم الخص ائص أو الخاص يات المحس وبة (،)Computed Properties
والحاجة إليها عند بناء تطبيقات باستخدام .Vue.jsتشبه بنية الخصائص المحس وبة البني ة الخاص ة ب التوابع،
ُت ّ
عرف الخصائص المحسوبة ضمن قسم جديد اسمه computedيُ وضع على نفس مس تو القس مين data
>"<div id="app
<span>Current temperature:</span><input type='text' v-
>model='temperature' /
><span> - Clouds:</span
>'<select v-model='clouds
><option>Yes</option
><option>No</option
></select
><p
)<b>Result:</b> (Computed) {{evaluation_computed}} | (Method
}})({{evaluation_method
></p
><p
}}'{{clouds == 'Yes'? 'With some clouds.':'And the sky is clear.
></p
></div
49
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
بعد تنفيذ البرنامج السابق ستحصل على خرج شبيه بما يلي:
عرفت مربع نص ،باإلض افة إلى عنص ر قائم ة منس دلة
بالنسبة لقسم HTMLأعتقد أنّ األمور واضحة ،فقد ّ
يحمل القيمتين Yesو Noلإلش ارة إلى وج ود غي وم في الس ماء أم ال .ك ل من العنص رين الس ابقين مرب وطين
فيما إذا كان حا ًرا أم معتداًل أم باردً ا بحسب قيمة الحقل ،temperatureوالحظ هنا أ ّنني أعرض التق ييم من
الخاصية المحس وبة evaluation_computedوالت ابع )( evaluation_methodعلى الت والي لغ رض
المعرف ض من
ّ انتبهت إلى أ ّن ني ال أضع قوسي االستدعاء بعد اسم الخاصية المحسوبة على عكس التابع العادي
القسم .methods
50
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
أيضا أ ّنني ق د
تماما .والحظ ً
evaluation_computedأم في التابع )( evaluation_methodمتطابقة ً
وضعت في كل منهما تعليمة الكتابة إلى الطرفية ( )consoleالخاصة بأدوات المطوّ ر ض من المتص ّفح ل نراقب
كيف ستُ َّ
نفذ كل منهما.
ستالحظ ظهور الكلمتين Computedو Methodعلى التوالي ،مما يشير إلى أنّ التنفيذ قد دخل إلى الخاصية
قد ظهرت وحدها ضمن الطرفية ،ولن تظهر الكلمة Computedمما يشير إلى أنّ الش يفرة البرمجي ة الموج ودة
ضمن الخاصية المحسوبة لم ُت َّ
نفذ!
تم تغييره ا بش كل أو ب آخر ،فتختص ر عملي ة التنفي ذ وتع رض التق ييم الس ابق
ضمنها ال تحتوي على خصائص ّ
الناتج التالي نتج معي بع د تغي ير حال ة الغي وم ع دّ ة م رات دون تغي ير قيم ة درج ة الح رارة س وى الم ّرة
األولى فقط:
رغم أنّ الخصائص المحسوبة كافية في معظم األحيان إاّل أ ّن ه هن اك بعض الح االت ال تي يك ون اس تخدام
َ
المراقب ة ( )Watched Propertiesتش به إلى ح دّ كب ير الخص ائص الخصائص المراقبة أفض ل ،والخص ائص
51
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
.1يمكن تنفيذ شيفرة برمجية غير متزامنة ضمنها ،بمعنى أ ّنه يمكن تنفيذ مهام بشكل متوازي مع التطبيق
َ
المراقبة كما كنّا نفعل مع الخصائص المحسوبة. .2ال نحتاج إلى إرجاع قيمة من الخصائص
ُتع ّرف الخص ائص المحس وبة ض من قس م جدي د اس مه watchيُ وض ع على نفس مس توى ب اقي األقس ام
بسيطا:
ً لنأخذ مثااًل
>"<div id="app
><input type="text" v-model='content' /
><p
The input has changed: {{counter}} times.
></p
></div
52
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
}
)}
اس تخدمت في المث ال الس ابق مرب ع إدخ ال نص ي يس مح للمس تخدم بكتاب ة م ا ي رغب .عن دما يكتب
استخدمت الربط ثنائي االتجاه باستخدام v-modelللربط مع الحقل ( contentراجع الفص ل الث اني).
وضعت نفس اسم الحقل contentضمن القسم watchكما هو واضح ،وأسندت إليه ت ابع .ه ذه هي الص يغة
لزيادة قيمة الحقل counterبعد ثانيتين في ح ال ح دث أي تغي ير علي ه .اعتم دت ه ذا األس لوب ،لكي ألفت
ّ
نفذ التطبيق السابق ،وابدأ بالكتابة والتعديل ض من مر ّب ع النص .س تالحظ أنّ قيم ة الع دّ اد س تتزايد بينم ا
تجري التع ديالت ض من مر ّب ع النص ،ولكن ه ذا التزاي د ال يح دث ف و ًرا ،إ ّنم ا بت أخير زم ني ق دره ث انيتين عن
التعديالت الفعلية.
نفذ ضمن ّ
مغلف ( )Closureوبالتالي لن ُتش ير الكلم ة thisإذا البرمجية ستُ ّ
ّ والسبب في ذلك أنّ الشيفرة
ً
سابقا. خدمت مباشر ًة إلى كائن Vue.jsكما اعتدنا
استُ ِ
اس تخدمنا في جمي ع األمثل ة ال تي تعاملن ا معه ا ح تى اآلن القس م elمن ك ائن Vue.jsلتحدي د العنص ر
ّ
سيمثل الق الب templateال ذي س يعمل التط بيق على تعديل ه والتعام ل مع ه كم ا وس بق أن المستَ هدف الذي
ُ
53
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
القسم elفي هذه الحالة ،وذلك في اللحظة التي نريد فيها الربط م ع عنص ر مح دّ د .انظ ر إلى المث ال البس يط
>"<div id="app
}}{{title
></div
الحظ أ ّنني قد حذفت القسم ،elوهكذا ،وعند تنفيذ المثال السابق ستحصل على الخرج التالي:
}}{{title
أي أنّ Vue.jsلم يعرف في هذه الحالة الق الب ال ذي س يتعامل مع ه .لح ل ه ذه المش كلة وإظه ار الرس الة
سطرا واحدً ا فقط إلى شيفرة JavaScriptالسابقة ،لتصبح الشيفرة على النحو التالي:
ً المناسبة ،سنضيف
;)'app.$mount('#app
المهمة جدًّ ا في Vue.jsحيث أ ّنها تسمح ببناء المكوّ نات ال تي س نتحدّ ث عنه ا
ّ ُتعتبر هذه الميزة ،من المزايا
بعد قليل.
54
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
بسيطا ّ
يوضح هذه الفكرة: ً لنأخذ مثااًل
>"<div id="app
></div
ّ
نفذ المثال السابق لتحصل على الجملة:
Hsoub Academy
55
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
;)}
;)'app.$mount('#app
;)'app.$mount('#app
الشيفرة السابقة سهلة ومباشرة .بعد التنفيذ ستحصل على شكل شبيه بما يلي:
وجود {{ .}}titleهناك مالحظة بسيطة أخرى حول شيفرة HTMLالمكتوبة ضمن القالب .يجب أن يحتوي
المسنَد إلى القسم templateعلى عنصر جذر واحد ،في مثالنا السابق أنشأت عنصر divلهذا الغرض،
القالب ُ
ووضعت فيه العنصرين h2و pكما هو واضح.
عام ة عب ارة عن وح دة برمجي ة مس تقلة ب ذاتهاُ ،تنج ز عماًل واح دً ا على الغ الب .نص ادف
المكوّ ن بص ورة ّ
كثيرا في ع الم البرمجي ات .وإذا أردت أمثل ة عنه ا في ع الم ال ويب ،فج داول البيان ات ال تي تع رض
ً المكوّ نات
ً
وأيضا المساحات الص غيرة الموج ودة على ج انب المعلومات المختلفة للمستخدم مع مزايا الترشيح والترتيب،
الصفحة التي تعرض درجة الحرارة الحالية أو أسعار الصرف للعمالت ،كلها عبارة عن مكوّ نات.
وبص ورة عام ة أي ناحي ة وظيفي ة يمكن أن ُتس تخدَ م بش كل متك رر في نفس المش روع ال برمجي أو في
برمجية مختلفة يمكن أن ُت ّ
رشح لتصبح مكو ًنا. ّ مشاريع
56
Vue.js أساسيات إطار العمل Vue.js المزيد حول كائن
ً
س أبني.الحق ا سنؤجل ذلك إلى فص ول
ّ حيث، ولن ندخل في تفاصيلها،سنالمس المكوّ نات في هذا الفصل
انظ ر إلى. وظيفت ه التحوي ل من واح دة الكيل وغرام إلى واح دة الباون د،في هذا الفص ل مك وّ ن بس يط للغاي ة
:التطبيق التالي
<div id="app">
<weightconverter></weightconverter>
<weightconverter></weightconverter>
<weightconverter></weightconverter>
</div>
// commnet
var app = new Vue({
el: '#app',
components: {
'weightconverter': wcComponent
}
});
ّ
: ستحصل على شكل شبيه بما يلي،نفذ التطبيق السابق
األول من ه ذه
ّ لنب دأ بالقس م.JavaScript لننظ ر اآلن إلى ش يفرة. بعد قلي لHTML سأتحدث عن شيفرة
57
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
المتغي ر .wcComponent
ّ كما هو واضح فإ ّنن ا سنس ند المك وّ ن ال ذي يُ رجع ه الت ابع )( componentإلى
أما الوسيط الثاني فهو كائن آخر يحوي إعدادات المكوّ ن.
نصيةّ ،
ّ
لو تمعنت النظ ر به ذا الك ائن ،فس تجد أ ّن ه يط ابق ك ائن Vue.jsقياس ي م ع اختالف واح د بس يط .يكمن
االختالف في القسم .dataفي كائنات Vue.jsال تي أنش أناها ح تى اآلن ك ّن ا ُنس ند للقس م dataك ائن ع ادي
{ )(data: function
{ return
pounds: 0
}
}
أما القسم الثاني من شيفرة JavaScriptفتحتوي على تعريف كائن Vue.jsع ادي ،ولكن م ع وج ود قس م
ّ
جديد وهو القسم .componentsهذا القسم يحتوي على أيّ ة مكونات سيستخدمها التطبيق ،وهي في حالتن ا
58
أساسيات إطار العمل Vue.js المزيد حول كائن Vue.js
المتغي ر
ّ نسجل المكونات التي نريد استخدامها :اس م المك وّ ن يلي ه المرج ع ل ه (موج ود ض من
ّ الحظ كيف
wcComponentبالطبع).
بالنس بة إلى ش يفرة HTMLفهي بس يطة ،حيث نس تخدم العنص ر الجدي د weightconverterض من
شيفرة HTMLكما لو أصبح عنصر HTMLنظامي .اس تخدمت ه ذا العنص ر ثالث م ّرات من ب اب توض يح أ ّن ه
4.8ختام الفصل
4.9تمارين داعمة
4.9.1تمرين 1
أجر تعدياًل على تطبيق تحويل الوحدات الذي بنين اه قب ل قلي ل ،بحيث يس مح بالتحوي ل باالتج اهين :من
كيلوغرام إلى باوند ،ومن باوند إلى كيلو غرام بشكل مباشر.
4.9.2تمرين 2
أنشئ مكوّ ًن ا جدي دً ا ،عب ارة عن م ّ
ؤقت زم ني تن ازلي ( .)Countdown Timerقيمت ه االبتدائي ة دقيق ة
واحدة ،ثم يتناقص حتى يصل للصفر .ثم استخدام هذا المكوّ ن ضمن تطبيق بسيط لتجربته فقط.
59
.5مدخل إىل التعامل مع المكونات
ّ
سنتعلم في هذا الفصل:
ّ
محلي. تجهيز هيكل التطبيق على حاسوب •
جي د .سيعمل هذا التطبيق البسيط على السماح للمستخدم بعرض بعض المهام ال تي
أسس بناء المكوّ نات بشكل ّ
ينوي تنفيذها فيما بع د ،م ع إمكاني ة تحدي د فيم ا إذا ك ان ق د أنج ز المه ام أم ال باس تخدام زر اختي ار بس يط.
وسنضيف إليه ميزة ترشيح بسيطة إلخفاء أو إظهار المهام المنجزة ،باإلضافة إلى إمكانية إضافة مهام جديدة.
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
عم ا اعتدناه في الفصول السابقة .كان تركيزنا في الفصول الس ابقة منص ًّبا
مغايرا ّ
ً منحى
المرة ً
سنسلك هذه ّ
ّ
التعلم أو تج ريب جي د في الواق ع عن دما نري د
على كتابة تطبيقات vue.jsضمن موقع ،JSFiddleوهذا األم ر ّ
بعض المزايا الخفيفة .ولكن عند االنتقال إلى مستوى أعلى ببناء تطبيقات عملية وواقعية ،ينبغي علينا بالتأكي د
تشتمل هذه األدوات بطبيعة الح ال على خ ادوم نس تخدمه أثن اء بن اء التط بيق ،نح اكي من خالل ه س لوك
الخ واديم الفعلي ة ال تي ستستض يف تطبيقن ا النه ائي ال ذي س يعمل علي ه المس تخدم في نهاي ة المط اف .في
دوم ا بجع ل ظ روف تج ريب التط بيق مماثل ة ق در المس تطاع لم ا س يكون علي ه الوضع
الحقيق ة ،أنص ح ً
النهائي للتطبيق.
المحرر الذي ترغب به ،أو حتى يمكنك استخدام بيئة تطوير متكاملة
ّ من .Microsoftيمكنك في الواقع اختيار
يمكنك اختي ار نظ ام التش غيل المناس ب ل ك من األس فل .بالنس بة لن ا س نختار النس خة الخاص ة بوين دوز .بع د
نص ب التطبيق مع ترك الخيارات االفتراضية كما هي (قد تحتاج إلى صالحيات مدير النظام).
التنزيلّ ،
اإلضافة Live Serverالتي سنس تخدمها كخ ادوم بس يط .يمكن ك الوص ول مباش ر ًة إلى م دير اإلض افات من
الناحية اليسرى من الشاشة ،كما هو ظاهر من الشكل التالي .بع د ذل ك أدخ ل اس م اإلض افة Live Server :في
خانة البحث .بع د أن يج ده ،اخ تره ،لتظه ر الناف ذة الخاص ة ب ه كم ا في الش كل الس ابق ،ثم انق ر ال زر األخض ر
61
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
من المفيد ً
أيضا تثبيت اإلضافتين التاليتين:
اكتب اس م ك ل من ه اتين اإلض افتين في خان ة البحث ،واعم ل على تثبيتهم ا كم ا فعلن ا قب ل قلي ل مع
أنصح بإعادة تشغيل Visual Studio Codeعند هذه المرحلة حتى ولو لم يطلب منك ذلك.
ّ
مجل دً ا لنبدأ ببناء مشروعنا! انتقل إلى المكان الذي ترغب فيه بإنشاء المشروع على القرص الصلب ،وأنشئ
مرة أخرة إلى Visual Studio Codeثم اختر األمر Open Folder >- File
سمه .veujs-mytasksانتقل ّ
ّ
توا. ّ
المجلد الذي أنشأته ًّ واختر
ّ
مؤش ر من نافذة المستكشف Explorerالموجودة في الطرف األيسر ،الح ظ األيقون تين الص غيرتين ،ض ع
الفأرة للحظات فوق كل منهما لتكتشف وظيفة كل منهما .األيقونة األولى من اليسار وظيفتها إنشاء ملف جدي د
ّ
المجلد الحالي. ّ
مجلد جديد ضمن ّ
المجلد الحالي ،واأليقونة األخرى وظيفتها إنشاء ضمن
62
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
اس تخدم زر مل ف جدي د لتُ نش ئ ملفين ،واخ تر االس مين index.htmlو app.jsلهم ا على ال ترتيب.
63
Vue.js أساسيات إطار العمل مدخل إىل التعامل مع المكونات
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>My Tasks</title>
<meta name='viewport' content='width=device-width, initial-
scale=1'>
</head>
<body>
<h1>Welcome to MyTasks Application</h1>
<p>This application is built to explain how to deal with
components</p>
<div id='app'>
<tasks></tasks>
</div>
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="app.js"></script>
</body>
</html>
وهوtasks األمر الجديد الوحيد فيها هو إضافة العنصر، السابقة عبارة عن شيفرة بسيطةHTML شيفرة
ال ذيapp.js باإلض افة إلى مرج ع للمل فvue.js الح ظ كي ف أض فت م رجعين لمل ف إط ار العم ل،يرا
ً وأخ
:سيحتوي على الشيفرة البرمجية لكل من المكوّ ن والتطبيق
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="app.js"></script>
Vue.component('tasks', {
template: '<strong><p>{{name}} - Tasks</p></strong>',
data() {
return {
name: 'Husam'
}
}
})
64
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
{(new Vue
'el: '#app
)}
البرمجية هنا مماثلة لتلك التي تعاملها معها في الفصل الس ابق ،حيث نس ّجل مك وّ ن جدي د باس م
ّ الشيفرة
tasksبحيث ُنس ند ل ه ق الب بس يط ،يع رض اس م الش خص ال ذي سنُس ند إلي ه ه ذه المه ام عن طريق
انتقل اآلن إلى ناف ذة المستكش ف ،Explorerوانق ر ب زر الف أرة األيمن على المل ف index.htmlثم اخ تر
األمر ( Open with Live Serverتذكّر أننا ثبتنا اإلضافة Live Serverقب ل قلي ل) ،س يؤدي ذل ك إلى فتح
ناف ذة أو تب ويب جدي د ض من متص ّفح االن ترنت االفتراض ي ل ديك بحيث يتج ه إلى العن وان
ه ذا دلي ل على أنّ األم ور تس ير على م ا ي رام .وأنّ نجحن ا ببن اء الهيك ل الع ام للتط بيق .لننتق ل اآلن
للمرحلة التالية.
لنب دأ اآلن بالعم ل الفعلي في بن اء المك وّ ن الخ اص بالمه ام ،وال ذي أس ميناه .tasksس أنقل أواًل ش يفرة
HTMLالمسندة للحقل templateضمن المكوّ ن ،وأضعها ضمن مكان منفصل أل ّنها ستص بح بع د قلي ل كب يرة
'template: '#tasks-template
65
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
الحظ أنني قد عرضت مكان التعديل فقط طل ًبا لالختصار .الجديد هنا أ ّنني وضعت مع ّرف الق الب الجدي د
ال ذي س يحتوي على الش يفرة .انتق ل اآلن إلى المل ف index.htmlوأض ف الش يفرة التالي ة مباش ر ًة بعد
كم ا ت رى أج ريت بعض التع ديل على ش يفرة HTMLال تي ك انت موج ودة س ً
ابقا .انتق ل اآلن إلى
المتصفح ثم حدثها (إن لم ُتحدّ ث بشكل تلقائي) ،يجب أن تحصل على شكل ق ريب
ّ الصفحة index.htmlفي
العنصر scriptوالذي تحمل السمة typeله القيمة text/x-templateكم ا ه و واض ح .باإلض افة ل ذلك
الحظ كيف جعلت قيمة المعرف idله نفس القيمة التي أسندتها للحقل templateضمن المكوّ ن قبل قليل.
من المهم جدًّ ا تحقيق مبدأ الفصل في بناء المكوّ نات .أل ّنه كلما أصبح المك وّ ن أك ثر تعقي دً ا كم ا س ترى بع د
قليل ،كلما برزت الحاجة إلى تحقيق مبدأ الفصل بشكل أفضل.
ُكسب اآلن مكوّ ننا الوليد بعض المزايا اإلضافية لكي يصبح قاد ًرا على عرض بعض المهام للمستخدم .أج ر
لن ِ
التعديالت التالية ضمن الملف app.jsليصبح مشابهً ا لما يلي:
{ Vue.component('tasks',
template: '#tasks-template',
{ )(data
{ return
name: 'Husam',
[ tasks_list:
{ title: "Write an introduction about vue.js
components.", done: true },
{ title: "Drink a cup of team.", done: false },
{ title: "Call Jamil.", done: false },
} { title: "Buy new book.", done: true
]
}
}
)}
{(new Vue
'el: '#app
)}
66
Vue.js أساسيات إطار العمل مدخل إىل التعامل مع المكونات
. يحتوي على بيانات المهام التي أرغب بعرضهاtasks_list لقد أضفت حقاًل جديدً ا أسميته،في الواقع
تضم األولى النص الخ اص: يحتوي على خاصيتين،مهم ة ضمن القائمة عبارة عن كائن بسيط
ّ الحظ كيف أنّ كل
.false أم ليس بعدtrue أما الثانية فتضم قيمة منطقية تشير إلى أنّ المهمة قد ُن ّفذت
ّ ،بالمهمة
ليص بح مم اثاًل، وأجر بعض التع ديالت ال تي س تكون أك بر ه ذه الم رةindex.html انتقل اآلن إلى الملف
:لما يلي
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>My Tasks</title>
<meta name='viewport' content='width=device-width, initial-
scale=1'>
<style>
.tasks-container {
border-width: 1px;
border-style: solid;
display: inline-block;
margin-right: 20px;
padding: 8px;
}
.w3-table-all {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
display: table;
border: 1px solid #ccc
}
.w3-table-all tr {
border-bottom: 1px solid #ddd
}
.w3-table-all tr:nth-child(odd) {
background-color: #fff
}
.w3-table-all tr:nth-child(even) {
background-color: #f1f1f1
}
.w3-table-all td,
.w3-table-all th {
67
Vue.js أساسيات إطار العمل مدخل إىل التعامل مع المكونات
.w3-table-all th:first-child,
.w3-table-all td:first-child {
padding-left: 16px
}
.w3-table-all th{
background-color: #d0d0d0;
}
</style>
</head>
<body>
<h1>Welcome to MyTasks Application</h1>
<p>This application is built to explain how to deal with
components</p>
<div id='app'>
<tasks></tasks>
</div>
68
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
></td
><td
}} {{ task.title
></td
></tr
></tbody
></table
></div
></script
><script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script
><script src="app.js"></script
></body
></html
ّ
متصفح اإلنترنت لديك لتحصل على شكل شبيه بما يلي: حدّ ث الصفحة index.htmlضمن
نسبيا ،إاّل أنّ األمر في الحقيقة ليس كذلك .ح دثت نس بة
ً ّ
ومعقدة ربما تشعر أنّ الشيفرة قد أصبحت كبيرة
كب يرة من التع ديالت عن دما أض فت عنص ر التنس يق styleم ع تنس يقاته إلى المل ف .index.htmlك ان من
األفضل وضع تنسيقات CSSضمن ملف مستقل ،وهذا ما سأعمل عليه بع د قلي ل .التنس يقات المس تخدمة هن ا
استعرتها من موقع W3Schoolsالشهير .باإلضافة إلى ذلك ،الحظ أ ّنني قد استخدمت عنصر الج دول table
الموجه
ّ البرمجي ة واض حة ،باس تثناء
ّ لع رض قائم ة المه ام .ع دا عن ذل ك ،أعتق د أنّ معظم الش يفرة
الجديد:v-bind:key :
69
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
موج ه آخ ر مس ً
بقا ،وه و v-bind:hrefوذل ك في الفص ل الث اني (اس تخدام ّ في الواقع لقد استخدمنا
vue.jsللتعام ل م ع .)DOMلكنن ا سنس تخدم الي وم الكلم ة keyب داًل من .hrefالس تخدام v-bind:key
من الواضح أ ّنه في الوضع الحالي ،من غير الممكن لنا أن نع دّ ل على أي مهم ة بحيث تص بح ّ
منف ذة أو غ ير
ّ
منفذة .سنعمل في الفقرة التالية على تحسين تجربة االستخدام ،بتوفير إمكانية إجراء هذه التعديالت.
سنعمل اآلن على السماح للمستخدم بتعديل حالة المهم ة وذل ك بإض افة عنص ر اختي ار .Checkboxقب ل
ذلك دعنا ننقل تنسيقات CSSإلى ملف منفصل .أنشئ ملف جديد ضمن نافذة المستكشف في Visual Studio
انق ل محتوي ات العنص ر styleفي المل ف index.htmlإلى ملفن ا الجدي د ،ثم اح ذف العنص ر .style
الستخدام التنسيقات ضمن الملف الجديد ،أضف مرجعً ا إليه في المل ف index.htmlض من القس م headعلى
النحو التالي:
تغييرا ضمن الشيفرة البرمجية للق الب فق ط ،وتحدي دً ا بالقس م الخ اص بإنه اء أو ع دم إنه اء
ً سنجري اآلن
...
><td
}} {{ task.done
></td
...
...
><td
><input type="checkbox" v-model="task.done"/
></td
...
70
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
الحظ أ ّنني قد استخدمت الربط ثنائي االتجاه " v-model="task.doneللربط الثنائي للبيانات.
االختصارات في vue.js
لعلك قد الحظت أ ّننا استخدمنا بيانات ثابتة في التعامل مع مكوّ ن المهام .ولكن في الواقع العملي سنحتاج
إلى أن تكون هذه البيانات قابلة للتغيير كما هو واضح ,لهذا الهدف ّ
توفر المكوّ نات في vue.jsميزة الخص ائص
في الحقيقة للخصائص الموجودة ضمن القسم propsفوائد مهم ة عن دما س نتحدث عن المكون ات المتداخل ة
ً
الحق ا في الفصل التالي ،حيث سنستخدمها لتمرير البيانات من المكون األساسي إلى المكون الفرعي.
لنبدأ بإجراء التعديالت الالزمة .أجر التعديالت التالية في الملف app.jsليصبح على الشكل التالي:
71
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
{ Vue.component('tasks',
template: '#tasks-template',
{ props:
name: String,
tasks_list: Array
}
)}
{(new Vue
'el: '#app
)}
لقد أزلت قسم dataوأضفت بداًل منه القسم ( propsيمكن بالطبع أن يكون ا معً ا بنفس ال وقت) .ع رفت
{ props:
name: String,
tasks_list: Array
}
الوسيط األول هو nameوهو من النوع Stringأي نص ،والوس يط الث اني ه و tasks_listوه و من
نوع Arrayأي مصفوفة كما هو واضح .بالنسبة لطريقة االستخدام فهي سهلة ج دا .أج ر التع ديل الت الي على
مررت البيانات إلى المكوّ ن كما لو أ ّنها وسوم عادية .الشيء الوحيد الملفت للنظ ر ه و أ ّن ني ق د اس تخدمت
ّ
الموجه v-bind:عند تمرير المصفوفة tasks_listوهذا األمر إلزامي عن د تمري ر وس ائط ديناميكي ة إلى
المكوّ نات ،في حين أ ّنه ال يجب استخدام هذا الموج ه عن د تمري ر وس ائط نص ية س اكنة كم ا فعلن ا عن د تمري ر
الوسيط .name
الحظ أنه يوجد العديد من أنواع الوسائط التي يمكن تمريرها إلى المكونات وهي:
72
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
لنعم ل اآلن على اس تخدام أك ثر من مك ون واح د ض من الص فحة لنكتش ف ق وة المكون ات .انس خ ش يفرة
حدث الصفحة index.htmlمن جديد لتحصل على شكل شبيه بما يلي:
يمكننا بسهولة أن نستخدم هذا المكون في المكان الذي نحتاج إلي ه في الص فحة ،كم ا يمكن مش اركته م ع
اآلخرين .مازال هناك الكث ير للتح دث عن ه ح ول المكوّ ن ات ،س نتناول في الفص ول الالحق ة العدي د من المزاي ا
الخاصة بها ،والطرق المثالية للتعامل معها .يمكنك الحصول على الشيفرات الكاملة بالملفات الثالث ة ال تي عملن ا
><!DOCTYPE html
><html
><head
>'<meta charset='utf-8
>'<meta http-equiv='X-UA-Compatible' content='IE=edge
><title>My Tasks</title
<meta name='viewport' content='width=device-width, initial-
>'scale=1
>"<link rel="stylesheet" href="tasks.css
></head
><body
73
Vue.js أساسيات إطار العمل مدخل إىل التعامل مع المكونات
<div id='app'>
<tasks name='Husam' v-bind:tasks_list='[{ title: "Write an
introduction about vue.js components.", done: true },
{ title: "Drink a cup of tea.", done: false },
{ title: "Call Jamil.", done: false },
{ title: "Buy a new book.", done: true }]'></tasks>
74
Vue.js أساسيات إطار العمل مدخل إىل التعامل مع المكونات
</table>
</div>
</script>
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="app.js"></script>
</body>
</html>
:tasks.css الملف •
.tasks-container {
border-width: 1px;
border-style: solid;
display: inline-block;
margin-right: 20px;
padding: 8px;
}
.w3-table-all {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
display: table;
border: 1px solid #ccc
}
.w3-table-all tr {
border-bottom: 1px solid #ddd
}
.w3-table-all tr:nth-child(odd) {
background-color: #fff
}
.w3-table-all tr:nth-child(even) {
background-color: #f1f1f1
}
.w3-table-all td,
.w3-table-all th {
padding: 8px 8px;
display: table-cell;
text-align: left;
vertical-align: top
}
.w3-table-all th:first-child,
.w3-table-all td:first-child {
padding-left: 16px
75
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
}
{.w3-table-all th
;background-color: #d0d0d0
}
{ Vue.component('tasks',
template: '#tasks-template',
{ props:
name: String,
tasks_list: Array
}
)}
{(new Vue
'el: '#app
)}
كثيرا ما ستحتاج في التطبيقات التي س تكتبها إلى م يزة الترش يح بص رف النظ ر عن ن وع التط بيق ال ذي
ً
تبنيه .سنتناول في هذه الفقرة كيفية إضافة هذه الميزة إلى مكوّ ن المهام.
رغم أنّ هذه الميزة بسيطة ،وتنحصر وظيفتها في إخفاء (أو إظهار) المهام المنجزة ،إاّل أ ّنها ستعطيك فكرة
س نكمل على الش يفرة األخ يرة لتط بيق المه ام .س تكون م يزة التص فية على ش كل ص ندوق
اختي ار Checkboxموج ود أعلى قائم ة المه ام .عن دما يخت اره المس تخدم ف إنّ المه ام المنج زة س تختفي،
والعكس صحيح.
سنبدأ بإضافة عنص ر االختي ار ه ذا إلى المل ف index.htmlض من القس م الخ اص بق الب المك وّ ن .أض ف
الح ظ معي أنّ ه ذا العنص ر مرتب ط بحق ل اس مه hide_competed_tasksس نعرفه بع د قلي ل ض من
مكوّ ن المهام.
76
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
افتح اآلن الملف app.jsوأض ف القس مين dataو computedللمك وّ ن .tasksس يحتوي قس م data
على تعريف الحقل hide_competed_tasksالمرتب ط بعنص ر ص ندوق االختي ار ال ذي أض فناه قب ل قلي ل،
وسيكون من النوع المنطقي ،Booleanفي حين أنّ القسم computedفس يحتوي على الخاص ية المحس وبة
{ Vue.component('tasks',
template: '#tasks-template',
{ props:
name: String,
tasks_list: Array,
},
{ )(data
{ return
hide_completed_tasks: false
}
},
{ computed:
{ )(filtered_tasks
? return this.hide_completed_tasks
;this.tasks_list.filter(t => !t.done) : this.tasks_list
}
}
)}
إذا تأملت معي محتويات الخاصية المحسوبة filtered_tasksفستجدها عبارة عن ش يفرة برمجي ة
بسيطة لتصفية المهام المنجزة من خالل اختبار قيمة الخاصية .doneأي أنّ عملية التصفية ستحدث في ه ذا
ه ذا ك ّل ش يء! إذا أحببت اآلن ،انق ر ب زر الف أرة األيمن على المل ف index.htmlالموج ود ض من ناف ذة
المستكشف ،Explorerواختر األمر Open with Live Serverكما اعتدنا من قبل .ستحصل على شكل
77
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
متكرر على صندوق االختي ار Hide completed tasksلتج د كي ف أنّ المه ام
ّ جرب اآلن أن تنقر بشكل
المنجزة تختفي وتظهر ً
وفقا لذلك.
مقبول لهما.
{ .add-task-container
;position: relative
;margin-top: 10px
}
{.add-task-container div
;position: absolute
;top: 0
;right: 60px
;left: 45px
}
78
Vue.js أساسيات إطار العمل مدخل إىل التعامل مع المكونات
.add-task-container input{
position: absolute;
width:50px;
top: 0;
right: 0;
}
وأضف الشيفرة التالية بعد نهاية وسم اإلغالق للجدول مباشر ًة (ض منindex.html انتقل اآلن إلى الملف
<div class="add-task-container">
<span>Task: </span>
<div>
<input type="text" v-model="new_task_text"/>
</div>
<input type="button" value="Add" v-on:click="add_new_task"/>
</div>
واح رص على أن تك ون محتويات ه، افتح هذا المل ف.app.js حان اآلن دور الشيفرة البرمجية ضمن الملف
Vue.component('tasks', {
template: '#tasks-template',
props: {
name: String,
tasks_list: Array,
},
data() {
return {
hide_completed_tasks: false,
new_task_text : ""
}
},
computed: {
filtered_tasks() {
return this.hide_completed_tasks ?
this.tasks_list.filter(t => !t.done) : this.tasks_list;
}
},
methods: {
add_new_task(event) {
this.tasks_list.push({ title: this.new_task_text, done:
false });
this.new_task_text = "";
}
}
})
79
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
{(new Vue
'el: '#app
)}
الجديد هنا هو أ ّنني أضفت حقاًل جدي دً ا إلى القس م dataوأس ميته new_task_textس يرتبط بمرب ع
النص الذي سندخل من خالله عنوان المهمة .كم ا ق د أض فت القس م methodsوع رفت ض منه الت ابع الجدي د
الشيفرة البرمجية الموجودة في هذا التابع بسيطة ،فهي تعمل على إض افة المهم ة الجدي دة إلى مص فوفة
جرب كتابة المهمة التالية My new task! :ضمن مربع النص ،ثم انق ر ال زر .Addستحص ل على ش كل
80
أساسيات إطار العمل Vue.js مدخل إىل التعامل مع المكونات
5.8ختام الفصل
بدأنا في هذا الفصل بالولوج في عالم المكوّ نات ،إذ يُ عتبر ما تناولناه في هذا الفصل مقدّ مة بس يطة إاّل أنه ا
مهمة في التعامل مع المكونات حيث تعلمنا كيف نبني هيكاًل لتط بيق بس يط على حاس وبنا الشخص ي ،وكيفي ة
ّ
وتعلمنا أساسيات فصل ش يفرة مبسط لمحاكاة عمل التطبيق بشكل فعلي ،كما بنينا مكوّ ًنا مفيدً ا،
إضافة خادوم ّ
vue.jsعن ب اقي التط بيق .هنال ك المزي د ّ
لتعلم ه ح ول المكوّ ن ات وح ول vue.jsبص ورة عام ة في الفص ول
5.9تمارين داعمة
ابتداء من
ً أنشئ مكوّ ًنا باسم vu-countdowntimerوظيفته العد التنازلي بمقدار ثانية واحدة كل ّ
مرة،
81
.6التعمق في مكونات Vue.js
ّ
سنتعلم في هذا الفصل:
مخصصة.
ّ التخاطب بين المكوّ نات باستخدام أحداث •
ّ
المتعلق ة به ا ،وال تي نتعرف على المزي د من المزاي ا
ّ ّ
سنتعلم في هذا الفصل المزي د عن المكوّ ن ات ،حيث س
ستساعدنا على بناء مكوّ نات عملية ومفيدة .سنبدأ هذا الفصل ببناء تطبيق نموذجي س يكون الهيك ل األساس ي
سنبني من أجل هذا الفصل تطبيق نموذجي بسيط لكي نطبق عليه األفكار التي سنتاولها هنا .س يكون ه ذا
التطبيق عبارة عن واجهة بسيطة لمحل افتراض ي بي ع مش روبات متنوع ة .س يع ّبر المك وّ ن في ه ذه الم رة عن
ّ
مجل دً ا جدي دً ا س ّمه hsoub-drinks كما ترى فإ ّنني أستخدم اللغة العربية في التطبيق هذه الم ّرة! أنش ئ
حاليا أسميته drinkأي مشروب ما .لهذا المك وّ ن خاص ّية وحي دة
ً يحتوي هذا التطبيق على مكوّ ن وحيد
اسمها nameتع ّبر عن اسم هذا المش روب .انظ ر إلى ش يفرة Vue.jsال تي سأض عها ض من المل ف app.jsال ذي
توا: ّ
المجلد hsoub-drinksالذي أنشأته ًّ سيكون موجودً ا ضمن
{ Vue.component('drink',
template: '#drink-template',
{ props:
{ name:
type: String
}
}
;)}
{(new Vue
el: '#app',
83
Vue.js أساسيات إطار العمل Vue.js التعمق في مكونات
data: {
drinks: [" "بابونج," "زهورات," "شاي أخضر," "قهوة,"]"شاي
}
})
<html lang="ar">
<body>
<div class="header">
<span id="logo"><مشروبات حسوب/span>
</div>
<div class="drinks">
<drink v-for="drink in drinks" v-
bind:name="drink"></drink>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="app.js"></script>
<link rel="stylesheet" href="app.css" />
</body>
</html>
84
Vue.js أساسيات إطار العمل Vue.js التعمق في مكونات
وبالت الي تولي دdrinks في المرور على عناصر المص فوفةv-for مر معنا فيما سبق نستخدم حلقة
ّ كما
َّ
ّ المولدة وال تي
تمث ل ً الح ظ. كم ا ه و واض ح من الش يفرة الس ابقةdrink عنص ر المك وّ ن
أيض ا أنّ العناص ر
أرج و أن ال يختل ط علي ك.drinks يحم ل الص نفdiv المشروبات المتوفرة ستكون موج ودة ض من عنص ر
وه ذا أمر، ألنّ كليهم ا يحمالن نفس االس مdrink وبين ص نف التنس يقdrink األم ر بين اس م المك وّ ن
.تماما
ً جائز
:hsoub-drinks المجلد
@import url(//fonts.googleapis.com/earlyaccess/notonaskharabic.css);
body {
height: 100vh;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: 'Noto Naskh Arabic', serif;
background-color: #ccdcdc;
background-repeat: no-repeat;
background-position: 100% 100%
}
span#logo {
font-weight: 700;
color: #eee;
font-size: larger;
letter-spacing: .05em;
padding-left: .5rem;
padding-right: .5rem;
padding-bottom: 1rem;
float: right;
padding-top: 6px;
margin-right: 20px;
}
.header{
background-color:slategray;
width: 80% ;
height: 50px;
margin-left: auto;
margin-right: auto;
}
h1.title {
text-align: center;
font-size: 1.875rem;
85
Vue.js أساسيات إطار العمل Vue.js التعمق في مكونات
font-weight: 500;
color: #2d3336
}
h2.subtitle {
margin: 8px auto;
font-size: x-large;
text-align: center;
line-height: 1.5;
max-width: 500px;
color: #5c6162
}
.content {
margin-left: auto;
margin-right: auto;
padding-top: 1.5rem;
padding-bottom: 1.5rem;
width: 620px
}
.drinks {
padding: 0 40px;
margin-bottom: 40px
}
.drinks .drink {
background-color: #fff;
-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
margin-top: 1rem;
margin-bottom: 1rem;
border-radius: .25rem;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
cursor: pointer;
position: relative;
-webkit-transition: all .3s ease;
transition: all .3s ease
}
.drinks .drink>.description {
width: 100%;
padding: 1rem;
}
86
Vue.js أساسيات إطار العمل Vue.js التعمق في مكونات
.drinks .drink>.price {
width: 20%;
color: #09848d;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
padding-top: 1.5rem;
font-family: Crimson Text, serif;
font-weight: 600
}
87
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
;bottom: 0
;left: 0
right: 0
}
ً
جاهزا .نستطيع اآلن المتابعة مع موضوعات هذا الفصل. أصبح التطبيق النموذجي
ح دّ كب ير .تظه ر ه ذه األدوات ض من أدوات المط وّ ر ال تي يمكن الوص ول إليه ا بض غط المفت اح .F12
يمكنك زيارة هذه الصفحة لالطالع على كيفية تثبيت هذه األدوات.
بعد أن تثبت األدوات السابقة ،يمكنك الوص ول إليه ا بض غط المفت اح F12كم ا أش رنا ،ثم تبحث عن لس ان
التبويب ( Vue.jsقد تحتاج إلى نقر زر عرض المزيد في حال لم تجد لسان التبويب هذا) .انظ ر الش كل الت الي
88
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
6.3المكونات المتداخلة
نحتاج في بعض األحيان إلى جعل المكونات متداخلة فيما بينها ،كأن يك ون هن اك مك وّ ن أساس ي (مك وّ ن
أب) يستخدم مكوّ نات أصغر (مكوّ نات أبناء) ضمنه .سنوظف هذا المفهوم ضمن التطبيق النموذجي السابق.
سأض يف مكوّ ًن ا جدي دً ا ض من المل ف app.jsوسأس ّمه .drink-selectorس يلعب ه ذا المك وّ ن دور
المك وّ ن األساس ي ال ذي يح وي المك وّ ن drinkال ذي س يكون ض منه بش كل مت داخل .انظ ر إلى محتوي ات
{ Vue.component('drink',
template: '#drink-template',
{ props:
{ name:
type: String
}
}
)}
{ Vue.component('drink-selector',
template: '#drink-selector-template',
{ )(data
{ return
]"شاي"" ,قهوة"" ,شاي أخضر"" ,زهورات"" ,بابونج"[ drinks:
}
}
)}
{(new Vue
'el: '#app
)}
الحظ معي كيف نقلت البيانات الخاصة بالتطبيق من كائن Vue.jsإلى المكوّ ن .drink-selectorلهذا
ً
الحقا إن شاء اهلل. األمر فائدة سنراها
مكوّ ننا الجديد .وسننقل إليه الشيفرة الخاصة بتوليد قائمة المشروبات .انظر محتوى القالب:
89
Vue.js أساسيات إطار العمل Vue.js التعمق في مكونات
<html lang="ar">
<body>
<div class="header">
<span id="logo"><مشروبات حسوب/span>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="app.js"></script>
<link rel="stylesheet" href="app.css" />
</body>
</html>
ً
يمكن ك اآلن أن تنشئ.إذا اس تطعنا اس تخدام مك وّ ن ض من مك وّ ن آخ ر بش كل مت داخل
<drink-selector></drink-selector>
90
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
األس لوب ال ذي اس تخدمناه ح تى ه ذه اللحظ ة باس تخدام الت ابع .Vue.componentواألس لوب اآلخ ر ه و
سجلتها على المستوى العام وذلك في التطبيق النهائي ،حتى ولو لم تستخدمها في ذل ك التط بيق .وه ذا يع ني
زيادة في حجم شيفرة JavaScriptالتي على المس تخدمين تحميله ا من اإلن ترنت دون فائ دة .ه ذا فض اًل عن
مش اكل من الناحي ة التص ميمية للتط بيق .ففي تطبيقن ا األخ ير مثاًل ،لن نس تخدم المك وّ ن drinkخ ارج
لحل هذه المشكلة ،وبالتالي تسجيل المكوّ ن ات بش كل محلي إذا اقتض ى األم ر ذل ك ،فيمكنن ا بك ل بس اطة
{ = let drink_component
template: '#drink-template',
{ props:
{ name:
type: String
}
}
}
{ Vue.component('drink-selector',
template: '#drink-selector-template',
{components:
drink: drink_component
},
{ )(data
{ return
91
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
كما يمكن بطبيعة الحال فعل األمر ذاته مع المكوّ ن drink-selectorأي تسجيله محليا بدون استخدم
التابع Vue.componentفي حال أردنا استخدام هذا المكوّ ن فقط ضمن صفحة محدّ دة ضمن تطبيق ال ويب.
{ = let drink_selector_component
template: '#drink-selector-template',
{components:
drink: drink_component
},
{ )(data
{ return
]"شاي"" ,قهوة"" ,شاي أخضر"" ,زهورات"" ,بابونج"[ drinks:
}
}
}
الجواب بكل بساطة ،وبما أ ّنه ال يوجد مكوّ ن رئيسي يمكن أن يُ َّ
عرف المك وّ ن drink-selectorض منه،
فسنسجله ضمن كائن Vue.jsالخاص بالتطبيق باستخدام القسم ً components
أيضا:
{(new Vue
el: '#app',
{components:
'drink-selector': drink_selector_component
}
)}
الحظ معي أ ّنني قد عرفت اسم المكوّ ن ه ذه الم رة على ش كل نص drink-selector :بش كل مختل ف
عن تعري ف المك وّ ن .drinkالس بب في ذل ك أ ّن ني أرغب باالس تمرار باس تخدام الرم ز -ض من اس م المك ون
تمام ا ب الطبع .إذا أردت االطالع على الش كل النه ائي للمل ف app.jsبع د
drink-selectorوه ذا ج ائز ً
التعديالت األخيرة ،انظر إلى الشيفرة التالية:
92
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
{ = let drink_component
template: '#drink-template',
{ props:
{ name:
type: String
}
}
}
{ = let drink_selector_component
template: '#drink-selector-template',
{components:
drink: drink_component
},
{ )(data
{ return
]"شاي"" ,قهوة"" ,شاي أخضر"" ,زهورات"" ,بابونج"[ drinks:
}
}
}
{(new Vue
el: '#app',
{components:
'drink-selector': drink_selector_component
}
)}
قدما في تطبيق المشروبات ،حيث س نعمل اآلن على إض افة م يزة تحدي د المش روب ال ذي اخت اره
لنمضي ً
ُكس ب ّ
المتطلب ات البس يطة ،حيث سن ِ المس تخدم عن طري ق النق ر علي ه بالف أرة .تحت اج ه ذه الم يزة إلى بعض
عرف ضمن القسم dataكما نعلم ،لتحديد فيما إذا كان المكوّ ن drinkحقاًل جديدً ا اسمه ُ is_selected
سي ّ
المستخدم قد اختار هذا المشروب أم ال ،باإلضافة إلى تزوي ده بت ابع جدي د يس مح باختي ار المش روب ولنس ّمه
selectوالذي سيحتوي على تعليمة برمجي ة واح دة تجع ل قيم ة الحق ل is_selectedمس اوية للقيم ة
،trueأي تع ّب ر عن عملي ة االختي ار .انظ ر كي ف س يبدو ش كل المك ون drinkبع د إض افة التع ديلين
السابقين عليه:
{ = let drink_component
template: '#drink-template',
{ props:
{ name:
type: String
}
93
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
},
{ )(data
{ return
is_selected: false
}
},
{ methods:
{ )(select
;this.is_selected = true
}
}
}
المكوّ ن drinkلالستجابة لحدث النقر .انظر التعديالت التالية على القالب :drink-template
ع د إلى المتص ّفح لمعاين ة التغي يرات (ت ذكّر أ ّنن ا نس تعرض المل ف index.htmlض من
الخادوم .)Live Serverجرب أن تنقر على المشروبين" :شاي" و "ش اي أخض ر" ،ثم انتق ل إلى ناف ذة أدوات
المطوّ ر بضغط ،F12ومن هناك انتقل إلى لسان التبويب .Vueانشر العقد في حال احتجت ذلك ،ستحصل على
94
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
جرب أن تعاين حالة المشروب التالي "قهوة" ستجد أن قيمة الحق ل is_selectedل ه تس اوي false
أل ّنن ا لم ننق ر على القه وة .ج رب اآلن أن تع اين حال ة المش روب الت الي "ش اي أخض ر" ،س تالحظ أنّ
ّ
متوق ع من ه ح تى اآلن. حاليا يعم ل كم ا ه و
ً قيمة is_selectedفي هذه الحالة هي .trueأي أنّ التطبيق
بقي أن نض يف بعض الت أثيرات البص رية البس يطة لإلش ارة إلى أنّ المش روب ق د اخت ير من قب ل المس تخدم.
النحو التالي:
س ُيط ّبق تنس يق CSSالمس مى ' 'active-drinkفق ط عن دما تك ون قيم ة الحق ل is_selected
تس اوي trueأي عن دما يخت ار المس تخدم المش روب الح الي .وال حاج ة بطبيع ة الح ال الس تخدام عالم ة
االقتباس المفردة في حال لم يحتوي اسم الصنف على رمز مثل .-بقي أن نضيف تنسيق CSSنفس ه إلى مل ف
95
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
عد إلى المتصفح واختر المشروب األول والثالث مرة أخرى لتحصل على شكل شبيه بما يلي:
تمت المهمة بنجاح! ولكن ،ماذا لو أردنا اختيار مشروب واح د فق ط من القائم ة؟ س نحل ه ذه المش كلة
لقد ّ
مخصصة.
ّ ّ
سنتعلم كيفية التخاطب بين المكوّ نات المختلفة باستخدام أحداث في الفقرة التالية حيث
برزت الحاجة في الفقرة السابقة إلى اختي ار مش روب واح د فق ط من قائم ة المش روبات المتاح ة .أي أ ّنن ا
معينة تسمح باختيار مشروب واحد فقط ،بحيث تعمل هذه اآللي ة على إلغ اء أي اختي ار س ابق
بحاجة إلى آلية ّ
أخيرا.
ً لمشروب ما ( في حال وجوده) ضمن القائمة ،واإلبقاء على المشروب الذي اختاره المستخدم
يمكن تحقيق ه ذا األم ر بالتخ اطب بين المك وّ ن االبن drinkوالمك وّ ن األب drink-selectorحيث
المكوّ ن األب drink-selectorبأن مشروبًا ما قد اختاره المستخدم ،فيعمل عندئذ المك ون األب على إلغ اء
اختيار أي مشروب سابق يمكن أن يكون قد اختير من قبل ،باستثناء المشروب الحالي.
قبل المتابعة ،توقف عن الق راءة قلياًل ،حض ر كو ًب ا من الش اي (أو القه وة) ،ثم ع د إلى هن ا من جدي د ،ألنّ
96
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
سنبدأ من الملف app.jsحيث س نجري بعض التع ديالت على المك ونين drinkو .drink-selector
استخدمنا في المثال في الفقرة السابقة الحق ل is_selectedلإلش ارة إلى ك ون المش روب الح الي •
قد اختير أم ال .سأحول ه ذا الحق ل إلى خاص ية محس وبة ( )Computed Propertyباإلض افة إلى
أ ّنني سأحذف قسم dataبشكل كامل ،وسنرى سبب ذلك باإلضافة بعد قليل.
ألول م رة الت ابع المض ّمن $emitض من الت ابع ( selectب داًل من التعليم ة
كم ا سأس تخدم ّ •
ان ّ
نبلغ المكون األب بأن المشروب الحالي ق د اخت ير ،وذل ك ب أن أم ّرر اس م ه ذا المش روب كوس يط ث ٍ
للتابع .emit$
سأضيف ً
أيضا خاصية جدي دة اس مها selectedDrinkإلى المك ون drinkض من القس م props •
وذل ك لكي أس مح للمك ون األب فيم ا بع د ،بتمري ر اس م المش روب (مك ون )drinkال ذي اخت اره
{ = let drink_component
template: '#drink-template',
{ props:
{ name:
type: String
},
{selectedDrink:
type: String
}
},
{computed:
{)(is_selected
;return this.selectedDrink === this.name
}
},
{ methods:
{ )(select
)this.$emit('drink_selected_event', this.name
}
}
}
97
Vue.js أساسيات إطار العمل Vue.js التعمق في مكونات
ال ذي سأص دره (باس تخدام الت ابع المض ّمنdrink_selected_event معالج ا للح دث
ً س يكون
وهو الذي سيحتفظ باسم المكوّ نdata ضمن القسمcurrent_drink أضفت حقاًل جديدً ا أسميته •
.توا
ًّ (المشروب) الذي اختاره المستخدم
let drink_selector_component = {
template: '#drink-selector-template',
components: {
drink: drink_component
},
data() {
return {
drinks: [" "بابونج," "زهورات," "شاي أخضر," "قهوة,"]"شاي,
current_drink: null
}
},
methods:{
drink_selected_handler(drink_name){
this.current_drink = drink_name;
}
}
}
مبيتً ا
ّ الموج ه ليس
ّ ه ذا.v-on:drink_selected_event للموج ه
ّ األول ه و اس تخدامي
ّ األمر •
98
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
المبيت .$emit
ّ
الموجه االبن.
ّ الموجه األب ،مع الخاصية selectedDrinkمن
ّ الحقل current_drinkمن
)this.$emit('drink_selected_event', this.name
التي تعمل على اس تدعاء ح دث مخص ص للتخ اطب م ع المك وّ ن األب ،حيث يق ول المك وّ ن االبن للمك وّ ن
علما أنّ اسم المك وّ ن االبن (اس م المش روب) س ّ
يمرر ض من الوس يط الث اني من تم اختياري!"ً ،
األب" :انظر لقد ّ
الموجه "v-on:drink_selected_event="drink_selected_handlerضمن
ّ بسبب وجود
األب ،حيث تعمل تعليمة بسيطة ضمنه على إسناد اسم المشروب (المكون االبن) الذي اختاره المس تخدم ض من
الحق ل current_drinkوبه ذه الطريق ة يع رف المك وّ ن األب من ه و المش روب الح الي ال ذي
اختاره المستخدم.
س تؤدي ه ذه المعرف ة ،وبس بب طبيع ة Vue.jsإلى تح ديث ق الب المك وّ ن بكامل ه ،وبالت الي س ّ
تنفذ
جميع المشروبات الموجودة ضمن المكوّ ن األب عن طريق الخاصية selectedDrinkوبالت الي س يعرف ك ل
هذه التعليمة بسيطة للغاية ،وهي ُترجع قيمة من النوع المنطقي tureإذا كان اسم المكوّ ن الحالي يط ابق
اسم المكوّ ن "المحظوظ" الذي اختاره المستخدم .أو ُترجع القيمة falseإذا لم تتحقق هذه المطابقة.
الموج ه
ّ زبدة القول ،فإنّ القيمة التي سترجعها الخاصية المحسوبة is_selectedهي التي ستُ سند إلى
99
أساسيات إطار العمل Vue.js التعمق في مكونات Vue.js
نستنتج مما سبق ،أ ّنه يمكن للمكوّ ن األب أن يرسل رسائل إلى المكوّ ن االبن الموجود ضمنه ،عن طريق
الخصائص التي نعرفها ضمن القسم propsفي المكون االبن ،التي ُتعتبر مستقبالت للمكون االبن تسمح
أما عندما يريد المكون االبن مخاطبة المكون األب ،فيمكن ذلك
له بالتقاط الرسائل من خارجه بشكل عامّ .
مخصصة باستخدام التابع $emitكما أوضحنا في المثال األخير.
ّ عن طريق أحداث
جرب التطبيق بعد التعديالت األخيرة .الحظ كيف أصبح يسمح باختيار مشروب واحد فقط.
6.7ختام الفصل
لقد تناولنا في هذا الفصل الكثير من الموضوعات المهمة حول المكوّ نات ،وأعتق د أ ّن ه أص بح من الض روري
االنتقال إلى مستوى أعلى ،عن طريق بناء تطبيقات بأساليب احترافية توفره ا Vue.jsلن ا .س نعمل في الفص ل
القادم إن شاء اهلل على االطالع على كيفية فصل المكوّ ن ات ض من ملف ات مس تقلة تحت وي الواح دة منه ا على
ّ
المتعلقة بالمكوّ ن مما يس اهم بتنظيم الش يفرة البرمجي ة إلى ح دّ كب ير .باإلض افة إلى االطالع جميع التفاصيل
على تقنية بناء تطبيقات Vue.jsبشكل مختلف عن طريق .Vue.js CLIح تى الفص ل الق ادم أرج و أن تكون وا
بأفضل حال!
100
.7إنشاء مشاريع باستخدام Vue CLI
ّ
سنتعلم في هذا الفصل:
وسنتعرف ً
أيض ا على كيفي ة إع داد Vue CLI ّ سنتعرف في هذا الفصل على Vue CLIولماذا نحتاج إليه.
ّ
بالتفصيل ،ثم س نعمل على موائم ة تط بيق "مش روبات حس وب" ال ذي بنين اه في الفص ل الس ابق لكي يتوافق
بدأنا أول فصل في الكتاب بكتابة التطبيقات التي نحتاج لها ض من موق ع ،JSFiddleثم طورن ا عملن ا ب أن
محليا باستخدامه،
ًّ محرر الشيفرة البرمجية Visual Studio Codeبحيث أصبحنا نكتب تطبيقاتنا
ّ استخدمنا
جيد في الواق ع ولكن ق د يك ون في بعض األحي ان غ ير ك اف .وخاص ًة إذا ب دأت بكتاب ة
السيناريو األخير ّ
تطبيقات أكبر وأكثر تعقيدً ا باستخدام المكوّ نات التي تكتبها أنت والتي تحتاج إليها في تطبيقاتك.
المشكلة التي ستواجهها هي التداخل بين الشيفرة الخاصة بالمكوّ نات مع الشيفرة الخاصة بالتطبيق ،وه ذا
يحدث على مستوى شيفرة JavaScriptو شيفرة HTMLوحتى تنسيقات .CSSفي ح ال التطبيق ات الكب يرة
سيكون هذا التداخل مزعج وأكثر عرضة لألخطاء .لذلك فمن الحكمة أحيا ًنا االنتقال إلى مستوى أعلى في بن اء
الشيفرة ،باإلضافة إلى تزويدنا بخادوم تطوير بسيط (مختلف عن الخادوم )Live Serverيسمح لن ا بمحاك اة
الظروف الفعلية التي سيعمل ض منها ه ذا التط بيق .توج د ع دة ق والب ُمتاح ة يس تطيع Vue.jsتولي دها ل ك،
نستطيع تثبيت Vue CLIعلى مختلف أنواع أنظمة التشغيل األساسية ( )Windows, Linux, Mac OS
بنفس األسلوب تقري ًبا .سأركّز هنا على نظام التشغيل .Windows
7.2.1تثبيت Node.js
رغم أ ّنن ا س نحتاج إلى Node.jsإاّل أ ّنن ا لن نكتب أي ش يفرة باس تخدامه حالي ا ،إنم ا سنس تخدم م دير
الحزم npmوهو ضروري لتثبيت ،Vue CLIباإلضافة إلى احتواءه على خادوم التطوير الذي تحدثنا عن ه قب ل
ستحتاج إلى Node.jsوتأكد أ َّنه مثبت لديك ،أو زر الموقع الخاص بـ ِّ Node.js
ونزل اإلصدار األخير من ه
(يفضل استعمال اإلصدار LTSالمستقر طويل الدعم ولكن يمكنك تنزيل أحدث إصدار .)Current
102
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
بعد تنزيل برنامج التث بيت ،ش ّغل ه ذا البرن امج (س تحتاج إلى ص الحيات م دير النظ ام) ،واتب ع خط وات
موجه األوامر في ( Windowsيمكنك ذلك من خالل ضغط مفتاح الويندوز مع المفت اح ،Rثم كتاب ة
ّ ّ
شغل
األمر cmdمباشر ًة ،ونقر زر موافق .)OKبعد ذلك اكتب األمر التالي:
موج ه
ّ بيا .بع د االنته اء ،س يعود
قصيرا نس ً
ً ستبدأ عندها عملية تثبيت Vue CLIوالتي ستأخذ ً
أيضا وقتً ا
7.2.3تثبيت Git
سنحتاج ً
أيضا إلى تطبيق إدارة اإلصدار .Gitيمكنك تحميله من هذا الرابط مع اختيار نسخة وين دوز .بع د
نص ب التط بيق (س تحتاج إلى ص الحيات م دير النظ ام) .ات رك الخي ارات االفتراض ية كم ا هي
تنزي ل المل فّ ،
باس تثناء الشاش ة ال تي تطلب من ك فيه ا تحدي د الطرفي ة االفتراض ية للـ .Gitاخ تر الخي ار
الثاني .Use Windows' default console windowثم تابع بنقر الزر Nextحتى تصل للنهاية.
103
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
موجه األوامر (ناف ذة جدي دة) واكتب األم ر الت الي لكي نتأكّ د من
ّ بعد االنتهاء من تثبيت .Gitافتح نافذة
git --version
ستحصل على إصدار النسخة الحالي إذا جرت األمور بشكل سليم.
اآلن وبعد أن انتهينا من إعداد Vue CLIأصبح بإمكاننا الشروع باستخدامه .سنبدأ بإنشاء مشروع جدي د.
وبما أ ّنن ا س نعمل على نق ل تط بيق "مش روبات حس وب" إلى Vue CLIبع د قلي ل ،ل ذلك فسنس مي المش روع
موجه األوامر:
ّ لنبدأ اآلن! اكتب األمر التالي ضمن
من السطر السابق vue :هو األمر الخ اص بتنفي ذ Vue CLIكم ا أش رنا ،الوس يط createيش ير كم ا ه و
104
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
الذي ّ
ننفذ فيه األمر السابق .اضغط المفتاح Enterلتنفيذ األمر ،سيطلب منك Vue CLIالمزيد من المعلوم ات
من الشكل السابق ،يسأل Vue CLIعن نوع القالب الذي نريد استخدمه ،توج د العدي د من الق والب ،حيث
يمكنك ضغط مفتاح السهم السفلي من لوحة المفاتيح الختيار Manually select featuresواالطالع
في بعض األحيان القليلة ،يمكن أن يحدث جمود في عملية إنشاء المشروع لسبب أو آلخر .إذا شعرت أنّ
هذه العملية قد استغرقت وقتً ا طوياًل غير منطقي ،أو أنّ عملية التحميل تقف عند حزمة محدّ دة وال
موجه األوامر،
ّ تنتقل إلى حزمة تالية ،عندها يمكنك ضغط Ctrl + Cإليقاف ،Vue CLIثم أغلق نافذة
وكرر العملية
توا ،وأعد تشغيل الحاسوب ّ ّ
المجلد hsoub-drinks-cliالذي ُأ نشأ ًّ ثم احذف
من جديد.
ّ
المجلد hsoub-drinks-cliباستخدام األمر التالي: بعد االنتهاء من إنشاء المشروع .ادخل إلى
cd hsoub-drinks-cli
ثم ّ
نف ذ األمر التالي لتشغيل خادوم التطوير البسيط الذي يأتي مع :npm
105
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
سيؤدي ذلك إلى تشغيل هذا الخادوم على المنفذ االفتراض ي 8080ليعم ل على تخ ديم ملف ات المش روع
hsoub-drinks-cliالذي أنشأناه ت ًّوا .من الممكن أن ُتفتَ ح ناف ذة جدي دة من المتص فح االفتراض ي ل ديك
بشكل تلقائي بحيث تعرض مباشرة الصفحة الرئيسية االفتراضية .أو يمكنك أن تفعل أنت ذلك بأن تفتح ناف ذة
( أو لسان تبويب) جديدة من المتصفح لديك وتنتقل إلى العنوان الت الي .http://localhost:8080 :ستحص ل
الحظ أنه ممن الممكن في بعض األحيان أن يظهر لك تنبي ه أم ني من نظ ام التش غيل ،يطلب من ك الس ماح
106
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
سيظهر المشروع ضمن نافذة المستكشف في القسم األيسر من الشاشة بشكل شبيه بما يلي:
107
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
.Vue JSكما يحتوي هذا الملف على أيّ ة حزم من طرف src/main.js
ثالث يمكن أن يستخدمها التطبيق
108
Vue.js أساسيات إطار العمل Vue CLI إنشاء مشاريع باستخدام
ّ
.المجلد الخاص بالمكوّ نات التي سنكتبها للتطبيق components
س ّم المل ف الجدي د.New File بالنقر بزر الف أرة األيمن ثم اختي ار األم رComponents جديدً ا ضمن المجلد
ّ
.)الممثل لمشروب محدّ د (راجع الفصل السابق سيحوي هذا الملف المكوّ ن.drink.vue باالسم
<template>
<div v-on:click="select" class="drink" v-bind:class="{'active-
drink': is_selected}">
<div class="description">
<span class="title">{{name}}</span>
</div>
</div>
</template>
<script>
export default {
name: "drink",
props: {
name: {
type: String
},
selectedDrink: {
type: String
}
},
computed: {
is_selected() {
return this.selectedDrink === this.name;
}
},
methods: {
select() {
this.$emit("drink_selected_event", this.name);
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
109
Vue.js أساسيات إطار العمل Vue CLI إنشاء مشاريع باستخدام
<style scoped>
.drinks {
padding: 0 40px;
margin-bottom: 40px
}
.drinks .drink {
background-color: #fff;
-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .1);
margin-top: 1rem;
margin-bottom: 1rem;
border-radius: .25rem;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
cursor: pointer;
position: relative;
-webkit-transition: all .3s ease;
transition: all .3s ease
}
.drinks .drink>.description {
width: 100%;
padding: 1rem;
}
.drinks .drink>.price {
width: 20%;
color: #09848d;
display: -webkit-box;
110
Vue.js أساسيات إطار العمل Vue CLI إنشاء مشاريع باستخدام
display: -ms-flexbox;
display: flex;
padding-top: 1.5rem;
font-family: Crimson Text, serif;
font-weight: 600
}
111
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
;top: 0
;bottom: 0
;left: 0
right: 0
}
></style
><template
...
></template
><script
...
></script
><style
...
></style
يمكن أن يحت وي أي مل ف يحم ل االمت داد ( vueوبالت الي أي مك وّ ن) على ثالث ة أقس ام ُنع ّب ر عنها
بالوس وم < >templateو < >scriptو < .>styleالوس م < >templateإل زامي ،والوس مين اآلخ رين
اختيارين .قد تظن أنّ الشيفرة السابقة معقدة بعض الشيء إاّل أ ّنها بس يطة في الواق ع .الش يفرة الموج ودة هن ا
مماثلة لتلك الموجودة في الفصل السابق إلى حدّ كبير .حيث عملت على تجمي ع جمي ع الش يفرات البرمجي ة أو
التنس يقات الخاص ة ب المكوّ ن drinkض من المل ف .drink.vueأي أنن ا اس تطعنا ع زل ك ل م ا يتعلق
يحت وي القس م < >templateعلى ش يفرة HTMLالخاص ة بق الب المك وّ ن .أم ا القس م <>script
فيحتوي على ش يفرة Vue.jsالالزم ة للمك وّ ن .أم ا القس م < >styleفكم ا ه و واض ح يحت وي على التنس يق
الالزم للمكوّ ن .يمكن في بعض األحيان (كما في حالتنا هن ا) اس تخدام الكلم ة scopedم ع الوس م <>style
أري د الترك يز على الش يفرة الموج ودة ض من القس م < .>scriptالح ظ أ ّن ني ق د اس تخدمت التعليم ة
.export defaultهذه التعليمة هي تعليم ة JavaScriptووظيفته ا الس ماح بتص دير ك ائن Vue.jsال ذي
يأتي بعدها إلى خ ارج الوح دة البرمجي ة (المل ف) drink.vueوبالت الي يمكن اس تيراده فيم ا بع د باس تخدام
112
Vue.js أساسيات إطار العمل Vue CLI إنشاء مشاريع باستخدام
ً
طفيفا على اس مه ال ذي ك ان في الفص ل والذي أجريت تعدياًلdrinksselector جاء اآلن دور المكوّ ن
ً أنشئ
س ّم.New File بالنقر بزر الف أرة األيمن ثم اختي ار األم رComponents ملفا جديدً ا ضمن المجلد
ّ سيحوي هذا الملف المك وّ ن األساس ي ال ذي.drinksselector.vue الملف الجديد باالسم
ينظم عملي ة اختي ار
<template>
<div class="drinks">
<drink
v-for="drink in drinks"
v-bind:key="drink.name"
v-bind:name="drink"
v-on:drink_selected_event="drink_selected_handler"
v-bind:selectedDrink="current_drink"
></drink>
</div>
</template>
<script>
import drink from "./drink.vue";
export default {
name: "drinksselector",
components: {
drink
},
data() {
return {
drinks: [" "بابونج," "زهورات," "شاي أخضر," "قهوة,"]"شاي,
current_drink: null
};
},
methods: {
drink_selected_handler(drink_name) {
this.current_drink = drink_name;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
113
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
الحظ معي أنّ القسم < >styleهنا فارغ .قد تتس اءل كي ف س نط ّبق التنس يق الخ اص به ذا المك وّ ن كم ا
فعلنا في الفصل السابق .في الحقيقة سيط ّبق التنسيق الالزم لهذا المكوّ ن من خالل المك وّ ن االبن .drinkرغم
أ ّنن ا وض عنا الكلم ة scopedض من القس م < >styleمن المك وّ ن drinkكم ا م ّر معن ا قب ل قلي ل ،إاّل أنّ
التنسيقات الخاصة بالمكوّ ن drinksselectorستط ّبق علي ه .الس بب في ذل ك ه و أنّ المك وّ ن drinkه و
مكوّ ن متداخل (مكوّ ن ابن) م ع المك وّ ن drinksselectorفتطب ق التنس يقات على المك وّ ن األعلى (األب)
الحظ ً
أيضا السطر الذي يلي وسم الفتح <:>script
تعم ل ه ذه التعليم ة البرمجي ة على اس تيراد ك ائن الك ائن drinkمن المل ف .drink.vueاس تطعنا
مر
استخدام التعليمة importهنا بسبب وجود التعليمة export defaultضمن الملف drink.vueكما ّ
جاء اآلن دور ملف التطبيق الرئيسي App.vueوالذي يع د بح د ذات ه مكوّ ًن ا ،ولك ّن ه المك وّ ن الرئيس ي في
><template
><div
>"<div class="header
></spanمشروبات حسوب>"<span id="logo
></div
><script
;"import drinksselector from "./components/drinksselector.vue
{ export default
name: "App",
{ components:
drinksselector
}
;}
></script
114
Vue.js أساسيات إطار العمل Vue CLI إنشاء مشاريع باستخدام
<style>
@import "./assets/styles/app.css";
</style>
.@import الذي سننشئه بعد قليل بهذا المكوّ ن عن طريق التعليمةapp.css التنسيقات
ّ
ثم اختي ارsrc وذل ك ب النقر ب زر الف أرة األيمن على المجل دsrc المجل د ّ
مجل دً ا جدي دً ا ض من أض ف اآلن
ّ
بنفسassets المجل د ّ
مجل د آخ ر ض من ّ
ثم أنش ئ.assets المجلد الجديد باالس م سم
ّ .New Folder األمر
:التنسيقات التالية
@import url(//fonts.googleapis.com/earlyaccess/notonaskharabic.css);
body {
height: 100vh;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: 'Noto Naskh Arabic', serif;
background-color: #ccdcdc;
background-repeat: no-repeat;
background-position: 100% 100%
}
span#logo {
font-weight: 700;
color: #eee;
font-size: larger;
letter-spacing: .05em;
padding-left: .5rem;
padding-right: .5rem;
padding-bottom: 1rem;
float: right;
padding-top: 6px;
margin-right: 20px;
}
.header {
background-color: slategray;
width: 80%;
height: 50px;
margin-left: auto;
margin-right: auto;
115
Vue.js أساسيات إطار العمل Vue CLI إنشاء مشاريع باستخدام
h1.title {
text-align: center;
font-size: 1.875rem;
font-weight: 500;
color: #2d3336
}
h2.subtitle {
margin: 8px auto;
font-size: x-large;
text-align: center;
line-height: 1.5;
max-width: 500px;
color: #5c6162
}
.content {
margin-left: auto;
margin-right: auto;
padding-top: 1.5rem;
padding-bottom: 1.5rem;
width: 620px
}
: واحرص على أن يكون محتواه مماثاًل للشيفرة التاليةindex.html انتقل اآلن إلى الملف
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-
scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %>
doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
116
أساسيات إطار العمل Vue.js إنشاء مشاريع باستخدام Vue CLI
لقد انتهينا اآلن من جمي ع الملف ات! اذهب إلى المتص ّفح ثم انتق ل إلى العن وان http://localhost:8080
لتجد تطبيق "مشروبات حسوب" وقد عمل من جديد .ولكن هذه المرة باستخدام .Vue CLI
بعد االنتهاء من عملية التطوير بشكل كامل ،يمكن استخدام األمر التالي لبناء التطبيق وتجهيزه ضمن بيئ ة
يمكنك االطالع على المزيد حول هذا الموضوع من خالل من هذا الرابط الذي يحيلك إلى التوثيق الرسمي
باللغة اإلنجليزية.
7.5ختام الفصل
ّ
تعلمنا في هذا الفصل كيفية إنشاء تطبيق Vue.jsمتكامل باس تخدام ق الب ج اهز منحن ا إيّ اه .Vue CLI
ً
بداية ما هو مفهوم Vue CLIوكيفية إعداده ،وكيف ننشئ مشروع جديد باستخدامه. ّ
تعلمنا
كما عملنا على تحويل كامل تطبيق "مشروبات حس وب" من األس لوب الق ديم والمفي د في ح ال ك ّن ا نري د
117
.8التعامل مع دخل المستخدم عن
ّ
سنتعلم في هذا الفصل:
ِّ
المعدالت ( )Modifiersفي Vue.js •
لقد تعاملنا في بداية الكتاب مع عناصر اإلدخال العادية التي يستخدمها المستخدم إلدخال البيان ات ض من
س يتكوّ ن. سنبني تطبيق بسيط من أجل ه ذا الفص ل به دف تط بيق األفك ار ال واردة في ه،كما جرت العادة
أنش ئ مش روع جدي د. التي ننوي التعام ل معه اHTML تطبيقنا من صفحة واحدة فقط تحوي عدد من عناصر
ً
مسبقا في الفصل السابق (راج ع الفق رة "بن اء هيك ل تط بيق بس يط لش رح كما فعلناinput-forms-cli وسمه
ّ
ّ
)المجل د( في فتح المش روعVisual Studio Code استخدم، بعد االنتهاء من عملية اإلنشاء.)"أفكار الفصل
.توا
ًّ الذي أنشأته
كم ا فعلن ا فيHelloWorld.vue ل ذلك اح ذف المل فApp.vue لن نحتاج سوى ملف مكوّ ن واحد وه و
<template>
<div class="container">
<form>
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-
6 col-md-offset-3">
<h1 class="text-right"><الملف الشخصي للمستخدم/h1>
<hr>
<div class="form-group">
<label class="float-right" for="firstname">
<االسم/label>
<input
type="text"
id="firstname"
class="form-control"
v-model="userMainData.firstname">
</div>
<div class="form-group">
<label class="float-right" for="lastname">
<الكنية/label>
<input
type="text"
id="lastname"
class="form-control"
v-model="userMainData.lastname">
</div>
<div class="form-group">
<label class="float-right" for="age">
<العمر/label>
<input
type="number"
id="age"
class="form-control"
v-model="userMainData.age">
119
Vue.js أساسيات إطار العمل التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
</div>
<div class="form-group">
<label class="float-right" for="password">كلمة
<المرور/label>
<input
type="password"
id="password"
class="form-control"
v-model="userMainData.password">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-
6 col-md-offset-3 form-group">
<label class="float-right" for="description">
<نبذة/label><br>
<textarea
id="description"
rows="5"
class="form-control"
v-model="description"></textarea>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-
6 col-md-offset-3">
<div class="form-group">
<label class="float-right" for="graduate">
<input
type="checkbox"
id="graduate"
value=""متخرج
v-model="status"> متخرج
</label>
<label class="float-right" for="smoker">
<input
type="checkbox"
id="working"
value="ًا"أعمل حالي
v-model="status"> ًاأعمل حالي
</label>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-
6 col-md-offset-3 form-group">
<label class="float-right" for="male">
<input
type="radio"
id="male"
120
Vue.js أساسيات إطار العمل التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
value=""ذكر
v-model="gender"> <span><ذكر/span>
</label>
<label class="float-right" for="female">
<input
type="radio"
id="female"
value=""أنثى
v-model="gender"> <span><أنثى/span>
</label>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-
6 col-md-offset-3 from-group">
<label class="float-right" for="subscriptionKind">
<نوع االشتراك/label>
<select
id="subscriptionKind"
class="form-control"
v-model="selectedSubscription">
121
Vue.js أساسيات إطار العمل التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
<script>
export default {
data(){
return {
userMainData:{
firstname:'',
lastname:'',
age:0,
password:'',
},
description:''!اكتب نبذة قصيرة عنك,
status:[],
gender:''ذكر,
selectedSubscription:''فضي,
subscriptionKinds: [' 'عادي,' 'فضي,']'ذهبي
}
}
}
</script>
<style>
@import "./assets/styles/app.css";
</style>
ّ
المجل د األخ ير وس ّمه ً ثم أضفstyles وسمه
ملفا جديدً ا ضمن ّ ّ
assets المجلد ّ
مجلدً ا جديدً ا ضمن أضف
@import url(//fonts.googleapis.com/earlyaccess/notonaskharabic.css);
body{
font-family: 'Noto Naskh Arabic', serif;
122
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
}
يعمل هذا األمر كما نعلم على تشغيل خادوم الويب الخاص بالتطوير ،اذهب اآلن إلى متصفح الويب لديك،
123
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
ربما تكون قد استغربت قلياًل من عدم استخدامنا ألي مكتبة أو إطار عمل CSSفي عمليات التنس يق ال تي
كنا نجريها في تطبيقاتنا السابقة .بداًل عن ذلك ،كنا نستخدم شيفرة CSSعادية فحسب في تنسيق التطبيقات.
يعود سبب ذلك إلى أ ّنه ال يُ نصح أبدً ا إضافة إطار عمل CSSبالطريقة التقليدية ال تي تتمث ل في اس تخدام
الوسم < >linkكما يفعل أغلبنا عند تطوير تطبيقات أمامية ( .)Frontend Applicationsيع ود الس بب في
ذلك ألنّ أغلب ُأ طر عمل CSSتحتوي على شيفرة JavaScriptقد ال تكون متوافقة مع .Vue.js
ً
متوافق ا م ع Vue.jsلكي ال تحص ل مفاج آت غ ير علين ا ً
إذا اس تخدام إط ار عم ل CSSنض من أن يك ون
مرغوبة! سأتحدث هنا عن استخدام إط ار العم ل الش هير Bootstrapلكي ُنكس ب تطبيقاتن ا تنس يقات جميل ة
بعد االنتهاء وعودة موجه األوامر إلى حالته الطبيعية ،أضف السطر التالي إلى الملف :main.js
;"import "bootstrap/dist/css/bootstrap.min.css
Vue.config.productionTip = false
;"import "bootstrap/dist/css/bootstrap.min.css
{(new Vue
render: h => h(App),
)'}).$mount('#app
ً
جاهزا ثم أضفناه إلى التطبيق الخاص بنا ليصبح
نكون بهذا الشكل قد نصبنا إطار العمل Bootstrapومن ّ
مخصصة إلى حد كبير.
ّ لالستخدام .وهكذا نكون قد استغنينا عن كتابة تنسيقات
124
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
مغر بعض الشيء ،إاّل أ ّننا في الواق ع سنس تخدم ك ائن JavaScript
في الحقيقة رغم أنّ عنوان هذه الفقرة ٍ
عادي لتمثيل بيانات المستخدم األساس ية ض من تطبيقن ا الح الي .إذا راجعت ش يفرة التط بيق األساس ية ال تي
أوردتها في الفقرة األولى ،وتحديدً ا ضمن القسم < >scriptستجد البنية البسيطة التالية:
{userMainData:
firstname:'',
lastname:'',
age:0,
password:'',
}
كما أوضحت ،سيحمل الحقل userMainDataبيانات المستخدم الرئيسية التالي ة على ال ترتيب :االس م،
السؤال هنا ،كيف سنربط عناص ر HTMLالموافق ة؟ الج واب بس يط ،سنس تخدم v-modelللرب ط ثن ائي
االتجاه .انظر إلى الشيفرة المقتطعة من الشيفرة الموجودة ضمن القسم <:>template
>"<div class="form-group
></labelاالسم>"<label class="float-right" for="firstname
<input
"type="text
"id="firstname
"class="form-control
>"v-model="userMainData.firstname
></div
>"<div class="form-group
></labelالكنية>"<label class="float-right" for="lastname
<input
"type="text
"id="lastname
"class="form-control
>"v-model="userMainData.lastname
></div
>"<div class="form-group
></labelالعمر>"<label class="float-right" for="age
<input
"type="number
"id="age
"class="form-control
>"v-model="userMainData.age
></div
>"<div class="form-group
></labelكلمة المرور>"<label class="float-right" for="password
<input
125
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
"type="password
"id="password
"class="form-control
>"v-model="userMainData.password
></div
userMainData.firstname
تمام ا! يمكن ك
لق د اس تخدمت النقط ة للفص ل بين userMainDataوبين firstnameوه ذا ج ائز ً
مراجعة باقي عناصر HTMLلترى كيف استخدمت نفس الترميز الس ابق .الفائ دة في اس تخدام ه ذا األس لوب
حاول كتابة أي شيء ضمن الحقول األربعة السابقة ،ستجد أنّ ذلك سينعكس مباش رة على القس م الس فلي
ً
مسبق ا مع عناصر اإلدخال العادية فيما سبق من فصول ،وسنتعامل مع أنواع أخ رى في الحقيقة لقد تعاملنا
من عناصر اإلدخال في ه ذا الفص ل .أح د العناص ر الجدي دة ال تي س نتعامل معه ا ه و العنص ر <>textarea
يحتاج المبرمج في بعض األحي ان إلى تع ديل س لوك االس تجابة لـ .Vue.jsفمثاًل إذا الحظت في تطبيقن ا
هذا ،أنّ أي شيء تكتبه ضمن أي عنصر من عناصر اإلدخال النصية ،سينعكس مباشرة ضمن القس م الس فلي .ق د
يكون هذا السلوك غير مرغوب أحيا ًنا ،فقد ترغب ربما بأن ال يستجيب Vue.jsمباشر ًة لما يكتبه المستخدم ،بل
تؤج ل هذه االستجابة حتى ينتهي المستخدم مما يكتبه وينتقل إلى حقل نصي آخر مثاًل .
بأن ّ
126
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
"v-model.lazy="userMainData.firstname
احفظ التغييرات ،ثم حاول كتابة شيء ما ض من الحق ل firstnameوال تح اول مغ ادرة الحق ل ،س تجد
هذه المرة أنّ ذلك لن ينعكس مباش رة ض من القس م الس فلي .غ ادر اآلن ذل ك الحق ل إلى حق ل آخ ر ،س تجد أنّ
"v-model.lazy.trim = "userMainData.firstname
في تطبيقنا هذا ،سنستخدم م ربّعي اختي ار للتعب ير عن ك ون المس تخدم متخ ّرج أم غ ير متخ ّرج .به دف
عرفت حقاًل جديدً ا اسمه statusعلى أ ّنه مص فوفة (انظ ر القس م <.)>script
التعامل مع هذين المربعينّ ،
الموج ه v-modelلك ل من الم ربعين .انظ ر الش يفرة
ّ ربطت هذه المصفوفة مع مربعي االختي ار بإس نادها إلى
الحظ كيف أ ّننا ربطنا مربعي االختيار بنفس الشكل .الذي س يحدث وراء الك واليس ،ه و أ ّن ه عن دما يخت ار
127
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
المصفوفة ،statusفإذا اختار المستخدم كال المربعين ،فسيدرج Vue.jsعنصرين ضمن المصفوفة ،يع ّب ر ك ل
منهما عن قيم ة مر ّب ع االختي ار .أي أنّ ع دد عناص ر المص فوفة س يكون مس اويً ا لع دد المربع ات ال تي اختاره ا
يمكن تط بيق نفس المب دأ تقري ًب ا على أزرار االنتق اء ،في تطبيقن ا ه ذا ل دينا زري انتق اء يُ ع ّب ران عن ن وع
عرفت حقاًل جديدً ا أسميته genderيحمل القيم ة االفتراض ية ذك ر .انظ ر معي إلى
المستخدم (ذكر أم أنثى)ّ .
ً
بداية أ ّنني قد وضعت القيمة valueلك ل من ال زرين الس ابقين لتكون ا "ذك ر" و "أن ثى" على الحظ معي
الذي سيحدث عند بدء تشغيل التطبيق أنّ الحقل genderسيحمل القيمة ذكر بشكل افتراضي كما ذكرت
قب ل قلي ل ،وبالت الي س يختار Vue.jsال زر المع ّب ر عن قيم ة "ذك ر" ألنّ قيمت ه س تكون مماثل ة لقيم ة الحق ل
جرب أن تجري اآلن بعض التجارب على مربعي االختيار وزري االنتقاء ،والحظ النتائج التي ستحدث ضمن
األول ه و ّ
نتعلم كيفية الربط مع القائمة المنسدلة < .>selectسينقسم عملنا هن ا إلى قس مينّ . بقي لنا أن
الموجه .v-model
ّ تعبئة هذه القائمة ،والثاني هو الربط مع Vue.jsباستخدام
128
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
بالنس بة لتعبئ ة ه ذه القائم ة بالبيان ات األولي ة ال تي س يختار منه ا المس تخدم ،فق د ع ّرفت الحق ل
تع ّب ر هذه المصفوفة عن نوع االشتراك الذي يرغب المستخدم باعتماده .سيكون لدينا كما هو واض ح ثالث ة
هذه الشيفرة مأخوذة من القس م < >templateب الطبع .وهي عب ارة عن حلق ة بس يطة تعم ل على تعبئ ة
القائمة من خالل توليد عناصر < >optionالعمود الفقري لعنصر القائمة <.>select
بالنسبة لعملية الربط فق د ع ّرفت حقاًل آخ ًرا أس ميته selectedSubscriptionوأس ندت ل ه القيم ة
اني من عناصر ر الث ة للعنص ة مماثل ذه القيم ظ معي أنّ ه ي" .الح ية "فض االفتراض
المصفوفة .subscriptionKindsبعد ذلك ،ربطت عنصر القائمة باستخدام v-modelعلى النحو التالي:
"v-model="selectedSubscription
وهكذا وعند تشغيل التطبيق للمرة األولى ،سيظهر العنصر الثاني فضي وقد اختير بشكل افتراضي .جرب
8.7إرسال البيانات
كما هو معلوم ،عند وض ع عنص ر ال زر buttonض من عنص ر النم وذج ،formفس يؤدي نق ر ه ذا ال زر إلى
<button
"v-on:click.prevent="submitInfo
إرسال>"class="btn btn-primary
></button
129
أساسيات إطار العمل Vue.js التعامل مع دخل المستخدم عن طريق نماذج اإلدخال
ا كامل ع هن ابع .submitInfoسأض ف الت م methodلكي نتمكّن من تعري يف القس سنض
{methods:
{)(submitInfo
;)"تمت معالجة البيانات"(alert
}
}
من هذه الرسالة أن شيفرة قد تجدها مناسبة للبيانات ال تي أدخله ا المس تخدم .اله دف هن ا ه و أن تفهم المب دأ
8.8ختام الفصل
ّ
تعلمنا في هذا الفصل كيفية استخدام ُأ طر عمل جاهزة لتنسيق المحتوى ،حيث استخدمنا في هذا الفص ل
ال دخل من المس تخدم ،حيث تعاملن ا م ع عناص ر اإلدخ ال النص ية البس يطة باإلض افة إلى عنص ر اإلدخ ال ذو
ً
وأيض ا مربعات االختيار وأزرار االنتقاء وعنصر القائمة المنسدلة. األسطر المتعدّ دة <>textarea
مر معنا في فصول سابقة .أرجو لك الفائدة من هذا الفصل ،أراك في الفصول القادمة إن شاء اهلل.
المكوّ نات كما ّ
130
.9المرشحات Filterوالـمخاليط Mixin
ّ
سنتعلم في هذا الفصل:
ّ
المرشح ()Filter •
ّ
المرش حات ()Filters س نتابع عملن ا في ه ذا الفص ل م ع م يزتين مفي دتين في Vue.jsوهم ا:
ّ
سنوض ح والمخاليط (ُ .)Mixinsتعتبر هاتين الميزتين على بساطتهما من المزاي ا المتقدّ م ة نس ً
بيا في .Vue.js
المقصود بكل منهما في هذا الفص ل ،وذل ك بكتاب ة مث الين تطبيق يين بس يطين ،لتوض يح الغاي ة من اس تخدام
جيد.
هاتين التقنيتين بشكل ّ
أساسيات إطار العمل Vue.js المرشحات Filterوالـمخاليط Mixin
9.1المرشح ()Filter
ّ
المرش حات ال تي ن رغب بكتابته ا ض من قس م خ اص ض من ك ائن Vue.jsاس مه .filters يمكن تعريف
كمثال على ذل ك ،يمكن اس تخدام مرش ح يعم ل على تحوي ل حال ة األح رف إلى كب يرة (بالنس بة لألح رف
االنجليزية) ،رغم أ ّن ها قد تكون ضمن الحقل عبارة عن مزيج بين أحرف صغيرة وكبيرة .ربما تكتشف بع د قلي ل
برمجيا ّ
يوضح كيفية كتابة المرشحات .أنشئ مشروعً ا جديدً ا باس تخدام األم ر vueمن ً لنتناول اآلن مثااًل
ثم افتح المشروع باستخدام .Visual Studio Codeاحذف الملف HelloWorld.vueثم اس تبدال بم ا
><template
>"<div id="app
><h1>Filters</h1
}}{{text | toUpper
></div
></template
><script
{ export default
{)(data
{ return
"text:"We will apply a filter on this field.
}
},
{filters:
{)toUpper(value
;)(return value.toUpperCase
132
أساسيات إطار العمل Vue.js المرشحات Filterوالـمخاليط Mixin
}
}
}
></script
><style
{ #app
;font-family: Avenir, Helvetica, Arial, sans-serif
;-webkit-font-smoothing: antialiased
;-moz-osx-font-smoothing: grayscale
;text-align: center
;color: #2c3e50
;margin-top: 60px
}
></style
ّ
المرش ح toUpperض منه على ش كل ت ابع يقب ل قيم ة انظر إلى القس م الجدي د filtersكي ف ع رفت
ّ
المرشح حالة األحرف الكبيرة لهذه القيم ة عن طري ق ت ابع JavaScript وحيدة .valueالحظ كيف يُ رجع هذا
وهو .toUpperCase
ّ
المرشح كما هو ظاهر من الشيفرة السابقة .نضع المحرف | بعد اس م الحق ل الحظ معي اآلن طريقة تطبيق
ّ
المرشح .أي كما في التالي: ّ
المرشح عليه ،ثم نكتب اسم المراد تطبيق
text | toUpper
المرشح لن ّ
يؤثر على القيمة األصلية للحق ل textإنم ا س يجري ّ وهذا كل شيء .ينبغي االنتباه هنا إلى أنّ
التعديل على الخرج الذي سيظهر للمستخدم فحسب .ج رب اآلن معاين ة التط بيق البس يط الس ابق ل ترى كي ف
محلي ا ( .)Localيمكن
ً ً
تعريف ا ّ
المرش حات كقس م ض من ك ائن Vue.jsيُ عت بر األسلوب الس ابق في تعري ف
ّ
المرش حات بش كل ع ام ( )Globalوذل ك عن طري ق اس تخدام الت ابع Vue.filterض من تعري ف
Vue.config.productionTip = false
{)Vue.filter('toLower', function(value
;)(return value.toLowerCase
)}
{(new Vue
render: h => h(App),
133
أساسيات إطار العمل Vue.js المرشحات Filterوالـمخاليط Mixin
)'}).$mount('#app
ّ
المرش ح المحلي الق ديم ّ
المرشح العام الجديد ضمن الملف App.vueوذل ك على سنعمل اآلن على تطبيق
ّ
المرشح القديم .ال ذي س يحدث اآلن ،أنّ محتوي ات ّ
المرشح الجديد بشكل متسلسل على الحظ كيف طبقنا
المرشح toUpperأواًل ،مما سيعطينا حالة أحرف طباعية كبيرة ،ثم سيتم تط بيق
ّ الحقل textسيط ّبق عليها
ّ
المرشح toLowerعلى النتيجة األخيرة ،مما سيؤدي إلى تحويل حالة األحرف إلى الحالة الطباعية الصغيرة.
ّ
المرش ح toUpperولكن ني فض لت اس تخدامها كان يمكن ب الطبع تط بيق المرش ح toLowerفق ط دون
بالشكل المتسلسل السابق لتوض يح إمكاني ة تط بيق أك ثر من ّ
مرش ح بنفس ال وقت بش كل متسلس ل كم ا فعلنا
قبل قليل.
9.2المخلوط ()Mixin
قد ُتضطر في بعض األحيان إلى كتابة مكوّ نات تشترك بنفس الجزء من الش يفرة البرمجي ة تقري ًب ا .رغم أنّ
جاء المخلوط ( )Mixinليوجد حاًل لهذه المسألة ،حيث من الممكن جعل ذلك الجزء المشترك من المكوّ ن ات
ضمنه بحيث تتشارك تلك المكونات بالمخلوط مما يلغي الحاجة إلى تكرار الشيفرة البرمجية.
افتح المشروع باستخدام .Visual Studio Codeاحذف المل ف ،HelloWorld.vueثم أض ف ملفين ض من
أيضا ً
ملفا سمهما على النحو التالي BMI.vue :و .ImperialConverter.vueوأضف ً ّ
المجلد ّ ،components
ّ
المجلد .src اسمه ConverterMixin.jsإلى
فك رة ه ذا التط بيق هي إنش اء مك وّ نين األول ه و ImperialConverterي وفر إمكاني ة التحوي ل من
134
Vue.js أساسيات إطار العمل Mixin والـمخاليطFilter المرشحات
ّ
يش ترك ك ل من المك ونين الس ابقين بج زء من الش يفرة.)Body Mass Index( مؤشر كتلة الجسم عن حالة
م ع العلم أنّ ك ل من المك ونين الس ابقين مس تقلين.ConverterMixin البرمجية موض وع ض من المخل وط
ّ
.يتعلق بالبيانات تماما فيما
ً
على الشيفرة البرمجية المسؤولة عن التحويل من الكيل وغرام إلىConverterMixin يحتوي المخلوط
وkg_value حيث تحت وي على حقلي بيان ات،الشيفرة البرمجية الموج ودة في المخل وط بس يطة ج دً ا
<template>
<div>
<h2>Kilograms to Pounds Converter</h2>
<div>
<input type="text" style="width:50px;text-align:center;" v-
model="kg_value" />
<span style="margin-left:8px;">Kg = {{to_pounds}} pounds.</span>
</div>
<br />
<div>
<input type="text" style="width:50px;text-align:center;" v-
model="cm_value" />
<span style="margin-left:8px;">CM = {{to_inches}} Inches.</span>
</div>
</div>
</template>
135
Vue.js أساسيات إطار العمل Mixin والـمخاليطFilter المرشحات
<script>
import { ConverterMixin } from "../ConverterMixin";
export default {
name: "ImperialConverter",
mixins: [ConverterMixin],
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
< مناس بة إلدخ ال البيان ات الم راد تحويله ا وذل ك ض من القس مHTML ي وفر ه ذا المك وّ ن عناص ر
ثمimport > فنعمل على استيراد المخلوط باس تخدام التعليم ةscript< أما بالنسبة للقسم
ّ ،>template
الحظ أ ّن ه ال توج د ش يفرة برمجي ة.mixins أ ّننا نريد استخدام هذا المخلوط عن طريق القسمVue.js ُنخبر
.فعلية ضمن المكون أل ّن ه أغلب المنطق الحسابي يحدث ضمن المخلوط في مثالنا البسيط هذا
ّ
مؤش ر كتل ة الجس م باإلض افة إلى فهو المكوّ ن المسؤول (كما أشرنا) على حسابBMI أما بالنسبة للمكوّ ن
ّ
: انظر إلى الشيفرة البرمجية لهذا المكون.عرض تقرير بسيط للمستخدم حول القيمة المحسوبة
<template>
<div>
<h2>Body Mass Index (BMI)</h2>
<div>
<div>
<span>Weight (Kg):</span>
<input type="text" style="width:50px;text-align:center;" v-
model="kg_value" />
</div>
<br />
<div>
<span>Height (Cm):</span>
<input type="text" style="width:50px;text-align:center;" v-
model="cm_value" />
</div>
<br />
<div>
<span>BMI value: {{bmi_value}}</span> -
<span>{{result}}</span>
</div>
</div>
</div>
</template>
<script>
import { ConverterMixin } from "../ConverterMixin";
136
Vue.js أساسيات إطار العمل Mixin والـمخاليطFilter المرشحات
export default {
name: "BMI",
mixins: [ConverterMixin],
computed: {
bmi_value: function () {
return (703 * this.to_pounds) / (this.to_inches *
this.to_inches);
},
result: function () {
if (this.bmi_value < 16) {
return "Severe Thinness";
} else if (this.bmi_value < 17) {
return "Moderate Thinness";
} else if (this.bmi_value < 18.5) {
return "Mild Thinness";
} else if (this.bmi_value < 25) {
return "Normal";
} else if (this.bmi_value < 30) {
return "Overweight";
} else if (this.bmi_value < 35) {
return "Obese Class I";
} else if (this.bmi_value < 40) {
return "Obese Class II";
} else if (this.bmi_value >= 40) {
return "Obese Class III";
} else {
return "Not defined!";
}
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
انظ ر إلى الش يفرة البرمجي ة. الذي سنس تخدم من خالل ه المك ونين الس ابقينApp.vue أخيرا الملف
ً بقي
:لهذا الملف
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
137
Vue.js أساسيات إطار العمل Mixin والـمخاليطFilter المرشحات
<imperial-converter/>
<BMI/>
</div>
</template>
<script>
import ImperialConverter from './components/ImperialConverter.vue'
import BMI from './components/BMI.vue'
export default {
name: 'App',
components: {
ImperialConverter,
BMI
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
138
أساسيات إطار العمل Vue.js المرشحات Filterوالـمخاليط Mixin
9.3ختام الفصل
ّ
المرش حات ()Filters تح دثنا في ه ذا الفص ل عن م يزتين جدي دتين من مزاي ا ،Vue.jsوهم ا:
والمخاليط ( ،)Mixinsحيث قد وجدنا أنّ المرشحات هي عبارة عن شيفرات برمجية بسيطة تعمل على إج راء
منطق برمجي بسيط وسريع دون الحاجة الستخدام التوابع أو الخاصيات المحسوبة.
أما المخاليط فوجدنا أ ّن ها تقنية مفيدة للتخلص من تكرار الشيفرة البرمجية بين المكوّ نات المختلف ة ،حيث
ّ
يُ وضع القسم البرمجي المشترك بين مكوّ نين أو أكثر ض من مل ف منفص ل دعون اه ب المخلوط ،وتعم ل المكوّ ن ات
المختلفة بعد ذلك على استخدام هذا المخلوط وتتجنّب تكرار الشيفرة البرمجية.
139
.10استخدام Vue.jsلالتصال باإلنرتنت
ّ
سنتعلم في هذا الفصل:
وبما أ ّن نا نهتم بتبسيط المعلومة من خالل التركيز على مفهوم جديد مح دّ د ،فلن ن دخل في مج ال بن اء تط بيق
مخصص لكي يتعامل معه تطبيق ،Vue.jsولكن سنعتمد على إنش اء
ّ خلفية كامل ()Backend Application
تطبيق بسيط مجاني على ،Google Firebaseوهو عبارة عن خدمة قاعدة بيانات سيتواص ل معه ا تطبيقن ا
نتوسع في هذا الفصل في الشرح حول Google Firebaseومزاياها ،إذ يمكنك االطالع ح ول المزي د
ّ لن
عنه ا من خالل الوث ائق الخاص ة به ا وال تي س أزودك ب البعض منه ا بع د قلي ل .يكفي ك اآلن أن تعلم
التطبيقات التي يعملون عليها ،فهي عبارة عن خدم ة خلفي ة ( )Backend Serviceيمكن ك من خالله ا إنش اء
دعما بالنس بة إلين ا ،سنس تخدم Firebaseفي ه ذا الفص ل لبن اء قاع دة بيان ات بس يطة كخدم ة ّ
تمث ل ً
لتطبيق Vue.jsبسيط .انتق ل إلى الموق ع الرس مي لـ ،Firebaseثم من الزاوي ة اليم نى العلي ا اخ تر Sign in
انقر Go to consoleمن الزاوية اليمنى العليا لالنتقال إلى صفحة الخدمات ،ثم انق ر زر Add project
ً
بداية اسم المشروع باإلضافة إلى الموافقة على (أو )Create a projectإلضافة مشروع جديد ،سيطلب منك
141
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
لق د اخ ترت االس م vue-remote-serversستض طر ب الطبع إلى اس تخدام اس م آخ ر لمش روعك ألن
االسم الحالي أصبح محجو ًزا .بعد ذل ك انق ر زر Continueلالنتق ال إلى المرحل ة الثاني ة ال تي س يخيرك فيه ا
بتفعيل Google Analyticsمن أجل هذا المشروع .انقر الزر Continueمجددا لالنتقال إلى المرحلة األخيرة
في حال كنت قد اخ ترت تفعي ل Google Analyticsفي المرحل ة الثاني ة ،فس يطلب من ك في المرحل ة
األخيرة تحديد الحساب الذي ترغب باستخدامه مع ( Google Analyticsسيوفر لك حساب افتراض ي اس مه
Default Account For Firebaseأو سيسمح لك بإنشاء حساب جدي د إن أحببت) ،بع د تحدي د الحس اب،
إذا كنت تزور Firebaseللمرة األولى ،فسيطلب منك في المرحلة األخيرة تحديد المنطقة (الدولة)
بعد إنشاء المشروع سينتقل المتصفح إلى الصفحة الخاصة به .من القائمة اليسرى انق ر ال زر Developثم
142
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
بعد النقر على قاعدة البيانات ستحصل على واجهة تسمح لك ببناء قاعدة بيانات جديدة .اس تخدم ش ريط
التمرير العمودي لكي تنتقل إلى أسفل الصفحة قلياًل حتى تص ل إلى القس م الخ اص بإنش اء قاع دة بيان ات في
انقر زر Create databaseإلنشاء قاعدة البيانات المطلوبة .ستظهر ناف ذة ص غيرة تع رض فيم ا إذا كنت
تريد أن تجعل قاعدة البيانات مفتوحة للجميع بهدف اختبارها ،أم مقفلة تحتاج إلى تسجيل دخول .سنختار أن
143
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
الحظ التحذير الذي سيظهر باللون األحمر والذي يفي د ب أنّ أي ش خص سيص بح ق اد ًرا على تع ديل قاع دة
البيانات أو القراءة منها .بعد النقر على زر Enableستحصل على شكل شبيه بما يلي:
أصبحت قاعدة البيانات جاهزة ،الحظ من جديد كيف يظهر تحذير باللون األحمر يخبرك أنّ قاعدة البيانات
مفتوحة ويمكن ألي شخص الوصول إليها .الحظ ً
أيضا الرابط الذي يظهر مباشرة فوق التحذير:
https://vue-remote-servers.firebaseio.com/
هذا الرابط هو عنوان نقط ة االتص ال لخدم ة قاع دة البيان ات ( )Database Service Endpointال تي
ً
الحقا في هذا الفصل. توا .سنحتاج إلى هذا الرابط
أنشأناها ًّ
144
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
قد تتساءل ً
أيضا أين الجداول ضمن قاعدة البيان ات ه ذه؟ الحقيق ة أنّ قواع د البيان ات ض من Firebase
عبارة عن قواعد بيانات NoSQLلمعرفة المزيد حول قواعد البيانات هذه يمكنك زيارة هذه الصفحة.
يمكنك الحصول على المزيد من المعلومات حول Firebaseمن خالل هذا الرابط الذي يحتوي على
تحدث في بعض األحيان تحديثات مستمرة على الواجهات الخاصة بـ ،Google Firebaseلذلك فقد
عما تشاهده في الموقع .مع أ ّنني أرجو أاّل يحدث ذلك ،منعً ا ألي التباس
يختلف الشرح الموجود هنا قلياًل ّ
قد يعتريك عزيزي القارئ.
يمكن بالطبع استخدام أي طريقة لالتص ال ب اإلنترنت من خالل ،Vue.jsولكن ني س أختار في ه ذا الفص ل
أس لوب مخص ص لـ .Vue.jsسنس تخدم مكتب ة اس مها vue-resourceيمكن من خالله ا االتص ال ب الخواديم
ومبسط وبشكل منسجم تقري ًبا مع المكتبات الشهيرة المستخدمة لهذا الغرض .يمكنك الوص ول إلى
ّ بشكل سهل
المستودع الخاص بهذه المكتبة على Githubمن خالل هذا الرابط .في الحقيقة ،أنصحك بزيارة مستودع هذه
موجه األوامر ّ
ونفذ األمر التالي: ّ لتثبيت vue-resourceافتح
بعد االنتهاء من التثبيت يمكن اآلن إضافة هذه المكتبة إلى تطبيق Vue.jsوذلك بإضافة السطر الت الي إلى
;)Vue.use(VueResource
أم ا كيفية االستخدام الفعلي لهذه المكتبة فسنتعرف عليه في الفقرة التالية.
ّ
145
Vue.js أساسيات إطار العمل لالتصال باإلنرتنتVue.js استخدام
.Google Firebase البيانات التي أنشأناها في الفقرة األولى من هذا الفصل على
:موجه األوامر
ّ عن طريق تنفيذ األمر التالي ضمنvue-remote-servers أنشئ مشروع جديد اسمه
ّ
اح ذف اآلن المل ف.Visual Studio Code المجل د الخ اص ب ه عن طري ق افتح،بع د إنش اء المش روع
Vue.config.productionTip = false
Vue.use(VueResource);
new Vue({
render: h => h(App),
}).$mount('#app')
ً واحرص
: مماثلة لما يليApp.vue أيضا على أن تكون محتويات الملف
<template>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-
offset-3">
<h2>Vue.js Remote Server</h2>
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" v-
model="user.username" />
</div>
<div class="form-group">
<label>First name</label>
<input type="text" class="form-control" v-
model="user.firstname" />
</div>
<div class="form-group">
<label>Last name</label>
<input type="text" class="form-control" v-
model="user.lastname" />
146
Vue.js أساسيات إطار العمل لالتصال باإلنرتنتVue.js استخدام
</div>
<button class="btn btn-primary"
@click="postData()">Add</button>
<br />
<br />
<button class="btn btn-primary"
@click="getData()">Retrieve</button>
<br />
<br />
<ul class="list-group">
<li
class="list-group-item"
v-for="usr in users"
v-bind:key="usr.username"
>{{usr.username}} - {{usr.firstname}} {{usr.lastname}}</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
user: {
username: "",
firstname: "",
lastname: "",
},
users: [],
};
},
methods: {
postData: function () {
this.$http
.post("https://vue-remote-servers.firebaseio.com/users.json",
this.user)
.then(
(response) => {
console.log(response);
this.user.username = "";
this.user.firstname = "";
this.user.lastname = "";
},
(error) => {
console.log(error);
}
);
},
147
Vue.js أساسيات إطار العمل لالتصال باإلنرتنتVue.js استخدام
getData: function () {
this.$http
.get("https://vue-remote-servers.firebaseio.com/users.json")
.then((response) => {
return response.json();
})
.then((data) => {
const tmpArray = [];
this.users = tmpArray;
});
},
},
};
</script>
<style>
</style>
حيث تتك ون بيان ات.الفكرة من هذا التطبيق هي في إمكانية اإلضافة المتعددة لمس تخدمين افتراض يين
سترس ل.)Last name( ) والكني ةFirst name( ) واالس مUsername( اسم المستخدم:كل مستخدم من
148
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
بيانات كل مستخدم مفترض إلى قاعدة البيانات على .Firebaseبعد ذلك يمكن استرداد بيانات المس تخدمين
ً
مسبقا إلى قاعدة البيانات هذه ،من خالل نقر الزر .Retrieve المضافة
ُ
ً
مسبقا .وهذا ما انتبه إلى أننا سنستخدم في هذا التطبيق تنسيقات Bootstrapعلى افتراض أ ّنك قد ثبته
;"import "bootstrap/dist/css/bootstrap.min.css
إذا أردت أن تتذكر كيفية استخدام تنسيقات Bootstrapضمن Vue.jsيمكنك مراجعة الفقرة" :استخدام
إطار العمل "Bootstrapضمن الفصل" :التعامل مع دخل المستخدم عن طريق نماذج اإلدخال".
بالنسبة آللية عمل التطبيق ،الحظ معي بداي ًة أن ش يفرة HTMLالموج ودة ض من القس م <>template
هي بسيطة وواضحة .بالنسبة لحقول البيانات المستخدمة ،فهي معرفة ضمن القسم < >scriptحيث ع ّرفت
جمي ع الحق ول ال تي تع ود للمس تخدم المف ترض ض من ك ائن اس مه userموج ود ض من القس م dataض من
كائن .Vue.jsيحت وي ه ذا الك ائن على الحق ول التالي ة username :و firstnameو lastnameكم ا ه و
ّ
سنخزن ضمنها بيان ات المس تخدمين ال تي واضح .كما يحتوي القسم ً data
أيضا على مصفوفة اسمها users
ّ
سنوضح ذلك بعد قليل. سنحصل عليها من قاعدة بيانات Firebaseعند نقر زر Retrieveكما
أما بالنسبة للقسم methodsفيحتوي على تابعين فقط postData :و getDataوهما معالجين لحدثي
ّ
this.$http
.post("https://vue-remote-servers.firebaseio.com/users.json",
)this.user
(.then
{ >= )(response
;)console.log(response
;"" = this.user.username
;"" = this.user.firstname
;"" = this.user.lastname
},
{ >= )(error
;)console.log(error
}
;)
149
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
اس تخدمت الك ائن $httpمن الك ائن .thisفي الحقيق ة أنّ ه ذا الك ائن ُمت اح فق ط من خالل
المكتب ة vue-resourceال تي أض فناها في ه ذا الفص ل .يحت وي الك ائن $httpعلى ع دة تواب ع مفي دة في
استقبال وإرسال البيانات عبر اإلنترنت من وإلى خ واديم أو خ دمات ( )Servicesكم ا هي خدم ة .Firebase
بما أ ّننا نريد إضافة بيانات جديدة ،فسنستخدم التابع postكما هو واضح .يقبل هذا التابع وسيطين:
الوسيط األول هو عنوان نقطة االتصال للخدمة المراد التواصل معه ا ،وهي في حالتن ا ه ذه عن وان خدم ة
https://vue-remote-servers.firebaseio.com/users.json
الرابط السابق حصلت عليه من الصفحة الخاصة بقاع دة البيان ات vue-remote-serversإذا كنت ت ذكر
من الفق رة األولى من ه ذا الفص ل ،ولكن أض فت علي ه اس م المص در .users.jsonبم ا أ ّن ني أري د إض افة
مستخدمين افتراضيين إلى قاعدة البيانات فمن المنطقي إض افة بيان ات ه ؤالء المس تخدمين إلى ج دول (إن
صح التعب ير) اس مه .usersفي الحقيق ة في قواع د البيان ات من النم ط NoSQLنس مي مث ل ه ذه الج داول
ّ
سنخزن ضمنها بيان ات المس تخدمين بالمجموعات (ً .)Collections
إذا فاالسم usersهو اسم المجموعة التي
أما الوسيط الثاني فهو عب ارة عن البيان ات الم راد إرس الها .وق د أرس لت الك ائن userجمل ًة واح دة ،أل ّن ه
ّ
ق v-model يحت وي على البيان ات الفرعي ة المطلوب ة وال تي هي مربوط ة ب دورها عن طري
بعناصر HTMLالموافقة.
يُ رجع التابع postوعد ( )Promiseلذلك فإ ّننا ُنتبع استدعاء الت ابع postبنقط ة مباش رة وبع دها نكتب
تمام ا عن د العم ل م ع مكتب ات JavaScriptالش هيرة األخ رى .يقب ل الت ابع then
التابع thenكما ه و م ألوف ً
برمجي ة ُتع الج ال رد ال ذي حص لت عليه
ّ األول ه و ت ابع يحت وي على ش يفرة وس يطين ً
أيض ا :الوس يط ّ
مكتبة vue-resourceبعد اتصالها مع الخادوم البعيد .انظر إلى الشيفرة التالية:
{ >= )(response
;)console.log(response
;"" = this.user.username
;"" = this.user.firstname
;"" = this.user.lastname
}
150
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
الطرفية ( )Consoleالخاصة بأدوات المطوّ ر ض من متص ّفح ال ويب .يمكن ك إزال ة ه ذا الس طر إن أحببتّ .
أم ا
التعليمات الثالث التالية فهدفها تفريغ حقول بيانات المستخدم لإلشارة إلى نجاح العملية.
ملفات التطبيق:
ُزر اآلن الص فحة http://localhost:8080لتحص ل على واجه ة التط بيق .أدخ ل قيم مناس بة الس م
انتقل اآلن إلى الصفحة الخاصة بقاعدة البيانات ( vue-remote-serversعليك زي ارة الموقع ثم نق ر زر
وأخيرا اختيار قاعدة البيانات الحقيقية ( )Realtime Databaseالتي تحمل نفس االسم).
ً اليسرى،
الحظ معي اسم قاعدة البيانات vue-remote-serversيظهر في أعلى الشجرة ،ثم يظهر اسم المجموعة
يتفرع عن المجموعة usersالتي هي بمثابة جدول كما اتفقنا ،عقدة تالي ة تحم ل
ّ usersفي العقدة التي تليها.
151
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
رم و ًزا مبهم ة ،يتف ّرع عنه ا من جدي د البيان ات ال تي أرس لتها إلى قاع دة البيان ات وهي Husam :لالسم
بالنسبة للرموز المبهمة التي تظه ر فهي بمثاب ة مفت اح رئيس ي ( )Primary Keyأو مع ّرف ( )IDللبيان ات
التي تقع ضمنها .أل ّنه من البديهي إرسال العديد من بيان ات المس تخدمين ،فس يعمل Firebaseعلى تخص يص
شيفرة فريدة تحوي مثل هذه الرموز المبهمة لكل مستخدم مفترض تتم إضافته إلى قاعدة البيانات .يمكنك إن
البرمجية
ّ أم ا بالنس بة للت ابع getDataفه ا هي الش يفرة
ك ل الكالم الس ابق ك ان للت ابع ّ .postData
الموجودة ضمنه:
this.$http
)".get("https://vue-remote-servers.firebaseio.com/users.json
{ >= ).then((response
;)(return response.json
)}
{ >= ).then((data
;][ = const tmpArray
;this.users = tmpArray
;)}
ّ
المخزن ة ض من قاع دة سنستخدم هذه المرة التابع getمن الكائن $httpوذل ك للحص ول على البيان ات
البيانات .ال يحتاج هذا التابع كما هو واضح إاّل لوسيط واحد هو نفسه الوسيط ّ
األول للتابع postالذي تح دثنا
أيضا وع د ( ،)Promiseل ذلك وبنفس النق اش الس ابق فإ ّنن ا ُنتب ع اس تدعاء الت ابع get
يُ رجع التابع ً get
تمام ا-
بنقطة مباشرة وبعدها نكتب التابع .thenاكتفيت هنا بكتاب ة وس يط واح د للت ابع - thenوه ذا ج ائز ً
وهو عبارة عن تابع سهم كما هو واضح يحتوي على تعليمة برمجية واحدة فقط:
;)(return response.json
وظيفة هذه التعليمة هي إرجاع تمثيل JSONللرد الذي حص لت علي ه المكتب ة بع د اس تدعاء الت ابع .get
وذلك من خالل استدعاء التابع jsonمن الكائن .responseوهن ا ينبغي التنوي ه إلى أنّ الت ابع jsonيُ رج ع
أيضا وعد ( .)Promiseلذلك فإنّ التعليمة السابقة ُترجع هذا الوعد مما يسمح لنا بوضع نقطة مباش ر ًة بع د
هو ً
152
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
استدعاء التابع thenثم استدعاء تابع thenجديد يقبل وسيط وهو بالطبع عبارة عن تابع س هم جدي د يقب ل
يطا واح دً ا ً
أيض ا أس ميته dataيحت وي على البيان ات الفعلي ة ال تي حص لنا عليه ا من قاع دة البيان ات وس ً
على .Firebase
البيانات الخام الواردة من المكتبة vue-resourceالتي تتواصل مع قاعدة البيانات ،وتخزينه ا بش كل مناس ب
ض من المص فوفة المؤقت ة .tmpArrayوبع د انته اء عملي ة االس تخالصُ ،تس نَد ه ذه المص فوفة إلى
الحقل usersوهو مصفوفة بالطبع ،لتُ عرض البيانات بالشكل المرغوب على المستخدم .انظر هذه الشيفرة:
;this.users = tmpArray
إنّ سبب وجود حلقة forبالشكل السابق ،يع ود إلى ش كل البيان ات ال واردة من المكتب ة vue-resource
وال تي هي عب ارة عن ق اموس ( ،)Dictionaryيك ون المفت اح ( )Keyفي ه عب ارة عن المفت اح الرئيس ي (تل ك
أم ا القيم ة ( )Valueله ذا المفت اح فهي عب ارة عن ك ائن يتض من بيان ات
الرموز الغريب ة) ألح د المس تخدمينّ ،
المستخدم ( في حالتنا هذه تكون هذه البيانات عبارة عن اسم المستخدم واالسم والكنية كما نعلم).
انظر معي إلى البيانات الخام ال واردة من المكتب ة ،vue-resourceوال تي حص لت عليه ا بإض افة تعليم ة
الكتاب ة إلى الطرفي ة ( )Consoleعن د ورود البيان ات من المكتب ة (في الحقيق ة تعم دت إخف اء بعض التواب ع
153
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
الش كل الس ابق ه و نتيج ة إض افة مس تخدمين افتراض يين آخ رين إلى قاع دة البيان ات ،وبع د نقر
زر Retrieveبالطبع .انظر إلى الشكل التالي لترى كيف ستبدو نفس البيانات ولكن على صفحة الويب:
154
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
من الواضح أنّ تطبيقنا السابق يس مح بإض افة مس تخدمين افتراض يين ج دد ،كم ا يس مح بق راءة بيان ات
هؤالء المستخدمين وعرضهم على الصفحة .ولكن من المفيد أن يسمح التطبيق ً
أيضا بتعديل بيان ات مس تخدم
ً
مسبقا .يمكن ذل ك ببس اطة من خالل اس تخدام الت ابع putمن الك ائن $httpحيث يس مح افتراضي موجود
كبير ا من الناحية الشكلية على التطبيق السابق لكي يسمح بإنجاز ه ذه الم يزة،
ً سأجري في الحقيقة تعدياًل
ورغم التعديالت الكثيرة التي ستجري على الملف ،App.vueإاّل أ ّنها ُتعتبر في حقيق ة األم ر بس يطة وواض حة
><template
>"<div class="container
>"<div class="row
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-
>"offset-3
><h2>Vue.js Remote Server</h2
>"<div class="form-group
><label>Username</label
<input type="text" class="form-control" v-
>model="user.username" /
></div
>"<div class="form-group
><label>First name</label
<input type="text" class="form-control" v-
>model="user.firstname" /
></div
>"<div class="form-group
><label>Last name</label
<input type="text" class="form-control" v-
>model="user.lastname" /
></div
></div
></div
>"<div class="row
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-
>"offset-3
"<button class="btn btn-primary
>@click="postOrPutData()">{{actionButtonTitle}}</button
"<button class="btn btn-primary float-right
>@click="reset()">Reset</button
155
Vue.js أساسيات إطار العمل لالتصال باإلنرتنتVue.js استخدام
</div>
</div>
<hr>
<div class="row">
<div class="col-2">
<button class="btn btn-primary btn-dark"
@click="getData()">Retrieve</button>
</div>
</div>
<div class="row" v-for="usr in users" v-bind:key="usr.username">
<div class="col-2">{{usr.username}}</div>
<div class="col-4">{{usr.firstname}} {{usr.lastname}}</div>
<div class="col-1">
<button class="btn btn-link"
@click="prepareToSave(usr.id)">Edit</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
user: {
username: "",
firstname: "",
lastname: "",
},
users: [],
currentUserIdToSave: "",
actionButtonTitle: "Add",
};
},
methods: {
postOrPutData: function () {
if (this.actionButtonTitle === "Add") {
this.$http
.post(
"https://vue-remote-servers.firebaseio.com/users.json",
this.user
)
.then(
(response) => {
console.log(response);
this.user.username = "";
this.user.firstname = "";
this.user.lastname = "";
},
(error) => {
156
Vue.js أساسيات إطار العمل لالتصال باإلنرتنتVue.js استخدام
console.log(error);
}
);
} else {
this.$http
.put(
"https://vue-remote-servers.firebaseio.com/users/" +
this.currentUserIdToSave +
".json",
this.user
)
.then(
(response) => {
console.log(response);
},
(error) => {
console.log(error);
}
);
}
},
getData: function () {
this.$http
.get("https://vue-remote-servers.firebaseio.com/users.json")
.then((response) => {
return response.json();
})
.then((data) => {
const tmpArray = [];
this.users = tmpArray;
});
},
prepareToSave: function (id) {
for (var i = 0; i < this.users.length; i++) {
if (this.users[i].id === id) {
this.user.username = this.users[i].username;
this.user.firstname = this.users[i].firstname;
this.user.lastname = this.users[i].lastname;
this.currentUserIdToSave = this.users[i].id;
this.actionButtonTitle = "Save";
break;
}
}
157
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
},
{ )( reset: function
;"this.actionButtonTitle = "Add
;"" = this.currentUserIdToSave
;"" = this.user.username
;"" = this.user.firstname
;"" = this.user.lastname
},
},
;}
></script
><style
{ .row
;margin-top: 8px
}
></style
ّ
سأوضح التعديالت الرئيسية التي طرأت على الش يفرة البرمجي ة .في البداي ة أج ريت تع ديالت تنس يقية
على القسم < >templateللسماح بإضافة زر جديد اسمه ،Resetباإلضافة إلى أ ّنني غيرت العنص ر المس ؤول
عن عرض بيانات المستخدمين من قاعدة البيانات (كان عبارة عن قائم ة غ ير مرتب ة ،)ulوذل ك لكي أس تطيع
إضافة زر تعديل Editبجوار كل مستخدم للسماح بتعديل بياناته في حال الرغبة بذلك.
أضفت ً
أيضا حقلين جدي دين للقس م ،dataاألول ه و currentUserIdToSaveووظيفت ه االحتف اظ
بمعنى آخر ،سيعمل التطبيق على تنفيذ مجموعة مختلفة من التعليمات البرمجية بحسب النص الذي يظهر
سي ّ
نفذ عند النقر على هذا ال زر ،فق د غ يرت اس م حالي ا على هذا الزر .لذلك فمن المنطقي تغيير اسم التابع الذي ُ
ً
التابع من postDataإلى postOrPutDataلإلشارة إلى وظيفته الجديدة المتمثلة في اإلضافة الجديدة أو
هذا التابع:
158
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
this.user
)
(.then
{ >= )(response
;)console.log(response
;"" = this.user.username
;"" = this.user.firstname
;"" = this.user.lastname
},
{ >= )(error
;)console.log(error
}
;)
{ } else
this.$http
(.put
"https://vue-remote-servers.firebaseio.com/users/" +
this.currentUserIdToSave +
".json",
this.user
)
(.then
{ >= )(response
;)console.log(response
},
{ >= )(error
;)console.log(error
}
;)
}
الحظ عبارة ifالموجودة في بداية التابع ،وانتبه إلى الشرط الموجود ضمنها .يختبر هذا الش رط فيم ا إذا
كانت القيمة الحالية للحقل actionButtonTitleتساوي القيمة .Addفإذا تحقق هذا الش رط ،فه ذا يع ني
أنن ا نري د إض افة مس تخدم جدي د ،فتُ ّ
نف ذ الكتل ة البرمجي ة المتعلق ة بتحق ق ذل ك الش رط ،وهي نفس الكتل ة
تستخدم في ه ذه الم رة الت ابع putكم ا ه و واض ح .يتم التحكّم في قيم ة الحق ل actionButtonTitle
ض من الت ابعين الجدي دين prepareToSaveو resetكم ا س نرى ذل ك بع د قلي ل .ل نركّز اآلن قلياًل على
التابع :put
this.$http
(.put
"https://vue-remote-servers.firebaseio.com/users/" +
this.currentUserIdToSave +
159
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
".json",
this.user
)
كيف وضعت اسم الجدول (المجموعة) usersيليه قيمة المفتاح الرئيسي الذي حصلت عليه من قيمة الحق ل
userالذي من المفترض اآلن أن يحمل البيانات المعدّ لة لهذا المستخدم .من الممكن أن نجري تعديل على ج زء
من البيان ات أو على جمي ع البيان ات أو أن ال نج ري أي ة تع ديالت .في ك ل حال ة من الح االت الس ابقة س يتم
استبدال بالقيم الحالية لبيانات الكائن userالبيانات القديمة الموجودة ضمن قاع دة البيان ات وال تي له ا نفس
كما أوضحت قب ل قلي ل ،فق د أض فت ت ابعين جدي دين هم ا prepareToSave :و ،resetكم ا أج ريت
بسيطا للتابع .getDataس أبدأ من التع ديل البس يط ال ذي أجريت ه على الت ابع .getDataأض فت في
ً تعدياًل
أنشأت متغير جديد اسمه withIdتنحصر وظيفته في إضافة الحقل idإلى البيانات التي تأتي أصاًل من
قاعدة البيانات وذلك بهدف االحتفاظ بالمفتاح الرئيسي لكل مستخدم مع بيانات ه األساس ية .س نرى س بب ه ذا
بالنسبة للشيفرة البرمجي ة لك ل من الت ابعين prepareToSaveو resetفهي بس يطة للغاي ة .بالنس بة
وسيطا واح دً ا ه و
ً فيستدعى عند نقر الزر Editبجوار مستخدم ما .يقبل هذا التابع
للتابع ُ prepareToSave
قيمة المفتاح الرئيسي لذلك المستخدم الذي نرغب بتعديل بياناته .بعد ذلك ندخل حلق ة ،forه دفها الوص ول
( idالذي يحمل قيمة المفتاح الرئيسي للمستخدم المراد تعديله) م ع قيم ة الحق ل idلك ل مس تخدم موج ود
ض من المص فوفة .usersالح ظ هن ا أنّ الحق ل idالموج ود ض من المص فوفة usersق د أض فناه ض من
التابع .getData
160
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
بع د الوص ول إلى الك ائن المطل وب ض من المص فوفة ،تعم ل الش يفرة على تح ديث بيان ات الحق ل user
وبالت الي تتم تعبئ ة عناص ر اإلدخ ال على الص فحة ببيان ات المس تخدم الم راد تعديل ه ،ثم ُتع دَّ ل قيم ة الحق ل
currentUserIdToSaveليحم ل قيم ة المفت اح الرئيس ي له ذا المس تخدم الم راد تعديل ه (الح ظ أ ّنن ا
يرا بالنس بة للت ابع resetفه و يُ عي د األم ور إلى أص لها األول .أي يعم ل على تفري غ حق ول اإلدخ ال،
وأخ ً
ويعم ل على إع ادة الس ياق إلى حال ة إدخ ال مس تخدم جدي د بإس ناد القيم ة Addض من الحق ل
حالي ا أي
ً ،actionButtonTitleكما يعمل على تفري غ الحق ل currentUserIdToSaveأل ّن ه ال يوج د
إذا شغلت التطبيق بعد هذه التعديالت يُ فترض أن تحصل على شكل شبيه بما يلي (الح ظ أ ّن ني ق د نق رت
ً
أيضا الزر :)Retrieve
161
أساسيات إطار العمل Vue.js استخدام Vue.jsلالتصال باإلنرتنت
جرب نقر زر Editبجوار أحد المستخدمين ،ثم عدّ ل بيانات ه ،ثم انق ر زر ،Saveوبع دها انق ر زر Retrieve
من جديد .يجب أن ترى اآلن التعديالت التي أجريته ا على ذل ك المس تخدم .انق ر زر Resetللع ودة إلى س ياق
االنتقال إلى صفحة منفصلة عند النقر على زر Editلتعديل بيانات المستخدم بشكل مستقل .لكنني آثرت
تماما
اتباع هذا األسلوب غير العملي اآلن ،ألنّ اتباع األسلوب العملي يقتضي الدخول في بحث جديد ً
ً
الحقا في فصل منفصل إن شاء اهلل. وهذا ما سأفعله
ً
مسبقا باستخدام التابع deleteمع الكائن من الممكن ً
أيضا إضافة ميزة حذف مستخدم موجود
10.5ختام الفصل
ّ
وتعلمن ا لقد ّ
تعل منا الكثير في هذا الفصل كيفية إنشاء قاعدة بيانات بسيطة على ،Google Firebaseكما
كيفية استخدام المكتبة vue-resourceإلكساب تطبيقات Vue.jsالقدرة على االتصال باإلنترنت ،وبنينا ً
أيضا
مبس ط ّ
يوض ح كيفي ة التواص ل م ع قاع دة البيان ات على ،Google Firebaseوبالت الي كيفي ة تطبيق عملي ّ
إضافة وقراءة وتعديل البيانات الموجودة ضمنها.
مهم ا بالفعل ،فمن خالله استطعت للمرة األولى الخروج من "القمقم" والتواص ل م ع الع الم
يعد هذا الفصل ًّ
مهم ة ً
أيض ا ح ول كيفي ة التعام ل م ع Vue.jsتل ك المكتبة الخ ارجي .س تحمل م ا تبقى من فص ول مف اهيم ّ
القوية والمرنة.
162
.11بناء تطبيقات ذات صفحة واحدة
ّ
سنتعلم في هذا الفصل:
دة فحة واح د على ص ات تعتم اء تطبيق ة بن ل كيفي ذا الفص ّ
نتعلم في ه س
فق ط ( )Single Page Applicationsأو اختص ا ًرا .SPAت ّ
وفر Vue.jsه ذه اإلمكاني ة من خالل مكتبة
اسمها vue-routerتسمح بتعريف مسارات داخلية ض من التط بيق به دف دعم مفه وم .SPAوتطبيق ات SPA
هي تطبيقات ويب عادية ،لك ّنها تختلف عن التطبيقات الكالسيكية في أنّ االنتقال من ص فحة إلى أخ رى ض من
الموقع ال يحتاج إلى إعادة تحميل كامل الصفحة بما تحويه من ملفات شيفرة نصية وص ور وغيره ا من أص ول
معرف ة
الموقع .فالذي يحدث في تطبيقات SPAهو أنّ جميع الواجهات المفترض وجوده ا في الموق ع س تكون ّ
ومحملة إلى حاسوب المستخدم ،فيعمل تطبيق SPAفقط على استبدال واجهة مكان واجهة أخرى دون
ّ ً
مسبقا
ً
كاملة من الخادوم. الحاجة إلى تحميل الصفحة
وثيق ا بالفص ل الس ابق أل ّن ه س يعمل على تحوي ل التط بيق المعتم د في الفص ل
ً ارتباط ا
ً يرتبط هذا الفصل
السابق إلى تطبيق يدعم SPAلذلك أنصحك بمراجعة الفصل الس ابق قب ل االس تمرار في ه ذا الفص ل .على أي ة
بنينا في الفصل السابق تطبيق تجريبي بسيط ،هدفه التواصل مع قاعدة بيانات موج ودة على ،Firebase
عمليا
ًّ ّ
ولعلك تذكر ،أ ّنني قد أشرت في ذلك الفصل إلى أنّ األسلوب ال ذي اتبعن اه في بن اء ذل ك التط بيق لم يكن
بسبب أ ّننا قد "حشرنا" جميع وظ ائف التط بيق ض من واجه ة واح دة وه ذا أم ر غ ير عملي ب الطبع .ح ان اآلن
إصالح ذلك العيب وذل ك باس تخدام تقني ة .SPAس نحوّ ل جمي ع وظ ائف التط بيق الس ابق إلى تط بيق جدي د
موجه األوامر:
ّ لنبدأ بإنشاء هيكل التطبيق الجديد بتنفيذ األمر التالي ضمن
لكي ننج ز مفه وم SPAفي تطبيقن ا ه ذا ،سنس تخدم تقني ة التوجي ه ( )Routingال تي عن طريق
المكتبة vue-routerكما أشرنا قبل قليل .استخدم األمر التالي لتثبيت المكتبة :vue-router
ّ
مجلد التطبيق باس تخدام Visual Studio Codeثم اح ذف المل ف .HelloWorld.vueس نحتاج افتح
ّ
والمجل دات من أج ل ه ذا التط بيق .انق ر اآلن ب زر الف أرة األيمن على إلى إنش اء مجموع ة جدي دة من الملف ات
ّ
المجل د لتخ زين الواجه ات سمه .viewsسنستخدم هذا ّ
مجلد جديد ّ ّ
المجلد srcواختر New Folderإلنشاء
ّ
المجلد viewsالذي أنش أناه ت ًّوا الملف ات التالي ة AddUser.vue :و المختلفة للتطبيق الخاص بنا .أنشئ ضمن
ّ
المجل د .srcالمل ف EditUser.vueو AllUsers.vueو .Home.vueأنش ئ ً
أيض ا المل ف routes.jsض من
164
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
عن طري ق عب ارةvue-router يجب أواًل أن نس تورد المكتب ة،لكي نب دأ باس تخدام التوجي ه
:االستيراد التالية
ّ
وسأوض ح س بب ذل ك بع د routes.js سنضع هذه العبارة (وبشكل مختلف عما اعتدنا عليه) ضمن المل ف
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: Home
165
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
},
{
path: "/AddUser",
name: "AddUser",
component: AddUser
},
{
path: "/EditUser",
name: "EditUser",
component: EditUser
},
{
path: "/AllUsers",
name: "AllUsers",
component: AllUsers
},
;]
أوضحنا قبل قليل ،أنّ وظيفة الملف routes.jsهي تعريف مسارات العناوين الداخلي ة ال تي سنس تخدمها
أول تعليمتين واض حتين أم ا بالنس بة للتعليم ات األرب ع األخ رى ،فهي الس تيراد الواجه ات ال تي
أعتقد أنّ ّ
سنس تخدمها في التط بيق .ه ذه الواجه ات هي بطبيع ة الح ال مكوّ ن ات (أل ّنه ا موج ودة ض من ملف ات تحم ل
االمتداد .)vue
;)Vue.use(VueRouter
[ = const routes
{
path: "/",
166
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
name: "Home",
component: Home
},
{
path: "/AddUser",
name: "AddUser",
component: AddUser
},
{
path: "/EditUser",
name: "EditUser",
component: EditUser
},
{
path: "/AllUsers",
name: "AllUsers",
component: AllUsers
},
;]
الحظ معي أننا نضع المسارات التي سنستخدمها في التطبيق ضمن مصفوفة اس مها .routesك ل عنص ر
من هذه المصفوفة عبارة عن ك ائن ل ه الحق ول path :و nameو .componentانظ ر مثاًل إلى الك ائن ّ
األول
{
path: "/",
name: "Home",
component: Home
}
ّ
ويمث ل عرف المسار الخاص بها ليكون / ّ
يمث ل هذا الكائن المسار الخاص بالصفحة الرئيسية للتطبيق .فهو يُ ّ
الصفحة الرئيسية في تطبيقات الويب عادة .أي يمكن الوصول إلى هذه الواجهة من خالل الرابط التالي:
http://www.yourdomain.com/#/
ً
الحقا في ه ذا أما اسم هذا المسار فهو ( Homeمن الممكن أن نصل إلى أي مسار من خالل اسمه كما سنرى
ّ
الفص ل) .بالنس بة للواجه ة ال تي س ترتبط به ذا المس ار فهي ( Homeانظ ر إلى تعليم ة االس تيراد الخاصة
بالواجهة .)Home.vue
تماما ،فإذا أخذنا مثاًل المسار الثاني فنج د أنّ المس ار ال ذي
بالنسبة لباقي المسارات فتعمل بنفس األسلوب ً
يُ شير إليه هو /AddUserأي أ ّن نا نستطيع الوصول إليه عن طريق رابط مماثل لما يلي:
http://www.yourdomain.com/#/AddUser
167
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
Vue.config.productionTip = false
;)Vue.use(VueResource
;)Vue.use(VueSimpleAlert
{(new Vue
router,
render: h => h(App),
)'}).$mount('#app
استيراد المكتبة vue-resourceلالتصال بالخواديم البعيدة ،والتي تعاملنا معها في الفصل السابق. •
ً
مسبقا .والهدف منه ا ع رض رس ائل استيراد مكتبة جديدة اسمها vue-simple-alertلم نتعامل معها •
ّ
سنتعلم بعد قليل كيفية التعامل معها. ذات تنسيق جميل للمستخدم،
موجه األوامر:
ّ ستحتاج بالتأكيد إلى تثبيت المكتبة vue-simple-alertبتنفيذ األمر التالي ضمن
168
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
Vue.use(VueResource);
Vue.use(VueSimpleAlert);
new Vue({
router,
render: h => h(App),
}).$mount('#app')
ولكن الح ظ معي هن ا كي ف أض فت ك ائن، وق د اس تخدمنا مثله ا م را ًرا،التعليم ة الس ابقة مألوف ة
الموجه
ّ ولن يعم ل التوجي ه في التط بيق م ا لم نض ف ك ائن، ه ذه اإلض افة ض رورية. إليه اrouter لموج ه
ّ
.بهذه الصورة
App.vue الملف11.2.1
<template>
<div id="app">
<nav id="nav">
<p class="logo-place">Vue.js Remote Server (Enhanced)</p>
<ul class="nav-links">
<li class="links">
<router-link to="/">Home</router-link>
</li>
<li class="links">
<router-link to="/AddUser">Add User</router-link>
</li>
<li class="links">
<router-link to="/AllUsers">All User</router-link>
</li>
</ul>
</nav>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
169
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
components: {},
};
</script>
<style>
#nav {
display: flex;
margin-bottom: 24px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
text-decoration: none;
margin-right:12px;
}
#nav a.router-link-active {
color: #ab26ab;
}
.nav-links {
padding-right: 20px;
list-style: none;
display: flex;
margin:21px 0 0 0;
}
.links-hover {
text-decoration: underline;
}
.logo-place {
font-size: 20px;
color: purple;
font-weight: bold;
margin:16px 0 0 16px;
}
</style>
الح ظ أواًل وج ود وس م جديد.هن اك أم ران جدي دان س نتحدث عنهم ا بالنس بة له ذا المل ف
،vue-router في الحقيق ة أنّ ه ذا الوس م م ا ه و إاّل مك وّ ن موج ود ض من المكتب ة.router-view اس مه
كما أش رناSPA ّألن تطبيقات.ووظيفته تحديد مكان إدراج واجهات التطبيق المختلفة ضمن الصفحة الرئيسية
. ال تتطلب إعادة تحميل الصفحة بالكامل عندما يريد المستخدم االنتقال إلى واجهة مختلفة،من قبل
170
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
ً وهو مكوّ نrouter-link األمر اآلخر هو وجود وسم جديد آخر وهو
وظيف ة.أيضا ضمن نفس المكتب ة
وجه إلي ه
َّ ) ال ذي س ُيPath( و هي مس ؤولة عن تحدي د المس ارto نجد من المقطع الس ابق وج ود الس مة
:وجه المستخدم إلى المسار الكامل التالي
َّ سي
ُ في المثال السابق.المستخدم عند نقر هذا الرابط
http://www.yourdomain.com/#/AddUser
Home.vue الملف11.2.2
:وهو ملف الصفحة الرئيسية في التطبيق وستكون محتوياته على الشكل التالي
<template>
<div class="container">
<div class="row">
<div class="col-6 offset-2">
<h1>Welcome in our website!</h1>
</div>
</div>
171
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
</template>
<script>
export default {
name: "Home",
};
</script>
س وى أ ّن ك تمتل ك الح ق في إض افة أص ناف تنس يقية إلى،ال يوج د في الش يفرة الس ابقة أي جدي د
AddUser.vue الملف11.2.3
انظ ر معي إلى الش يفرة البرمجي ة.يحتوي هذا الملف على الواجهة المسؤولة عن إض افة مس تخدم جدي د
:الخاصة به
ّ
<template>
<div class="container">
<div class="row">
<div class="col-6 offset-2">
<h1>Add User</h1>
</div>
</div>
<div class="row">
<div class="col-6 offset-2">
<div class="container">
172
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
<div class="row">
<div class="col-12">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" v-
model="user.username" />
</div>
<div class="form-group">
<label>First name</label>
<input type="text" class="form-control" v-
model="user.firstname" />
</div>
<div class="form-group">
<label>Last name</label>
<input type="text" class="form-control" v-
model="user.lastname" />
</div>
</div>
</div>
</div>
<button class="btn btn-primary float-left" style="margin-
left:12px;" @click="postUser()">Add</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: "AddUser",
methods: {
postUser() {
this.$http
.post("https://vue-remote-servers.firebaseio.com/users.json",
this.user)
.then(
() => {
this.user.username = "";
this.user.firstname = "";
this.user.lastname = "";
173
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
{ return
{ user:
username: "",
firstname: "",
lastname: "",
},
;}
},
;}
></script
><style scoped
{ .row
;margin-top: 8px
}
></style
الشيفرة البرمجية الموجودة ضمن هذا الملف تماثل تقري ًبا تلك ال تي ك انت مس ؤولة عن إض افة مس تخدم
كما كان من الممكن إضافة رسالة شبيهة بالرسالة السابقة في ح ال فش لت عملي ة اإلض افة للمس تخدم (لم
ُأ ضف مث ل ه ذه الرس الة إلى الش يفرة الس ابقة) .الت ابع $alertموج ود ض من المكتب ة vue-simple-alert
منس قة للمس تخدم .بالنس بة لمثالن ا ه ذا ،س نعرض رس الة ُتخ بر
وظيفته كما هو واض ح ،ه و في ع رض رس الة ّ
المستخدم بأنّ عملية إضافة بيانات المس تخدم إلى قاع دة بيان ات Firebaseق د تمت بنج احّ .
يمث ل الوس يط
174
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
AllUsers.vue الملف11.2.4
يحتوي هذا المل ف على الواجه ة الخاص ة بع رض بيان ات المس تخدمين ال ذين س بق إض افتهم إلى قاع دة
<template>
<div class="container">
<div class="row">
<h2>All Users</h2>
<button style="margin-left:16px;" class="btn btn-primary"
@click="getData()">Retrieve</button>
</div>
<hr />
<div class="row" v-for="usr in users" v-bind:key="usr.username">
<div class="col-2">{{usr.username}}</div>
<div class="col-4">{{usr.firstname}} {{usr.lastname}}</div>
<div class="col-1">
<router-link :to="{name: 'EditUser', params:
{user:usr}}">Edit</router-link>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
user: {
username: "",
firstname: "",
lastname: "",
},
175
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
users: [],
;}
},
{ methods:
{ )( getData: function
this.$http
)".get("https://vue-remote-servers.firebaseio.com/users.json
{ >= ).then((response
;)(return response.json
)}
{ >= ).then((data
;][ = const tmpArray
;this.users = tmpArray
;)}
},
},
;}
></script
><style scoped
{.row
;margin-top:8px
}
></style
مرة أخرى ،ال تختلف الشيفرة البرمجية الموج ودة هن ا عن تل ك ال تي ك انت موج ودة في الفص ل الس ابق.
فعن دما ينتق ل المس تخدم له ذه الواجه ة وينق ر على ال زر ،Retrieveس تُ حدّ ث الواجه ة بحيث تع رض جمي ع
حاليا ضمن قاعدة بيانات .Firebaseبعد عرض هؤالء المس تخدمين ،س تالحظ وج ود
ً المستخدمين المخزنين
رابط اسمه Editيظه ر بج وار ك ل مس تخدم .عن د نق ر ه ذا ال زر س ينقلك التط بيق إلى واجه ة تحري ر بيان ات
ولكن السؤال هن ا ،كي ف س تتمكّن الواجه ة EditUserمن معرف ة المس تخدم المطل وب تحري ر بيانات ه؟
ّ
الجواب هو في المكوّ ن router-linkالموجود ضمن هذه الواجهة .AllUsersانظ ر معي إلى االس تخدام
176
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
استخدمنا في المقطع السابق السمة toبشكل مختل ف عن اس تخدامنا له ا في الواجه ات الس ابقة .الح ظ
أواًل كيف وضعت نقطتين رأسيتين قبل كلمة toمباش ر ًة (وهم ا ض روريتان في ه ذه الحال ة) ،ثم أس ندت إلى
ّ
ويمثل اسم الواجهة التي نري د هذا الكائن لديه مفتاحين .األول هو nameويمتلك القيمة '،'EditUser
االنتقال إليها عندما ينقر المستخدم ه ذا الراب ط .الح ظ أ ّن ني قلت "اس م" وليس "مس ار" ،أي أنّ االس م ال ذي
ً
موافق ا للقيم ة nameال تي ك انت موج ودة ض من مل ف المس ارات routes.jsعن دما نكتبه هنا يحب أن يكون
بالنسبة للمفتاح الثاني فهو paramsوهو مسؤول عن تمري ر أي ة وس ائط نرغبه ا إلى الواجه ة ال تي نري د
االنتقال إليها .في حالتنا ه ذه ن رغب بتمري ر بيان ات المس تخدم الم راد تحريره ا بش كل كام ل .طريق ة التمري ر
مررنا كائن جديد للمفتاح paramsيحتوي ه ذا الك ائن في حالتن ا ه ذه ،على مفت اح
مفيدة للغاية ،الحظ كيف ّ
وحيد اسمه userونسند له القيمة usrالتي ُتعت بر كائ ًن ا مس تقاًل بح د ذات ه يحت وي على بيان ات المس تخدم
المراد تحرير بياناته .أي أنّ { }user:usrعب ارة عن ثنائي ة تح وي اس م الوس يط userم ع القيم ة المرتبطة
به .usr
يمكن بالطبع تمرير أكثر من وسيط إلى الواجهة باألسلوب السابق ،وذلك بوضعها بج وار بعض ها على ش كل
177
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
EditUser.vue الملف11.2.5
باإلض افة إلى إمكاني ة ح ذف بيان ات ه ذا المس تخدم،في هذه الواجهة يمكنن ا تع ديل بيان ات المس تخدم
ً
.)مسبقا في الفصل السابق ّ بشكل
كلي من قاعدة البيانات (هذه ميزة جديدة لم تكن ُمضافة
<template>
<div class="container">
<div class="row">
<div class="col-6 offset-2">
<h1>Edit User</h1>
</div>
</div>
<div class="row">
<div class="col-6 offset-2">
<div class="container">
<div class="row">
<div class="col-12">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" v-
model="user.username" />
</div>
<div class="form-group">
<label>First name</label>
<input type="text" class="form-control" v-
model="user.firstname" />
</div>
<div class="form-group">
<label>Last name</label>
<input type="text" class="form-control" v-
model="user.lastname" />
</div>
</div>
</div>
</div>
<button class="btn btn-primary float-left" style="margin-
left:12px;" @click="putUser()">Save</button>
<button
class="btn btn-danger float-right"
style="margin-right:12px;"
@click="deleteUser()"
>Delete</button>
</div>
</div>
</div>
</template>
178
Vue.js أساسيات إطار العمل بناء تطبيقات ذات صفحة واحدة
<script>
export default {
name: "EditUser",
methods: {
putUser() {
this.$http
.put(
"https://vue-remote-servers.firebaseio.com/users/" +
this.$route.params.user.id +
".json",
this.user
)
.then(
() => {
this.$alert(
"The user is updated.",
"Operation Succeeded",
"success"
);
},
(error) => {
console.log(error);
}
);
},
deleteUser() {
this.$confirm("Are you sure you want to delete the
user?").then(() => {
this.$http
.delete(
"https://vue-remote-servers.firebaseio.com/users/" +
this.$route.params.user.id +
".json"
)
.then(
() => {
this.$router.push('AllUsers');
},
(error) => {
console.log(error);
}
);
});
},
},
computed: {
user() {
return this.$route.params.user;
},
},
};
179
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
></script
><style scoped
{ .row
;margin-top: 8px
}
></style
الشيء الذي أود التركيز عليه من الشيفرة السابقة ه و كيفي ة اس تالم الوس ائط المم ّررة له ذه الواجه ة من
{ )(user
;return this.$route.params.user
}
مررن اه من
ترج ع الوس يط ال ذي ّ
تحت وي ه ذه الخاص ية المحس وبة على تعليم ة برمجي ة واح دة ُ
this.$route.params.user
الوسيط هو userكما أسميناه ض من الواجه ة ،AllUsersيحت وي ه ذا الوس يط على بيان ات المس تخدم
المفت اح paramsكم ا ه و واض ح ،والموج ود ب دوره ض من الك ائن ( $routeالموج ود ض من المكتب ة vue-
>"<div class="col-12
>"<div class="form-group
><label>Username</label
<input type="text" class="form-control" v-
>model="user.username" /
></div
>"<div class="form-group
><label>First name</label
<input type="text" class="form-control" v-
>model="user.firstname" /
></div
>"<div class="form-group
><label>Last name</label
<input type="text" class="form-control" v-
>model="user.lastname" /
180
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
></div
></div
أود ً
أيض ا التح دث عن الت ابع $confirmالموج ود ض من المكتب ة vue-simple-alertووظيفت ه
تخييرك بين أمرين .استخدمت التابع $confirmضمن التابع deleteUserوذلك لكي نطلب من المستخدم
تأكيد أ ّن ه يريد حذف المستخدم الحالي من قاعدة البيانات .انظر الشيفرة البرمجية للتابع :deleteUser
مألوفة وتشبه أخواتها من المقاطع البرمجية األخرى المسؤولة عن التعامل مع قاعدة بيانات .Firebaseالح ظ
;)'this.$router.push('AllUsers
هذا هو األسلوب المتبع لالنتقال بين الواجهات بشكل برمجي ،وذلك عن طريق اس تخدام الت ابع pushمن
نمر ر "اسم" الواجهة التي نرغب باالنتقال إليها كوسيط للتابع .push
الكائن ،$routerحيث ّ
181
أساسيات إطار العمل Vue.js بناء تطبيقات ذات صفحة واحدة
11.3ختام الفصل
مس تقباًل ،فأعتق د أنّ خ ير رفي ق ل ك س يكون التوثي ق الرس مي للتوجي ه تج ده على ه ذا الموقع ولكن باللغ ة
اإلنجليزية .أقترح عليك بعد قراءة هذا الفصل أن تحاول تج ريب بن اء تطبيق ات بس يطة تعتم د على التوجي ه،
182
.12نرش تطبيق Vue.jsإىل اإلنتـرنت
ّ
سنتعلم في هذا الفصل:
إنشاء موقع جديد على منصة Netlifyباالستناد إلى مستودع GitHub •
هذا الفصل هو األخير ،حيث سنتوّ ج هذا الكتاب بشرح كيفية نشر التطبيق الوارد في الفصل الس ابق ،وه و
عبارة عن تطبيق SPAيدعم التخاطب مع قاعدة بيانات موجودة على Firebaseكما تذكر .بع د بن اء التط بيق
ونشره ،س يتمكّن أي مس تخدم ح ول الع الم من الوص ول إلى تطبيقن ا ه ذا والتفاع ل مع ه .س أعتمد اس تخدام
كما ذكرت قبل قليل ،سنعتمد التطبيق المبني في الفصل السابق لتشغيله على خدم ة .Netlifyبغي ة ذل ك،
الي: تودع Githubالت ل على مس كل كام بيق بش ذا التط عه عملت على رف
github.com/HsoubAcademy/vuejs-spa
سبب ذلك هو أنّ Netlifyيسحب التطبيقات الموجودة على خدمات Gitمثل .GitHubس تحتاج ب الطبع
إلى أن يكون لديك حساب على ُ .GitHubزر المستودع الس ابق ،وس ّجل دخول ك على GitHubإذا لم تكن ق د
ً
مسبقا ،ومن الصفحة الرئيسية لمستودعنا ،انقر الزر Forkفي الزاوي ة اليم نى العلي ا إلنش اء تفريع ة فعلت ذلك
سيتطلب األمر لحظات حتى يتم إنشاء التفريعة من الشيفرة البرمجية ووضعها ضمن حسابك الخاص.
أنشئ حسابًا جديدً ا على Netlifyعن طريق زيارة الصفحة الرئيسية له الموقع الرسمي .انقر Sign upمن
حالي ا على
ً الزاوي ة اليم نى العلي ا لتظه ر ل ك الص فحة الخاص ة بإنش اء اش تراك جدي د .تب دو ه ذه الص فحة
النحو التالي:
الح ظ معي وج ود خي ارات متع ددة للتس جيل .سنس تخدم في حالتن ا ه ذه التس جيل باس تخدام البري د
بعد كتابة البريد اإللكتروني الذي تودّ التسجيل عن طريقه ،سيرس ل الموق ع رس الة تحق ق إلى ه ذا البري د
184
أساسيات إطار العمل Vue.js نرش تطبيق Vue.jsإىل اإلنتـرنت
ه ذه هي الص فحة الرئيس ية وال تي تحت وي على جمي ع عناص ر التحكم الخاص ة بحس ابك .نحن اآلن
ً
مسبقا ،وهي فارغة اآلن بطبيعة الح ال .انق ر موجودون ضمن الصفحة الخاصة بمواقع الويب التي أنشأتها أنت
الزر " "New site from Gitمن الطرف األيمن في األعلى ،لالتصال بمستودع من النوع .Gitستحص ل على
انق ر ال زر GitHubالموج ود في األس فل ،س يؤدي ذل ك إلى فتح ناف ذة جدي دة ق د تطلب من ك تس جيل
الدخول بحسابك على GitHubفي حال لم تكن مسجاًل دخولك على GitHubبعد (ذلك الحساب الذي أنش أت
التفريعة ضمنه):
185
أساسيات إطار العمل Vue.js نرش تطبيق Vue.jsإىل اإلنتـرنت
انقر الزر Authorize Netlifyللسماح لـ Netlifyبالوصول إلى حساب GitHubالخ اص ب ك .بع د إكم ال
عملية االستيثاق ( ،)Authorizationستظهر لك ص فحة تس مح ل ك باالختي ار بين الس ماح الكام ل لـ Netlify
للوصول إلى جميع المستودعات ضمن حسابك أو السماح بالوصول إلى مستودع مح دّ د .بالنس بة إلي ،سأس مح
ل ه بالوص ول إلى المس تودع vuejs-spaفق ط ،وه و المس تودع ال ذي أنش أناه كتفريع ة قب ل قلي ل من
الفقرة السابقة.
186
أساسيات إطار العمل Vue.js نرش تطبيق Vue.jsإىل اإلنتـرنت
تتضمن االنتقال إلى موقع GitHubبشكل تلق ائي وذل ك إلكم ال
ّ انقر زر Installلتبدأ عملية التثبيت التي
عملية الربط (قد يطلب منك كلمة المرور لحسابك في GitHubمرة أخرى).
بعد االنتهاء من العملية السابقة ستحتاج إلى العودة إلى الصفحة الرئيس ية لموق ع Netlifyوتك رار عملي ة
إنشاء موقع من مستودع ( GitHubالشكل رقم .)3هذه المرة س يظهر لن ا المس تودع ال ذي ن رغب باس تيراده.
187
أساسيات إطار العمل Vue.js نرش تطبيق Vue.jsإىل اإلنتـرنت
الرئيسي ( )Branchالتي سنستخدمه في عملية نش ر التط بيق ،باإلض افة إلى تحدي د التعليم ة الخاص ة ببن اء
ّ
والمجل د الخاص بالنشر .احرص على أن تحصل على شكل شبيه بما يلي: التطبيق،
أخيرا ،انقر الزر Deploy siteلبناء التطبيق ونشر الموقع على اإلن ترنت .س تأخذ ه ذه العملي ة القلي ل من
ً
الوقت ،حيث ستنتقل إلى ص فحة تخ برك ب أنّ عملي ة البن اء والنش ر قي د التجه يز .بع د أن تنتهي عملي ة البن اء
188
أساسيات إطار العمل Vue.js نرش تطبيق Vue.jsإىل اإلنتـرنت
الخيارات السابقة وأكثر يمكن التحكم بها من خالل خيارات الموقع في .Netlify
12.3ختام الفصل
ختمنا في هذا الفصل كتابنا ه ذا ،أساس يات إط ار العم ل ،Vue.jsبش رح كيفي ة نش ر التط بيق إلى خدم ة
متاحا على اإلنترنت .توجد العديد من الخ دمات ال تي تس مح بالنش ر المج اني ،ولك ّن ني
ً مجانية ليصبح تطبيقنا
ّ
لتتعلم ه حاولت في هذا الكتاب تغطية األمور األساسية فقط في ،Vue.jsلذلك فأمامك الكثير بك ل تأكي د
حول هذه التقنية الواعدة .يمكنك زيارة الموقع الرسمي إلطار العمل Vue.jsواالستزادة حوله.
189
أحدث إصدارات أكاديمية حسوب