<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: Vue.js</description><language>ar</language><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x645;&#x639;&#x631;&#x636; &#x623;&#x639;&#x645;&#x627;&#x644; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%85%D8%B9%D8%B1%D8%B6-%D8%A3%D8%B9%D9%85%D8%A7%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-r2493/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2025_01/-------Vue.js.png.515b97bd47ca1dac5935ef0c826c863a.png" /></p>
<p>
	تعرفنا في <a href="https://academy.hsoub.com/programming/html/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B9%D8%B1%D8%B6-%D8%A3%D8%B9%D9%85%D8%A7%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r2487/" rel="">مقال سابق</a> على طريقة بناء موقع ثابت كمعرض أعمال باستخدام تقنيات الويب الأساسية، وسنتعلم في هذا المقال أهم الخطوات التي علينا اتباعها لترقية موقعنا من موقع بسيط إلى تطبيق تفاعلي باستخدام لغة جافا سكريبت وإطار عملها Vue.js.
</p>

<h2 id="">
	متطلبات العمل
</h2>

<p>
	لإنشاء التطبيق نحتاج إلى تثبيت بيئة نود جي إس Node.js و<a href="https://academy.hsoub.com/programming/javascript/nodejs/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-%D9%81%D9%8A-nodejs-r1465/" rel="">مدير الحزم npm</a> على حاسوبنا المحلي، للقيام بذلك ننتقل إلى <a href="https://nodejs.org/" rel="external nofollow">موقع Node.js الرسمي</a> ونحمّل أحدث نسخة، بعد تنزيل وتثبيت Node.js سيثبت npm تلقائيًا. بعد ذلك نفتح <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">موجه الأوامر </a>أو الطرفية ونتحقق من أن<a href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-nodejs-r1463/" rel=""> Node.js</a> ومدير الحزم npm مثبتان بشكل صحيح باستخدام الأمرين التاليين:
</p>

<pre class="ipsCode">node -v
npm -v
</pre>

<p>
	بهذا نكون قد أعددنا متطلبات العمل، ونحن جاهزون للبدء بالخطوات العملية لإنشاء تطبيق معرض الأعمال.
</p>

<h2 id="-1">
	إنشاء بنية المشروع
</h2>

<p>
	يتوجب علينا بداية إنشاء مجلد جديد للمشروع، ثم ننشئ مشروع Vue.js جديد باستخدام الأمر التالي:
</p>

<pre class="ipsCode">npm init vue@latest
</pre>

<p>
	سينشئ هذا الأمر مشروع فيو جديد لكن سيُطلب منا بداية بعض الخيارات مثل اسم المشروع وتهيئة المشروع. بعد الانتهاء من إنشاء المشروع، سوف نتنقل له، ونثبت جميع الحزم أو التبعيات المطلوبة، ثم نشغل الخادم المحلي لعرض مشروعنا في المتصفح من خلال التعليمات التالية:
</p>

<pre class="ipsCode">cd &lt;your-project-name&gt;
npm install
npm run dev
</pre>

<p>
	يظهر لنا رابط الخادم المحلي localhost في الطرفية، ويمكن فتحه في المتصفح لعرض تطبيق Vue.js الخاص بنا كما في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="165534" href="https://academy.hsoub.com/uploads/monthly_2025_01/Vuejs.png.f8321975dd28592e0fff856a12d37203.png" rel=""><img alt="تطبيق vue js" class="ipsImage ipsImage_thumbnailed" data-fileid="165534" data-unique="fscwyyn2o" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2025_01/Vuejs.thumb.png.e0d52fda4076b11b02b5dad15193835e.png"> </a>
</p>

<h2 id="-2">
	بنية المشروع
</h2>

<p>
	إليك البنية التي سنتبعها لهذا المشروع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="165533" href="https://academy.hsoub.com/uploads/monthly_2025_01/983181213_.png.bc87a6f068349c6540ed49284687792f.png" rel=""><img alt="بنية التطبيق" class="ipsImage ipsImage_thumbnailed" data-fileid="165533" data-unique="q3wxaq4bz" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2025_01/983181213_.png.bc87a6f068349c6540ed49284687792f.png"> </a>
</p>

<p>
	يمثل <code>App.vue</code> المكوّن الجذر root component، الذي يحتوي بدوره على خمسة مكونات فرعية child components. من بين هذه المكونات كما تلاحظ المكوّن <code>ProjectListComponent.vue</code> الذي يمكن أن يحتوي بدوره على مكون فرعي آخر هو <code>ProjectComponent.vue</code>. لتشيكل هيكل متداخل بسيط ضمن التطبيق.
</p>

<p>
	يمكننا استخدام البنية التي نريدها لتنظيم مكونات المشروع، فمثلًا، يمكن استخدام مكوّن رئيسي <code>MainComponent</code> يحتوي على القسم التعريفي، وقسم المهارات، وقسم النشرة الإخبارية، وقائمة المشاريع كمكوّنات أبناء child components، لجعل البنية أكثر تعقيدًا، كما يمكننا الجمع بين قسم التعريف والمهارات وقسم النشرة الإخبارية بمكوّن واحد، فإطار العمل Vue.js يمنحنا حرية هيكلة مشروعنا بالطريقة التي تريدها.
</p>

<p>
	أولاً، علينا تعديل بعض المعلومات الوصفية meta information في ملف<code>Index.html</code>، وهو نقطة الأساس في المشروع:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5643_14" style=""><span class="dec">&lt;!doctype html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"description"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"My Portfolio"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"keywords"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"HTML, CSS, JavaScript"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"author"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"Hsoub Academy"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

    </span><span class="tag">&lt;title&gt;</span><span class="pln">My Portfolio</span><span class="tag">&lt;/title&gt;</span><span class="pln">
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"module"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"/src/main.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	علينا وضع المكوّن الجذر <code>App.vue</code> في العنصر <code>&lt;div id="app"&gt;&lt;/div&gt;</code> ضمن الملف index.html.
</p>

<h2 id="headercomponent">
	إنشاء المكوّن الجذر ومكوّن الترويسة header component
</h2>

<p>
	بإمكاننا الآن إنشاء المكوّن الأول <code>HeaderComponent.vue</code> ببساطة، كل ما علينا هو نسخ شيفرة HTML من الملف index.html الذي أنشأناه في <a href="https://academy.hsoub.com/programming/html/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B9%D8%B1%D8%B6-%D8%A3%D8%B9%D9%85%D8%A7%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r2487/" rel="">مقالنا السابق</a> ولصقه في العنصر <code>&lt;template&gt;</code> ضمن هذا المكون على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5643_16" style=""><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"websiteName"</span><span class="pun">],</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="com">&lt;!--Header and Navigation Bar--&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12 col-s-12 header-and-nav"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;header</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-4 col-s-4 header"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;h1&gt;</span><span class="pln">{{ websiteName }}</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;/header&gt;</span><span class="pln">
    </span><span class="tag">&lt;nav</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-8 col-s-8"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"nav-list"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">Root</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"portfolio.html"</span><span class="tag">&gt;</span><span class="pln">Home1</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"/portfolio.html"</span><span class="tag">&gt;</span><span class="pln">Home2</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://academy.hsoub.com/programming/"</span><span class="tag">&gt;</span><span class="pln">Lessons</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;li&gt;&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#project"</span><span class="tag">&gt;</span><span class="pln">Projects</span><span class="tag">&lt;/a&gt;&lt;/li&gt;</span><span class="pln">
      </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;/nav&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span></pre>

<p>
	ثم نستورد هذا المكوّن الذي أنشأناه للتو داخل المكوّن الجذر <code>App.vue</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5643_18" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HeaderComponent</span><span class="pln"> from </span><span class="str">"@/components/HeaderComponent.vue"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      websiteName</span><span class="pun">:</span><span class="pln"> </span><span class="str">"My Portfolio"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">HeaderComponent</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">HeaderComponent</span><span class="pun">&gt;&lt;/</span><span class="typ">HeaderComponent</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">style</span><span class="pun">&gt;</span><span class="pln">
</span><span class="lit">@import</span><span class="pln"> </span><span class="str">"./assets/style.css"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">style</span><span class="pun">&gt;</span></pre>

<p>
	استوردنا أيضًا في نهاية الكود أعلاه شيفرة CSS التي كتباناها في <a href="https://academy.hsoub.com/programming/html/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B9%D8%B1%D8%B6-%D8%A3%D8%B9%D9%85%D8%A7%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r2487/" rel="">المقال السابق</a> داخل المكوّن الجذر، كي تُطبَّق التنسيقات على جميع المكوّنات، حيث وضعنا ملف <a href="https://academy.hsoub.com/programming/css/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D9%84%D8%BA%D8%A9-css/" rel="">CSS</a> في مثالنا في المجلد <code>/src/assets/</code>. الآن إذا فتحنا رابط التطبيق في المتصفح فيجب أن نرى شريط التنقل الذي أضفناه.
</p>

<p>
	لدينا مشكلة جديدة لأن كل شيء مكتوب مباشرة في الشيفرة المصدرية، فإن أردنا تغيير شيء ما، فعلينا تغييره في كل مكان ورد فيه ضمن الشيفرة. لكن هدفنا هو جعل صفحة الويب ديناميكية ونسهل تغيير البيانات ولتحقيق ذلك، سنربط بعض معلومات موقعنا مع المتغيرات variables.
</p>

<p>
	على سبيل المثال لاحظ كيف كتبنا اسم الموقع وروابط التنقل في شريط التنقل من خلال إضافة الكود التالي للملف <code>HeaderComponent.vue</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1668_7" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      websiteName</span><span class="pun">:</span><span class="pln"> </span><span class="str">"My Portfolio"</span><span class="pln">
      navLinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Features"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pricing"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"FAQs"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"About"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;!--</span><span class="typ">Header</span><span class="pln"> and </span><span class="typ">Navigation</span><span class="pln"> </span><span class="typ">Bar</span><span class="pun">--&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"col-12 col-s-12 header-and-nav"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">header </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"col-4 col-s-4 header"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;{{</span><span class="pln"> websiteName </span><span class="pun">}}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">header</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">nav </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"col-8 col-s-8"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"nav-list"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li
          </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"nav-item"</span><span class="pln">
          v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"navLink in navLinks"</span><span class="pln">
          v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">key</span><span class="pun">=</span><span class="str">"navLink.id"</span><span class="pln">
        </span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"/portfolio.html"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">href</span><span class="pun">=</span><span class="str">"navLink.link"</span><span class="pun">&gt;{{</span><span class="pln">
            navLink</span><span class="pun">.</span><span class="pln">name
          </span><span class="pun">}}&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">nav</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span></pre>

<p>
	ولكن هل هذا هو الحل الأمثل؟ سيظهر اسم الموقع مرة أخرى في المكون <code>FooterComponent</code>، وبما أن المكوّنات المختلفة تُعرض منفصلة، فهذا يعني أن اسم الموقع سيُسترد من قاعدة البيانات مرتين، وذلك مضيعة للموارد. الحل البديل هو وضع اسم الموقع <code>websiteName</code> داخل المكوّن الجذر <code>App.vue</code> على شكل خاصية وتمريره إلى المكوّنات الأبناء التي تحتاج إلى استخدامه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1668_9" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HeaderComponent</span><span class="pln"> from </span><span class="str">"@/components/HeaderComponent.vue"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      websiteName</span><span class="pun">:</span><span class="pln"> </span><span class="str">"My Portfolio"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">HeaderComponent</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">HeaderComponent</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">websiteName</span><span class="pun">=</span><span class="str">"websiteName"</span><span class="pun">&gt;&lt;/</span><span class="typ">HeaderComponent</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">


</span><span class="pun">&lt;</span><span class="pln">style</span><span class="pun">&gt;</span><span class="pln">
</span><span class="lit">@import</span><span class="pln"> </span><span class="str">"./assets/style.css"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">style</span><span class="pun">&gt;</span></pre>

<p id="headercomponentvue">
	الآن نحصل على اسم الموقع في شيفرة <code>HeaderComponent.vue </code>كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3898_9" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      navLinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Features"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pricing"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"FAQs"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"About"</span><span class="pun">,</span><span class="pln"> link</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"websiteName"</span><span class="pun">],</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"col-12 col-s-12 header-and-nav"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">header </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"col-4 col-s-4 header"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;{{</span><span class="pln"> websiteName </span><span class="pun">}}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">header</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">nav </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"col-8 col-s-8"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"nav-list"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"nav-item"</span><span class="pln"> v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"navLink in navLinks"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">key</span><span class="pun">=</span><span class="str">"navLink.id"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">a </span><span class="pun">:</span><span class="pln">href</span><span class="pun">=</span><span class="str">"navLink.link"</span><span class="pun">&gt;{{</span><span class="pln"> navLink</span><span class="pun">.</span><span class="pln">name </span><span class="pun">}}&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">nav</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span></pre>

<h2>
	مكونات التطبيق
</h2>

<p>
	شرحنا في الفقرات السابقة طريقة تحقيق مكون الترويسة، ويمكن إنشاء باقي مكونات التطبيق وتخصيصها بنفس الطريقة التي أضفنا فيها الترويسة حيث سيتضمن تطبيقنا المكونات التالية:
</p>

<ul>
	<li>
		مكون الترويسة <code>HeaderComponent.vue</code>
	</li>
	<li>
		مكون التعريف <code>IntroComponent.vue</code>
	</li>
	<li>
		مكون النشرة البريدية <code>NewsletterComponent.vue</code>
	</li>
	<li>
		مكون المهارات <code>SkillsComponent.vue</code>
	</li>
	<li>
		مكون المشاريع <code>ProjectsComponent.vue</code>
	</li>
	<li>
		مكون التذييل <code>FooterComponent.vue</code>
	</li>
</ul>

<p>
	بعد إنشاء المكونات المطلوبة نعرضها في المكون الجذر <code>App.vue</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3898_7" style=""><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">HeaderComponent</span><span class="pln"> from </span><span class="str">'./components/HeaderComponent.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">IntroComponent</span><span class="pln"> from </span><span class="str">'./components/IntroComponent.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">NewsletterComponent</span><span class="pln"> from </span><span class="str">'./components/NewsletterComponent.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">SkillsComponent</span><span class="pln"> from </span><span class="str">'./components/SkillsComponent.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ProjectsComponent</span><span class="pln"> from </span><span class="str">'./components/ProjectsComponent.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">FooterComponent</span><span class="pln"> from </span><span class="str">'./components/FooterComponent.vue'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      websiteName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'My Portfolio'</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">HeaderComponent</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">IntroComponent</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">NewsletterComponent</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">SkillsComponent</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">ProjectsComponent</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">FooterComponent</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">HeaderComponent</span><span class="pln"> </span><span class="pun">:</span><span class="pln">websiteName</span><span class="pun">=</span><span class="str">"websiteName"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">IntroComponent</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">NewsletterComponent</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">SkillsComponent</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">ProjectsComponent</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">FooterComponent</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">style</span><span class="pun">&gt;</span><span class="pln">
</span><span class="lit">@import</span><span class="pln"> </span><span class="str">'./assets/style.css'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">style</span><span class="pun">&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: هنالك عدة طرق لإضافة الصور للتطبيق، وفي حالتنا سنضيف مجلد الصور <code>images</code> في المجلد <code>public</code> ضمن المشروع لسهولة الوصول لها مباشرة.
</p>

<p>
	عند الانتهاء من إضافة كافة الأقسام والصور والتنسيقات سيظهر تطبيقنا كما في الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="165535" href="https://academy.hsoub.com/uploads/monthly_2025_01/304503170_.png.d94096b87317548582bb0e5b76b87925.png" rel=""><img alt="نتيجة التطبيق" class="ipsImage ipsImage_thumbnailed" data-fileid="165535" data-unique="us5tgr4d3" src="https://academy.hsoub.com/uploads/monthly_2025_01/304503170_.png.d94096b87317548582bb0e5b76b87925.png"> </a>
</p>

<h2 id="-3">
	الخاتمة
</h2>

<p>
	تعلمنا في هذا المقال أهم خطوات تحويل موقع مطور بواسطة HTML و CSS إلى تطبيق Vue.js. حيث أنشأنا مشروع Vue جديد، ونقلنا التنسيقات والصور إلى المجلدات المناسبة في تطبيقنا، كما قسمنا صفحة HTML إلى مكونات متنوعة تمثل أجزاء الصفحة المختلفة وربطنا المكونات مع بعضها البعض في المكون الجذر. وتعرفنا كذلك على طريقة تحويل البيانات الثابتة إلى ديناميكية، حان دوركم لتجربة تحويل مواقعكم البسيطة إلى تطبيقات جافا سكريبت لجعلها أسهل في الصيانة وأكثر تنظيمًا.
</p>

<p>
	ترجمة، وبتصرّف للمقال <a href="https://www.ericsdevblog.com/posts/create-a-portfolio-website/" rel="external nofollow">Create a portfolio Website</a> لكاتبه Eric Hu.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-vuejs-r989/" rel="">مقدمة إلى Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-vuejs-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vue-cli-r1033/" rel="">إنشاء مشاريع Vue.js باستخدام Vue CLI</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%B9%D8%B1%D8%B6-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-vuejs-r1666/" rel="">عرض مكونات Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/" rel="">مدخل إلى التعامل مع المكونات في Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">2493</guid><pubDate>Thu, 16 Jan 2025 15:00:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x628;&#x633;&#x64A;&#x637; &#x645;&#x646; &#x62E;&#x644;&#x627;&#x644; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A8%D8%B3%D9%8A%D8%B7-%D9%85%D9%86-%D8%AE%D9%84%D8%A7%D9%84-vuejs-r2064/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/Vue.js.png.0723525f2fe745339c17ec10000676df.png" /></p>
<p>
	في هذا الفيديو سننشئ تطبيق بسيط لإدارة المهام من خلال إطار العمل Vue.js بإصداره الثالث.
</p>

<p>
	من خلال هذا التطبيق سنشرح الأمور الأساسية في إطار Vue.js وكيفية إنشاء مشروع وقائمة لإدارة المهام.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" src="https://academy.hsoub.com/applications/core/interface/index.html" title="إنشاء تطبيق بسيط من خلال Vue.js" width="1072" data-embed-src="https://www.youtube.com/embed/CHGZcCMCXO4"></iframe>
</p>

<p>
	إذا أردت التعرف أكثر على جافاسكربت، فننصحك بالانضمام إلى <a href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">دورة تطوير التطبيقات باستخدام لغة JavaScript</a>، ولا تنسَ الاستعانة خلال رحلة تعلمك وعملك بتوثيقات <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">موسوعة حسوب</a> المجانية. وإذا أردت متابعة المعلومات البرمجية العلمية مكتوبة فيمكنك الاطلاع على <a href="https://academy.hsoub.com/programming/" rel="">قسم البرمجة في أكاديمية حسوب</a>، كما يمكنك متابعة جديد الفيديوهات التقنية المتاحة على <a href="https://www.youtube.com/@HsoubAcademy" rel="external nofollow">يوتيوب أكاديمية حسوب</a> مجانًا.
</p>
]]></description><guid isPermaLink="false">2064</guid><pubDate>Tue, 20 Sep 2022 15:00:00 +0000</pubDate></item><item><title>&#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x639;&#x646;&#x627;&#x635;&#x631; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62E;&#x627;&#x635;&#x64A;&#x627;&#x62A; ref &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-ref-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1685/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/630743b5ee618_----ref----Vue---.png.15f59a5acd3b2e5542f0773711d87d78.png" /></p>

<p>
	اقتربنا من نهاية سلسلة إطار العمل Vue.js، إذ يجب الآن تعلّم كيفية الوصول إلى العناصر وإدارتها وتعديلها مثل إدارة التركيز أو كيف يمكننا تحسين الشمولية أو إمكانية الوصول لمستخدمي لوحة المفاتيح في تطبيقنا، إذ سنتعرّف على كيفية استخدام خاصيات <code>ref</code> في إطار العمل Vue للتعامل مع إدارة التركيز التي تُعَدّ ميزةً متقدمةً تتيح الوصول المباشر إلى عقد DOM الأساسية أسفل نموذج DOM الافتراضي أو الوصول المباشر من أحد المكوّنات إلى <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%AC%D8%B1%D9%8A%D8%A9-%D9%84%D9%80-dom-r646/" rel="">بنية DOM</a> الداخلية الخاصة بمكوِّن ابن، كما سنوفِّر مزيدًا من الموارد لتعلّم إطار عمل Vue للاستزادة منها.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكوّنات Vue بوصفها مجموعةً من <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r796/" rel="">كائنات جافاسكربت</a> التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع بنية DOM الأساسية، كما ستحتاج إلى طرفية مثبَّتٌ عليها node و <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">npm</a> لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكونات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية التعامل مع إدارة التركيز باستخدام خاصيات <code>ref</code> في <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">إطار العمل Vue</a>.
	</li>
</ul>
<h2>
	مشكلة إدارة التركيز
</h2>

<p>
	لدينا وظيفة تعديل تعمل بصورة جيدة في تطبيقنا، إلا أننا لم نقدّم تجربةً رائعةً للمستخدِمين الذين لا يستخدِمون الفأرة، فإذا فعّل المستخدِم زر "التعديل Edit"، فإننا نزيل هذا الزر من نموذج <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a> دون نقل تركيز المستخدِم إلى أيّ مكان آخر، لذلك سيختفي التركيز، ويمكن أن يكون هذا مربكًا لمستخدِمي لوحة المفاتيح والمستخدِمين غير المبصرين.
</p>

<p>
	طبقّ ما يلي لفهم ما يحدث حاليًا:
</p>

<ol>
<li>
		أعد تحميل صفحتك ثم اضغط على مفتاح <code>Tab</code>، ويجب أن تشاهد إطارًا يمثل التركيز حول حقل الإدخال لإضافة عناصر مهام جديدة.
	</li>
	<li>
		اضغط على مفتاح <code>Tab</code> مرةً أخرى، ويجب أن ينتقل التركيز إلى زر "الإضافة Add".
	</li>
	<li>
		اضغط على مفتاح <code>Tab</code> مرةً أخرى وسينتقل التركيز إلى مربع الاختيار الأول، ثم يجب أن ينتقل التركيز إلى زر "التعديل Edit" الأول.
	</li>
	<li>
		فعّل زر "التعديل Edit" بالضغط على مفتاح <code>Enter</code>، وبالتالي سيُستبدَل مربع الاختيار بمكوِّن التعديل، ولكن سيختفي إطار التركيز.
	</li>
</ol>
<p>
	يمكن أن يكون هذا السلوك مربكًا، ويختلف ما يحدث عند الضغط على مفتاح <code>Tab</code> مرةً أخرى تبعًا للمتصفح الذي تستخدِمه، فإذا حفظت التعديل أو ألغيته، فسيختفي التركيز مرةً أخرى عندما تعود إلى العرض الذي لا يتضمن تعديلًا.
</p>

<p>
	يمكن منح المستخدِمين تجربةً أفضل من خلال إضافة شيفرة برمجية للتحكّم في التركيز بحيث يُضبَط على حقل التعديل عند عرض نموذج التعديل، وسنعيد وضع التركيز على زر "التعديل Edit" عندما يلغي المستخدِم تعديله أو يحفظه، وبالتالي يجب فهم المزيد حول كيفية عمل إطار Vue داخليًا بهدف ضبط التركيز.
</p>

<h2>
	نموذج DOM الافتراضي وخاصيات ref
</h2>

<p>
	يستخدِم إطار العمل Vue مثل بعض أطر العمل الأخرى نموذج DOM الافتراضي Virtual DOM -أو VDOM اختصارًا- لإدارة العناصر، وهذا يعني أنّ إطار Vue يحتفظ في الذاكرة بتمثيلٍ لجميع العقد في تطبيقنا، كما يمكن إجراء أيّ تحديثات أولًا على العقد الموجودة في الذاكرة، ثم تُزامَن جميع التغييرات التي يجب إجراؤها على العقد الفعلية على الصفحة دفعةً واحدةً.
</p>

<p>
	بما أن قراءة وكتابة عقد DOM الفعلية تكون مستهلكة أكثر للأداء من العقد الافتراضية في أغلب الأحيان، فسيؤدي ذلك إلى أداء أفضل، ولكنه يعني أيضًا أنه لا يجب تعديل عناصر HTML مباشرةً من خلال واجهات برمجة تطبيقات المتصفح الأصيلة Native مثل <code>Document.getElementById</code> عند استخدام أطر العمل، لأنه سيؤدي إلى عدم مزامنة نموذج VDOM و DOM الفعلي، فإذا كنت بحاجة إلى الوصول إلى عقد DOM الأساسية مثل حالة ضبط التركيز، فيمكنك استخدام خاصيات ref في إطار Vue، كما يمكنك بالنسبة لمكّونات Vue المخصَّصة استخدام خاصيات ref للوصول مباشرةً إلى البنية الداخلية لمكوّن ابن، ولكن يجب تطبيق ذلك بحذر لأنه قد يصعّب فهم الشيفرة البرمجية.
</p>

<p>
	يمكن استخدام خاصيات ref في أحد المكونات من خلال إضافة السمة <code>ref</code> إلى العنصر الذي تريد الوصول إليه مع معرِّف من نوع سلسلة نصية لقيمة هذه السمة، إذ يجب أن تكون السمة <code>ref</code> فريدةً في المكون، ولا ينبغي أن يكون هناك عنصران يصيّّران في الوقت نفسه ولهما السمة <code>ref</code> نفسها.
</p>

<h2>
	إضافة الخاصية ref إلى التطبيق
</h2>

<p>
	لنضِف السمة <code>ref</code> إلى زر "التعديل Edit" في المكوِّن <code>ToDoItem.vue</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_13" style="">
<span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">"editButton"</span><span class="pln"> </span><span class="lit">@click</span><span class="pun">=</span><span class="str">"toggleToItemEditForm"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="typ">Edit</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	يمكن الوصول إلى القيمة المرتبطة بالسمة <code>ref</code> من خلال استخدام الخاصية <code>‎$refs</code> المتوفِّرة في نسخة المكوِّن، لذا أضِف التابع <code>console.log()‎</code> إلى التابع <code>toggleToItemEditForm()‎</code> كما يلي لمعرفة قيمة السمة <code>ref</code> عند النقر على زر "التعديل Edit":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_17" style="">
<span class="pln">toggleToItemEditForm</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">editButton</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isEditing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا فعّلتَ زر "التعديل Edit" الآن، فيُفترَض أن ترى <a href="https://wiki.hsoub.com/HTML/button" rel="external">عنصر الزر &lt;button&gt;</a> في HTML مشارًا إليه في طرفيتك.
</p>

<h2>
	التابع ‎$nextTick()‎ في إطار العمل Vue
</h2>

<p>
	يجب الآن التركيز على زر "التعديل Edit" عندما يحفظ المستخدِم التعديل أو يلغيه، لذلك يجب التعامل مع التركيز باستخدام التابعَين <code>itemEdited()‎</code> و <code>editCancelled()‎</code> في المكوِّن <code>ToDoItem</code>.
</p>

<p>
	أنشئ تابعًا جديدًا لا يأخذ أيّ وسيط بالاسم <code>focusOnEditButton()‎</code> وأسند السمة <code>ref</code> إلى متغير، ثم استدعِ التابع <code>focus()‎</code> على هذه السمة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_20" style="">
<span class="pln">focusOnEditButton</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> editButtonRef </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">editButton</span><span class="pun">;</span><span class="pln">
  editButtonRef</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضِف بعد ذلك استدعاءً إلى <code>this.focusOnEditButton()‎</code> في نهاية التابعَين <code>itemEdited()‎</code> و <code>editCancelled()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_22" style="">
<span class="pln">itemEdited</span><span class="pun">(</span><span class="pln">newItemName</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">"item-edited"</span><span class="pun">,</span><span class="pln"> newItemName</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isEditing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">focusOnEditButton</span><span class="pun">();</span><span class="pln">
</span><span class="pun">},</span><span class="pln">
editCancelled</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isEditing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">focusOnEditButton</span><span class="pun">();</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	جرّب تعديل عنصر مهمة ثم حفظ التعديل أو إلغاءه باستخدام لوحة المفاتيح وستلاحظ عدم ضبط التركيز، لذلك لا تزال لدينا مشكلة ويجب حلها، فإذا فتحتَ طرفيتك، فسترى ظهور الخطأ الذي يبدو غريبًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_24" style="">
<span class="str">"can't access property "</span><span class="pln">focus</span><span class="str">", editButtonRef is undefined"</span><span class="pln"> </span></pre>

<p>
	إذ جرى تعريف المرجع ref الخاص بالزر عند تفعيل زر "التعديل Edit"، ولكنه ليس كذلك الآن، وتذكّر أننا لم نعُد نصيّر قسم المكوّن الذي يحتوي على زر "التعديل Edit" عند تغيير قيمة <code>isEditing</code> إلى <code>true</code>، وبالتالي لا يوجد عنصر لربط المرجع به، لذلك يصبح غير مُعرَّف.
</p>

<p>
	لكننا نضبط قيمة <code>isEditing</code> على <code>false</code> قبل محاولة الوصول إلى المرجع، فهل يجب أن يعرض الموجّه <code>v-if</code> الزر الآن؟ حسنًا، يجب الآن استخدام نموذج DOM الافتراضي، وبما أنّ Vue يحاول تحسين وإصلاح التغييرات، فلن يحدّث نموذج DOM مباشرةً عند ضبط قيمة <code>isEditing</code> على <code>false</code>، لذلك فإنّ زر "التعديل Edit" لم يُصيَّر بعد عند استدعاء التابع <code>focusOnEdit()‎</code>، لذا يجب الانتظار حتى يجتاز إطار Vue دورة تحديث نموذج DOM التالية، إذ تحتوي مكونات Vue على تابع خاص يسمَّى <code>‎$nextTick()‎</code> الذي يقبل دالة رد نداء Callback Function تنفّذ بعد تحديث نموذج DOM.
</p>

<p>
	يمكننا تغليف جسم الدالة الحالية ضمن استدعاء الدالة <code>‎$nextTick()‎</code> لأنه يجب استدعاء التابع <code>focusOnEditButton()‎</code> بعد تحديث نموذج DOM.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_26" style="">
<span class="pln">focusOnEditButton</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$nextTick</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> editButtonRef </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">editButton</span><span class="pun">;</span><span class="pln">
    editButtonRef</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا فعّلتَ زر "التعديل Edit" ثم ألغيت التغييرات أو حفظتها باستخدام لوحة المفاتيح، فيجب إعادة التركيز إلى زر "التعديل Edit".
</p>

<h2>
	توابع دورة حياة إطار عمل Vue
</h2>

<p>
	تتمثَّل الخطوة التالية في نقل التركيز إلى <a href="https://wiki.hsoub.com/HTML/input" rel="external">العنصر &lt;input&gt;</a> في نموذج التعديل عند النقر على زر "التعديل Edit"، ولكن لا يمكننا فقط وضع التركيز ضمن معالِج حدث النقر على زر "التعديل Edit" لأن نموذج التعديل موجود في مكوِّن مختلف عن هذا الزر، لذا يمكننا إزالة المكوِّن <code>ToDoItemEditForm</code> ونعيد تحميله كلما نقرنا على زر "التعديل Edit" للتعامل مع هذا الأمر.
</p>

<p>
	تجتاز مكوّنات Vue سلسلةً من الأحداث تُعرَف باسم دورة الحياة Lifecycle التي تمتد من قبل إنشاء العناصر وإضافتها إلى نموذج VDOM أي تثبيتها، حتى إزالتها من نموذج VDOM أي تدميرها.
</p>

<p>
	يتيح إطار عمل Vue تشغيل توابع في مراحل مختلفة من دورة الحياة باستخدام توابع دورة الحياة Lifecycle Methods المفيدة لأشياء متعددة مثل جلب البيانات، إذ يمكن أن تحتاج إلى الحصول على بياناتك قبل تصيير مكوِّنك أو بعد تغيير الخاصيات، وتمثِّل القائمة التالية قائمة توابع دورة الحياة حسب الترتيب الذي تُطلَق فيه:
</p>

<ol>
<li>
		<code>beforeCreate()‎</code>: يُشغَّل قبل إنشاء نسخة من مكوِّنك، وليست البيانات والأحداث متاحةً بعد.
	</li>
	<li>
		<code>created()‎</code>: يُشغَّل بعد تهيئة مكوِّنك ولكن قبل إضافته إلى نموذج VDOM، ويُعَدّ المكان الذي يحدث فيه جلب البيانات.
	</li>
	<li>
		<code>beforeMount()‎</code>: يُشغَّل بعد تصريف Compile قالبك وقبل تصيير مكوِّنك إلى نموذج DOM الفعلي.
	</li>
	<li>
		<code>mounted()‎</code>: يُشغَّل بعد تثبيت مكوِّنك في نموذج DOM، ويمكن هنا الوصول إلى المراجع <code>refs</code>.
	</li>
	<li>
		<code>beforeUpdate()‎</code>: يُشغَّل كلما تغيرت البيانات في مكوِّنك وقبل تصيير التغييرات إلى نموذج DOM.
	</li>
	<li>
		<code>updated()‎</code>: يُشغَّل كلما تغيرت البيانات في مكوِّنك وبعد تصيير التغييرات إلى نموذج DOM.
	</li>
	<li>
		<code>beforeDestroy()‎</code>: يُشغَّل قبل إزالة أحد المكوّنات من نموذج DOM.
	</li>
	<li>
		<code>destroyed()‎</code>: يُشغَّل بعد إزالة أحد المكونات من نموذج DOM.
	</li>
	<li>
		<code>activated()‎</code>: يُستخدَم فقط في المكونات المغلَّفة بوسم <code>keep-alive</code> الخاص، ويعمل بعد تفعيل المكون.
	</li>
	<li>
		<code>deactivated()‎</code>: يُستخدَم فقط في المكونات المغلَّفة بوسم <code>keep-alive</code> الخاص، ويعمل بعد إلغاء تفعيل المكون.
	</li>
</ol>
<p>
	<strong>ملاحظة</strong>: يمكنك الاطلاع على <a href="https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram" rel="external nofollow">مخطط رائع يشرح وقت حدوث هذه التوابع في توثيق Vue</a>.
</p>

<p>
	لنستخدِم الآن تابعًا من توابع دورة الحياة لبدء التركيز عند تثبيت المكوِّن <code>ToDoItemEditForm</code>، لذا أضِف <code>ref="labelInput"‎</code> إلى العنصر <code>&lt;input&gt;</code> في المكوِّن <code>ToDoItemEditForm.vue</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_29" style="">
<span class="pun">&lt;</span><span class="pln">input </span><span class="pun">:</span><span class="pln">id</span><span class="pun">=</span><span class="str">"id"</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">"labelInput"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> autocomplete</span><span class="pun">=</span><span class="str">"off"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">.</span><span class="pln">lazy</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">=</span><span class="str">"newName"</span><span class="pln"> </span><span class="pun">/&gt;</span></pre>

<p>
	أضف بعد ذلك الخاصية <code>mounted()‎</code> إلى كائن المكوِّن مباشرةً، إذ لا ينبغي وضعها ضمن الخاصية <code>methods</code>، وإنما يجب وضعها في مستوى تسلسل <code>props</code> و <code>data()‎</code> و <code>methods</code> الهرمي نفسه، فتوابع دورة الحياة هي توابع خاصة بمفردها ولا توضَع مع التوابع التي يعرّفها المستخدِم ولا تأخذ أيّ مدخلات، ولاحظ أنه لا يمكنك استخدام <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D8%B8%D8%B1%D8%A9-%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-arrow-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r880/" rel="">دالة سهمية</a> هنا لأننا نحتاج الوصول إلى <code>this</code> للوصول إلى المرجع <code>labelInput</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_31" style="">
<span class="pln">mounted</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

</span><span class="pun">}</span></pre>

<p>
	أسنِد المرجع <code>labelInput</code> إلى متغير ضمن التابع <code>mounted()‎</code>، ثم استدعِ الدالة <code>focus()‎</code> الخاصة بالمرجع، ولست مضطرًا إلى استخدام <code>‎$nextTick</code> هنا لأن المكوِّن مُضاف بالفعل إلى نموذج DOM عند استدعاء التابع <code>mounted()‎</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_33" style="">
<span class="pln">mounted</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">const</span><span class="pln"> labelInputRef </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">labelInput</span><span class="pun">;</span><span class="pln">
   labelInputRef</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا فعّلتَ زر "التعديل Edit" الآن باستخدام لوحة المفاتيح، فيجب أن ينتقل التركيز إلى تعديل العنصر <code>&lt;input&gt;</code> مباشرةً.
</p>

<h2>
	التعامل مع التركيز عند حذف عناصر المهام
</h2>

<p>
	إذا نقرت على زر "التعديل Edit"، فسيكون نقل التركيز إلى مربع نص تعديل الاسم والعودة إلى زر "التعديل Edit" عند الإلغاء أو الحفظ من نموذج التعديل أمرًا منطقيًا، لكن ليس لدينا موقع واضح لنقل التركيز إليه عند حذف عنصر، ونحتاج إلى طريقة لتزويد مستخدِمي التقنيات المساعدة بالمعلومات التي تؤكّد حذف عنصر.
</p>

<p>
	نتعقّب فعليًا عدد العناصر في عنوان القائمة أي <a href="https://wiki.hsoub.com/HTML/h1-h6" rel="external">العنصر &lt;h2&gt;</a> في المكوِّن <code>App.vue</code>، وهو مرتبط بقائمة عناصر المهام، مما يجعله مكانًا مناسبًا لنقل التركيز إليه عند حذف عقدة.
</p>

<p>
	يجب أولًا إضافة مرجع إلى عنوان القائمة ثم إضافة السمة <code>tabindex="-1"‎</code> إليه، مما يجعل العنصر قابلًا للتركيز برمجيًا، أي يمكن التركيز عليه باستخدام شيفرة جافاسكربت إن لم يكن كذلك افتراضيًا.
</p>

<p>
	عدِّل العنصر <code>&lt;h2&gt;</code> في المكوِّن <code>App.vue</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2346_37" style="">
<span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list-summary"</span><span class="pln"> </span><span class="atn">ref</span><span class="pun">=</span><span class="atv">"listSummary"</span><span class="pln"> </span><span class="atn">tabindex</span><span class="pun">=</span><span class="atv">"-1"</span><span class="tag">&gt;</span><span class="pln">{{listSummary}}</span><span class="tag">&lt;/h2&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: تُعَدّ السمة <code>tabindex</code> أداةً قويةً للتعامل مع بعض مشاكل الشمولية Accessibility، ولكن يجب استخدامها بحذر، إذ يمكن أن يتسبّب الإفراط في استخدام السمة <code>tabindex="-1"‎</code> في حدوث مشاكل لجميع أنواع المستخدِمين، لذلك استخدمها فقط في المكان الذي تحتاجها فيه فقط، كما يجب عدم استخدام السمة <code>tabindex &gt; = 0</code>، إذ يمكن أن تسبب مشاكل للمستخدِمين لأنها يمكن أن تؤدي إلى عدم التطابق مع ترتيب انتقال التركيز باستخدام مفتاح <code>Tab</code> في نموذج DOM، و / أو إضافة عناصر غير تفاعلية إلى هذا الترتيب، كما يكون ذلك مربكًا للمستخدِمين خاصةً أولئك الذين يستخدِمون قارئات الشاشة والتقنيات المساعدة الأخرى.
</p>

<p>
	أصبح لدينا مرجع <code>ref</code> وأعلَمنا المتصفحات أنه يمكننا التركيز برمجيًا على العنصر <code>&lt;h2&gt;</code>، ويجب الآن التركيز عليه.
</p>

<p>
	استخدم المرجع <code>listSummary</code> في نهاية التابع <code>deleteToDo()‎</code> لضبط التركيز على العنصر <code>&lt;h2&gt;</code>، وبما أنّ العنصر <code>&lt;h2&gt;</code> يُصيَّر دائمًا في التطبيق، فليس هناك داع للقلق بشأن استخدام <code>‎$nextTick</code> مع توابع دورة الحياة للتعامل مع التركيز عليه.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2346_39" style="">
<span class="pln">deleteToDo</span><span class="pun">(</span><span class="pln">toDoId</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> itemIndex </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">findIndex</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> toDoId</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="pln">itemIndex</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">listSummary</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا حذفتَ عنصرًا من قائمتك الآن، فيجب نقل التركيز إلى عنوان القائمة الذي يجب أن يوفِّر تجربة تركيز جيدة لجميع المستخِدمين.
</p>

<p>
	تهانينا، انتهينا الآن من إنشاء تطبيقنا باستخدام إطار العمل Vue، وسنتعرّف الآن على بعض الموارد الإضافية لتعلم إطار العمل Vue.
</p>

<p>
	<strong>ملاحظة</strong>: إذا كنت بحاجة إلى التحقق من شيفرتك مقابل نسختنا، فيمكنك العثور على نسخة نهائية من شيفرة تطبيق Vue في مستودع todo-vue، كما يمكنك الحصول على <a href="https://mdn.github.io/todo-vue/dist/" rel="external nofollow">إصدار حي مباشر قيد التشغيل</a>.
</p>

<h2>
	موارد إضافية لتعلم إطار العمل Vue
</h2>

<p>
	سنختتم الآن هذا القسم من <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%AA%D8%B7%D9%88%D9%8A%D8%B1%20%D8%A7%D9%84%D9%88%D9%8A%D8%A8/" rel="">سلسلة تعلم تطوير الويب</a> الذي يشمل إطار العمل Vue من خلال إعطائك قائمة بالموارد التي يمكنك استخدامها في مسيرة تعلمك، بالإضافة إلى بعض النصائح المفيدة الأخرى.
</p>

<p>
	من الموارد التي يجب أن تتطلع عليها لمعرفة المزيد عن إطار العمل Vue:
</p>

<ul>
<li>
		<a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">كتاب أساسيات إطار العمل Vue .js</a> من أكاديمية حسوب الذي يشرح مفهوم إطار العمل Vue.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/" rel="">مقالات عن Vue</a>: مقالات عربية من أكاديمية حسوب عن إطار العمل Vue.js.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/" rel="">قسم الأسئلة البرمجية</a>: إن أردت الحصول على مساعدة من مبرمجين عرب.
	</li>
	<li>
		<a href="https://io.hsoub.com/programming" rel="external">منتدى البرمجة العربية</a>: المنتدى البرمجي العربي للحصول على مساعدة في إطار العمل Vue أو أي شيء متعلق بالبرمجة.
	</li>
	<li>
		<a href="https://vuejs.org/" rel="external nofollow">توثيق Vue</a>: يحتوي موقع Vue الرسمي على توثيق شامل بما في ذلك الأمثلة والكتب والموارد المرجعية.
	</li>
	<li>
		<a href="https://github.com/vuejs/vue" rel="external nofollow">مستودع Vue Github</a>: شيفرة Vue البرمجية نفسها حيث يمكنك فيه الإبلاغ عن المشاكل والمساهمة مباشرةً في شيفرة Vue الأساسية، كما يمكن أن تساعدك دراسة شيفرة Vue البرمجية على فهم كيفية عمل إطار العمل وكتابة شيفرة أفضل.
	</li>
	<li>
		<a href="https://cli.vuejs.org/" rel="external nofollow">توثيق Vue CLI</a>: يحتوي على معلومات حول تخصيص وتوسيع الخرج الذي تنشئه باستخدام واجهة سطر الأوامر CLI.
	</li>
	<li>
		<a href="https://nuxtjs.org/" rel="external nofollow">NuxtJS</a>: هو إطار عمل من Vue من طرف الخادم مع بعض الآراء المعمارية التي يمكن أن تكون مفيدةً لإنشاء تطبيقات قابلة للصيانة، حتى إن لم تستخدِم أيًا من ميزات التصيير من طرف الخادم Server Side Rendering التي يوفرها، كما يوفِّر توثيقًا مفصلًا حول استخدام NuxtJS.
	</li>
</ul>
<h2>
	بناء ونشر تطبيق Vue
</h2>

<p>
	توفِّر واجهة CLI في Vue أدوات لإعداد تطبيقنا للنشر على الويب كما يلي:
</p>

<ul>
<li>
		إذا كان خادمك المحلي لا يزال قيد التشغيل، فيمكن إنهاؤه بالضغط على الاختصار <code>Ctrl + C</code> في الطرفية.
	</li>
	<li>
		شغّل الأمر <code>npm run build</code> أو الأمر <code>yarn build</code> في الطرفية.
	</li>
</ul>
<p>
	مما يؤدي إلى إنشاء مجلد <code>dist</code> جديد يحتوي على جميع ملفات الإنتاج الجاهزة. يمكنك نشر موقعك على الويب من خلال نسخ محتويات هذا المجلد إلى بيئة استضافتك.
</p>

<p>
	<strong>ملاحظة</strong>: يتضمن توثيق Vue CLI <a href="https://cli.vuejs.org/guide/deployment.html#platform-guides" rel="external nofollow">دليلًا حول كيفية نشر تطبيقك</a> على العديد من أنظمة الاستضافة الشائعة.
</p>

<h2>
	إصدار Vue 3
</h2>

<p>
	يُعَدّ Vue 3 إصدارًا رئيسيًا من Vue مع الكثير من التغييرات الرئيسية، وقد دخل هذا الإصدار مرحلة الإصدار التجريبي النشط في شهر 4 من عام 2020، كما يُعَدّ أكبر تغيير فيه هو واجهة Composition <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> الجديدة التي تعمل بوصفها بديلًا <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">لواجهة <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> الحالية القائمة على الخاصيات، وتُستخدَم دالة <code>setup()‎</code> واحدة مع المكوِّن في هذه الواجهة الجديدة، حيث يتوفر فقط ما تعيده من هذه الدالة في عناصر القوالب <code>&lt;template&gt;</code>. كما يجب أن تكون واضحًا بشأن الخاصيات التفاعلية عند استخدام هذه الواجهة، إذ يعالج إطار العمل Vue ذلك نيابةً عنك باستخدام الواجهة Options <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>، مما يجعل واجهة برمجة التطبيقات الجديدة حالة استخدام أكثر تقدمًا.
</p>

<p>
	كما توجد بعض التغييرات الأخرى، بما في ذلك التغيير في كيفية تهيئة التطبيقات في Vue، ويمكنك الاطلاع عليها في <a href="https://vuejs.org/" rel="external nofollow">توثيق Vue.js الرسمي</a>.
</p>

<p>
	ترجمة -وبتصرّف- للمقالَين <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management" rel="external nofollow">Focus management with Vue refs</a> و<a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources" rel="external nofollow">Vue resources</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%B9%D8%B1%D8%B6-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1684/" rel="">العرض الشرطي في إطار العمل Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A9-computed-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1683/" rel="">إضافة تنسيق للمكونات واستعمال الخاصية computed في تطبيق Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-dom-r990/" rel="">استخدام Vue.js للتعامل مع DOM</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1685</guid><pubDate>Thu, 25 Aug 2022 10:02:44 +0000</pubDate></item><item><title>&#x627;&#x644;&#x639;&#x631;&#x636; &#x627;&#x644;&#x634;&#x631;&#x637;&#x64A; &#x641;&#x64A; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%B9%D8%B1%D8%B6-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A-%D9%81%D9%8A-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1684/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/63073e7bb0b88_-----Vue.png.49ba08525ba0015e5cd346d14f169a6d.png" /></p>

<p>
	حان الوقت الآن لإضافة الوظائف التي تمكّننا من تعديل عناصر المهام الموجودة مسبقًا، لذلك سنستفيد من إمكانات التصيير الشرطي Conditional Rendering في <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">إطار العمل Vue</a> مثل <code>v-if</code> و <code>v-else</code> للسماح بالتبديل بين عرض عناصر المهام الموجودة مسبقًا وعرض التعديل حيث يمكنك تعديل عناوين أو تسميات labels عناصر المهام، كما سنتعرّف على إضافة وظيفة لحذف عناصر المهام.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكونات Vue بوصفها مجموعةً من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%AC%D8%B1%D9%8A%D8%A9-%D9%84%D9%80-dom-r646/" rel="">بنية DOM</a> الأساسية، كما ستحتاج إلى طرفية مثبَّت عليها node و <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">npm</a> لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكوّنات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية استخدام التصيير الشرطي في إطار العمل Vue.
	</li>
</ul>
<h2>
	إنشاء مكون التعديل
</h2>

<p>
	يمكننا البدء بإنشاء مكوِّن منفصل للتعامل مع وظيفة التعديل، لذا أنشئ ملفًا جديدًا بالاسم ToDoItemEditForm.vue في المجلد components وانسخ الشيفرة التالية في هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_14" style="">
<span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">form </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"stack-small"</span><span class="pln"> </span><span class="lit">@submit</span><span class="pun">.</span><span class="pln">prevent</span><span class="pun">=</span><span class="str">"onSubmit"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">label </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"edit-label"</span><span class="pun">&gt;</span><span class="typ">Edit</span><span class="pln"> </span><span class="typ">Name</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="str">"{{label}}"</span><span class="pun">&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">:</span><span class="pln">id</span><span class="pun">=</span><span class="str">"id"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln"> autocomplete</span><span class="pun">=</span><span class="str">"off"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">.</span><span class="pln">lazy</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">=</span><span class="str">"newLabel"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn-group"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn"</span><span class="pln"> </span><span class="lit">@click</span><span class="pun">=</span><span class="str">"onCancel"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Cancel</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="pln">editing </span><span class="pun">{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn btn__primary"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Save</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;</span><span class="pln">edit </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    label</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
      required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
      required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      newLabel</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">newLabel </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">newLabel </span><span class="pun">!==</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">"item-edited"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">newLabel</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    onCancel</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">"edit-cancelled"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">style scoped</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">edit</span><span class="pun">-</span><span class="pln">label </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="lit">0b0c0c</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
input </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.4rem</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  min</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4.4rem</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.4rem</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid </span><span class="pun">#</span><span class="lit">565656</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
form </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  flex</span><span class="pun">-</span><span class="pln">direction</span><span class="pun">:</span><span class="pln"> row</span><span class="pun">;</span><span class="pln">
  flex</span><span class="pun">-</span><span class="pln">wrap</span><span class="pun">:</span><span class="pln"> wrap</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
form </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  flex</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">style</span><span class="pun">&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: تصفَّح الشيفرة السابقة ثم اقرأ الوصف التالي للتأكد من فهمك لكل شيء يطبّقه المكوِّن قبل المضي قدمًا، إذ تُعَدّ هذه الطريقة مفيدةً للمساعدة في تعزيز ما تعلمته حتى الآن.
</p>

<p>
	تضبط الشيفرة السابقة أساس وظيفة التعديل، إذ ننشئ نموذجًا يحتوي على حقل إدخال <code><a href="https://wiki.hsoub.com/HTML/input" rel="external">&lt;input&gt;</a></code> لتعديل اسم المهمة، ويوجد زر "حفظ Save" وزر "إلغاء Cancel":
</p>

<ul>
<li>
		إذا نقرت على زر "الحفظ Save"، فسيصدِر المكوِّن التسمية الجديدة باستخدام الحدث <code>item-edited</code>.
	</li>
	<li>
		إذا نقرت على زر "الإلغاء Cancel"، فسيشير المكوِّن إلى ذلك عن طريق إصدار الحدث <code>edit-cancelled</code>.
	</li>
</ul>
<h2>
	تعديل المكون ToDoItem
</h2>

<p>
	يجب إجراء بعض التعديلات على المكوِّن <code>ToDoItem</code> قبل التمكّن من إضافة المكوِّن <code>ToDoItemEditForm</code> إلى تطبيقنا، إذ يجب إضافة متغير لتعقّب تعديل العنصر، وزر لتبديل هذا المتغير، كما سنضيف زر حذف <code>Delete</code> لأن الحذف وثيق الصلة بالتعديل، أي عدّل قالب المكون <code>ToDoItem</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_12" style="">
<span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"stack-small"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"custom-checkbox"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">id</span><span class="pun">=</span><span class="str">"id"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">checked</span><span class="pun">=</span><span class="str">"isDone"</span><span class="pln">
             </span><span class="lit">@change</span><span class="pun">=</span><span class="str">"$emit('checkbox-changed')"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">label </span><span class="pun">:</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"id"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"checkbox-label"</span><span class="pun">&gt;{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn-group"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn"</span><span class="pln">  </span><span class="lit">@click</span><span class="pun">=</span><span class="str">"toggleToItemEditForm"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Edit</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn btn__danger"</span><span class="pln"> </span><span class="lit">@click</span><span class="pun">=</span><span class="str">"deleteToDo"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Delete</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"visually-hidden"</span><span class="pun">&gt;{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span></pre>

<p>
	أضفنا عنصر <code><a href="https://wiki.hsoub.com/HTML/div" rel="external">&lt;div&gt;</a></code> الذي يغلّف القالب بأكمله لأغراض التنسيق، وأضفنا زرَّي "تعديل Edit" و "حذف Delete":
</p>

<ul>
<li>
		إذا نقرت على زر "التعديل Edit"، فسيبدّل عرض مكوِّن <code>ToDoItemEditForm</code> لنتمكن من استخدامه لتعديل عنصر المهام باستخدام دالة معالج حدث تسمى <code>toggleToItemEditForm()‎</code> التي ستضبط الراية <code>isEditing</code> على القيمة <code>true</code>، لكن يجب أولًا تعريف هذه الدالة ضمن الخاصية <code>data()‎</code>.
	</li>
	<li>
		إذا نقرت على زر "الحذف Delete"، فسيُحذَف عنصر المهام باستخدام دالة معالج حدث تسمى <code>deleteToDo()‎</code>، إذ سنصدِر في هذا المعالج الحدث <code>item-deleted</code> إلى المكوِّن الأب، مما يؤدي إلى تحديث القائمة.
	</li>
</ul>
<p>
	لنعرِّف الآن معالجات النقرات والراية <code>isEditing</code>، لذا أضِف الخاصية <code>isEditing</code> بعد الخاصية <code>isDone</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_16" style="">
<span class="pln">data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    isDone</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">done</span><span class="pun">,</span><span class="pln">
    isEditing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضِف الآن توابعك ضمن الخاصية <code>methods</code> وبعد الخاصية <code>data()‎</code> مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_18" style="">
<span class="pln">methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    deleteToDo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'item-deleted'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    toggleToItemEditForm</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isEditing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span></pre>

<h2>
	عرض المكونات شرطيا باستخدام v-if و v-else
</h2>

<p>
	لدينا الآن الراية <code>isEditing</code> التي يمكننا استخدامها للإشارة إلى أن العنصر مُعدَّل أم لا، فإذا كانت للراية <code>isEditing</code> القيمة <code>true</code>، فيجب استخدام هذه الراية لعرض المكوِّن <code>ToDoItemEditForm</code> بدلًا من مربع الاختيار، إذ سنستخدِم الموجِّه <code>v-if</code> في إطار العمل Vue.
</p>

<p>
	لن يصيِّر الموجِّه <code>v-if</code> كتلةً ما إلا إذا كانت القيمة المُمرَّرة إليه <code>true</code>، وهذا مشابه لكيفية عمل التعليمة <code>if</code> في <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-javascript-r664/" rel="">لغة جافاسكربت</a>، إذ يحتوي الموجّه <code>v-if</code> على موجّهات مقابلة هي <code>v-else-if</code> و <code>v-else</code> لتوفير ما يعادلها في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">لغة جافاسكربت</a> مثل <code>else if</code> و <code>else</code> ضمن قوالب Vue.
</p>

<p>
	يجب أن تكون كتل <code>v-else</code> و <code>v-else-if</code> الشقيق الأول لكتل <code>v-if</code> و <code>v-else-if</code>، وإلا فلن يتعرَّف Vue عليها، كما يمكنك استخدام الموجّه v-if مع الوسم <code>&lt;template&gt;</code> إذا كنت بحاجة إلى تصيير قالب كامل شرطيًا.
</p>

<p>
	أخيرًا، يمكنك استخدام الموجّهَين <code>v-if</code> و <code>v-else</code> مع جذر المكوِّن لعرض إحدى الكتل فقط أو الكتلة الأخرى، لأنّ Vue لن يصيّر سوى كتلةً واحدةً من هذه الكتل في كل مرة، لذا سنطبّق ذلك في تطبيقنا مما يسمح باستبدال الشيفرة التي تعرض عنصر المهمة في نموذج التعديل.
</p>

<p>
	أضِف <code>v-if="!isEditing"‎</code> إلى عنصر <code>&lt;div&gt;</code> الجذر في المكون <code>ToDoItem</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_20" style="">
<span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"stack-small"</span><span class="pln"> v</span><span class="pun">-</span><span class="kwd">if</span><span class="pun">=</span><span class="str">"!isEditing"</span><span class="pun">&gt;</span></pre>

<p>
	أضف بعد ذلك السطر التالي بعد وسم إغلاق <code>&lt;div&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_22" style="">
<span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">-</span><span class="pln">edit</span><span class="pun">-</span><span class="pln">form v</span><span class="pun">-</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">:</span><span class="pln">id</span><span class="pun">=</span><span class="str">"id"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">label</span><span class="pun">=</span><span class="str">"label"</span><span class="pun">&gt;&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">-</span><span class="pln">edit</span><span class="pun">-</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	كما يجب استيراد المكوِّن <code>ToDoItemEditForm</code> وتسجيله لنتمكّن من استخدامه ضمن هذا القالب، لذا أضف السطر التالي قبل العنصر <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_26" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">ToDoItemEditForm</span><span class="pln"> from </span><span class="str">"./ToDoItemEditForm"</span><span class="pun">;</span></pre>

<p>
	أضِف الخاصية <code>components</code> قبل الخاصية <code>props</code> ضمن كائن المكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_24" style="">
<span class="pln">components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">ToDoItemEditForm</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	إذا انتقلتَ الآن إلى تطبيقك ونقرت على زر "تعديل Edit" عنصر المهام، فيجب أن ترى مربع الاختيار مستبدَلًا بنموذج التعديل.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="106311" href="https://academy.hsoub.com/uploads/monthly_2022_08/01_todo-edit-delete.png.c9237895368f87a889e627da10b7adb5.png" rel=""><img alt="01_todo-edit-delete.png" class="ipsImage ipsImage_thumbnailed" data-fileid="106311" data-unique="8t98qnbll" src="https://academy.hsoub.com/uploads/monthly_2022_08/01_todo-edit-delete.thumb.png.c95e597d09266b4b72e06580bfa997a4.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	لكن لا توجد طريقة حاليًا للعودة، لذلك يجب إضافة مزيد من معالجات الأحداث إلى المكوِّن.
</p>

<h2>
	الرجوع من وضع التعديل
</h2>

<p>
	يجب أولًا إضافة التابع <code>itemEdited()‎</code> إلى الخاصية <code>methods</code> في المكوِّن <code>ToDoItem</code>، إذ يأخذ هذا التابع عنوان label العنصر الجديد بوصفه وسيطًا ويرسل الحدث <code>itemEdited</code> إلى المكوِّن الأب ويضبط <code>isEditing</code> على القيمة <code>false</code>، لذا أضِف هذا التابع الآن بعد التوابع الحالية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_30" style="">
<span class="pln">itemEdited</span><span class="pun">(</span><span class="pln">newLabel</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'item-edited'</span><span class="pun">,</span><span class="pln"> newLabel</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isEditing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنحتاج بعد ذلك إلى التابع <code>editCancelled()‎</code>، ولا يأخذ هذا التابع أي وسائط ويعمل فقط على ضبط <code>isEditing</code> مرةً أخرى على القيمة <code>false</code>، لذا أضِف هذا التابع بعد التابع السابق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_32" style="">
<span class="pln">editCancelled</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">isEditing </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أخيرًا، سنضيف معالِجات الأحداث للأحداث الصادرة من المكوِّن <code>ToDoItemEditForm</code>، وسنربط التوابع المناسبة لكل حدث، لذا عدِّل الاستدعاء <code>&lt;to-do-item-edit-form&gt;</code> ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_34" style="">
<span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">-</span><span class="pln">edit</span><span class="pun">-</span><span class="pln">form v</span><span class="pun">-</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">:</span><span class="pln">id</span><span class="pun">=</span><span class="str">"id"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">label</span><span class="pun">=</span><span class="str">"label"</span><span class="pln">
                      </span><span class="lit">@item</span><span class="pun">-</span><span class="pln">edited</span><span class="pun">=</span><span class="str">"itemEdited"</span><span class="pln">
                      </span><span class="lit">@edit</span><span class="pun">-</span><span class="pln">cancelled</span><span class="pun">=</span><span class="str">"editCancelled"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">-</span><span class="pln">edit</span><span class="pun">-</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<h2>
	تعديل وحذف عناصر المهام
</h2>

<p>
	يمكننا الآن التبديل بين نموذج التعديل ومربع الاختيار، ولكن لم نعالِج تحديث المصفوفة <code>ToDoItems</code> مرةً أخرى في المكوِّن <code>App.vue</code>، ويمكن إصلاح ذلك من خلال الاستماع إلى الحدث <code>item-edited</code> وتحديث القائمة وفقًا لذلك، كما يجب التعامل مع حدث الحذف لنتمكّن من حذف عناصر المهام.
</p>

<p>
	أضف التوابع الجديدة التالية إلى كائن مكوِّن <code>App.vue</code> بعد التوابع الموجودة مسبقًا ضمن الخاصية <code>methods</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_36" style="">
<span class="pln">deleteToDo</span><span class="pun">(</span><span class="pln">toDoId</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> itemIndex </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">findIndex</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> toDoId</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">splice</span><span class="pun">(</span><span class="pln">itemIndex</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">},</span><span class="pln">
editToDo</span><span class="pun">(</span><span class="pln">toDoId</span><span class="pun">,</span><span class="pln"> newLabel</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> toDoToEdit </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> toDoId</span><span class="pun">);</span><span class="pln">
  toDoToEdit</span><span class="pun">.</span><span class="pln">label </span><span class="pun">=</span><span class="pln"> newLabel</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنضيف بعد ذلك مستمعي الأحداث للحدثين <code>item-deleted</code> و <code>item-edited</code>، بحيث:
</p>

<ul>
<li>
		يجب تمرير <code>item.id</code> إلى التابع بالنسبة للحدث <code>item-deleted</code>.
	</li>
	<li>
		يجب تمرير <code>item.id</code> والمتغير الخاص <code>‎$event</code> بالنسبة للحدث <code>item-edited</code>، إذ يُعَدّ المتغير <code>‎$event</code> هو متغير خاص بإطار العمل Vue ويُستخدَم لتمرير بيانات الحدث إلى التوابع، فإذا استخدمتَ أحداث HTML الأصيلة Native مثل الحدث <code>click</code>، فسيمرّر هذا المتغير كائن الحدث الأصيل إلى تابعك.
	</li>
</ul>
<p>
	عدّل الاستدعاء <code>&lt;to-do-item&gt;&lt;/to-do-item&gt;</code> ضمن قالب <code>App.vue</code> ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_38" style="">
<span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item </span><span class="pun">:</span><span class="pln">label</span><span class="pun">=</span><span class="str">"item.label"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">done</span><span class="pun">=</span><span class="str">"item.done"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">id</span><span class="pun">=</span><span class="str">"item.id"</span><span class="pln">
            </span><span class="lit">@checkbox</span><span class="pun">-</span><span class="pln">changed</span><span class="pun">=</span><span class="str">"updateDoneStatus(item.id)"</span><span class="pln">
            </span><span class="lit">@item</span><span class="pun">-</span><span class="pln">deleted</span><span class="pun">=</span><span class="str">"deleteToDo(item.id)"</span><span class="pln">
            </span><span class="lit">@item</span><span class="pun">-</span><span class="pln">edited</span><span class="pun">=</span><span class="str">"editToDo(item.id, $event)"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span></pre>

<p>
	يجب أن تكون الآن قادرًا على تعديل العناصر وحذفها من القائمة.
</p>

<h2>
	إصلاح خطأ باستخدام الحالة isDone
</h2>

<p>
	يبدو كل شيء رائعًا حتى الآن، ولكننا أحدثنا خطأً عن طريق إضافة وظيفة التعديل، لذا جرّب تنفيذ ما يلي:
</p>

<ol>
<li>
		تحديد أو إلغاء تحديد أحد مربعات اختيار المهام.
	</li>
	<li>
		الضغط على زر "التعديل Edit" لعنصر المهام نفسه.
	</li>
	<li>
		إلغاء التعديل بالضغط على زر "الإلغاء Cancel".
	</li>
</ol>
<p>
	لاحظ حالة مربع الاختيار بعد الضغط على زر الإلغاء، فلم ينسَ التطبيق حالة مربع الاختيار فقط، وإنما أحدث خللًا أيضًا في حالة الاكتمال <code>done</code> لعنصر المهام المقابل، فإذا حاولت تحديده أو إلغاء تحديده مرةً أخرى، فسيتغير عدد المهام المكتملة بعكس ما تتوقعه لأنّ الخاصية <code>isDone</code> ضمن <code>data</code> تُعطَى القيمة <code>this.done</code> عند تحميل المكوِّن، ويمكن إصلاح ذلك عن طريق تحويل عنصر بيانات <code>isDone</code> إلى الخاصية <code>computed</code>، إذ سنستخدِم ميزةً أخرى للخاصيات <code>computed</code> هي أنها تحافظ على التفاعل، مما يعني أنّ حالتها تُحفَظ عندما يتغير القالب.
</p>

<p>
	أزِل السطر التالي من الخاصية <code>data()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_40" style="">
<span class="pln">isDone</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">done</span><span class="pun">,</span></pre>

<p>
	أضِف الكتلة التالية بعد كتلة <code>data() { }‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5709_42" style="">
<span class="pln">computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  isDone</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">done</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	ستجد أنّ المشكلة قد حُلَّت الآن عند الحفظ وإعادة التحميل، إذ سيجري الاحتفاظ بحالة مربع الاختيار عند التبديل بين قوالب عناصر المهام.
</p>

<h2>
	فهم تشابك الأحداث
</h2>

<p>
	يُعَدّ تشابكُ الأحداث القياسية والمخصَّصة التي استخدمناها لتحفيز التفاعل في تطبيقنا أحد أكثر الأجزاء المربكة، إذ يمكننا فهم ذلك بصورة أفضل من خلال كتابة مخطط تدفقي أو وصف أو رسم توضيحي لمكان إصدار الأحداث ومكان الاستماع إليها وما يحدث نتيجة إطلاقها.
</p>

<p>
	فمثلًا في الملف App.vue:
</p>

<ul>
<li>
		يستمع العنصر <code>&lt;to-do-form&gt;</code> إلى:

		<ul>
<li>
				الحدث <code>todo-added</code> الصادر عن التابع <code>onSubmit()‎</code> ضمن المكوِّن <code>ToDoForm</code> عند إرسال النموذج، والنتيجة هي استدعاء التابع <code>addToDo()‎</code> لإضافة عنصر مهمة جديد إلى المصفوفة <code>ToDoItems</code>.
			</li>
		</ul>
</li>
	<li>
		يستمع العنصر <code>&lt;to-do-item&gt;</code> إلى:
		<ul>
<li>
				الحدث <code>checkbox-changed</code> الصادر عن مربع الاختيار في العنصر <code>&lt;input&gt;</code> ضمن المكوِّن <code>ToDoItem</code> عند تحديده أو إلغاء تحديده، والنتيجة هي استدعاء التابع <code>updateDoneStatus()‎</code> لتحديث حالة الاكتمال <code>done</code> لعنصر المهمة المقابل.
			</li>
			<li>
				الحدث <code>item-deleted</code> الصادر عن التابع <code>deleteToDo()‎</code> ضمن المكوِّن <code>ToDoItem</code> عند الضغط على زر "الحذف Delete"، والنتيجة هي استدعاء التابع <code>deleteToDo()‎</code> لحذف عنصر المهمة المقابل.
			</li>
			<li>
				الحدث <code>item-edited</code> الصادر عن التابع <code>itemEdited()‎</code> ضمن المكوِّن <code>ToDoItem</code> عند الاستماع بنجاح إلى الحدث <code>item-edited</code> باستخدام التابع <code>onSubmit()‎</code> ضمن المكوِّن <code>ToDoItemEditForm</code>، إذ يمثّل ذلك سلسلةً من حدثَي <code>item-edit</code> مختلفين، والنتيجة هي استدعاء التابع <code>editToDo()‎</code> لتحديث عنوان <code>label</code> عنصر المهمة المقابل.
			</li>
		</ul>
</li>
</ul>
<p>
	في الملف ToDoForm.vue:
</p>

<ul>
<li>
		يستمع <a href="https://wiki.hsoub.com/HTML/form" rel="external">العنصر &lt;form&gt;</a> إلى الحدث <code>submit</code>، والنتيجة هي استدعاء التابع <code>onSubmit()‎</code> الذي يتحقَّق من أنّ العنوان <code>label</code> الجديد ليس فارغًا، ثم يصدر الحدث <code>todo-added</code> الذي يمكن الاستماع إليه لاحقًا ضمن الملف App.vue كما ذكرنا سابقًا، ثم يمسح عنوان العنصر <code>&lt;input&gt;</code> الجديد.
	</li>
	<li>
		في الملف ToDoItem.vue:
	</li>
	<li>
		يستمع عنصر مربع الاختيار <code>checkbox</code> في العنصر <code>&lt;input&gt;</code> إلى الحدث <code>change</code>، والنتيجة هي إصدار الحدث <code>checkbox-changed</code> عند تحديد أو إلغاء تحديد مربع الاختيار الذي يمكن الاستماع إليه لاحقًا في المكوِّن App.vue كما ذكرنا سابقًا.
	</li>
	<li>
		يستمع زر <code>&lt;button&gt;</code> "التعديل Edit" إلى الحدث <code>click</code>، والنتيجة هي استدعاء التابع <code>toggleToItemEditForm()‎</code> الذي قيمة <code>this.isEditing</code> مبدَّلة إلى <code>true</code> والتي تعرض بدورها قالب تعديل عنصر المهام عند إعادة التصيير.
	</li>
	<li>
		يستمع زر <code>&lt;button&gt;</code> "الحذف Delete" إلى الحدث <code>click</code>، والنتيجة هي استدعاء التابع <code>deleteToDo()‎</code> الذي يصدر الحدث <code>item-deleted</code>، والذي يمكن الاستماع إليه لاحقًا ضمن المكوِّن <code>App.vue</code> كما ذكرنا سابقًا.
	</li>
	<li>
		يستمع المكوِّن <code>&lt;to-do-item-edit-form&gt;</code> إلى:
		<ul>
<li>
				الحدث <code>item-edited</code> الصادر عن التابع <code>onSubmit()‎</code> ضمن المكوِّن <code>ToDoItemEditForm</code> عند إرسال النموذج بنجاح، والنتيجة هي استدعاء التابع <code>itemEdited()‎</code> الذي يصدر الحدث <code>item-edited</code> الذي يمكن الاستماع إليه لاحقًا في المكوِّن <code>App.vue</code> كما ذكرنا سابقًا، كما يعيد ضبط <code>this.isEditing</code> على القيمة <code>false</code>، وبالتالي لن يظهر نموذج التعديل عند إعادة التصيير.
			</li>
			<li>
				الحدث <code>edit-cancelled</code> الصادر عن التابع <code>onCancel()‎</code> ضمن المكوِّن <code>ToDoItemEditForm</code> عند النقر على زر "الإلغاء Cancel"، والنتيجة هي استدعاء التابع <code>editCancelled()‎</code> الذي يعيد ضبط <code>this.isEditing</code> على القيمة <code>false</code>، وبالتالي لن يظهر نموذج التعديل عند إعادة التصيير.
			</li>
		</ul>
</li>
</ul>
<p>
	في الملف ToDoItemEditForm.vue:
</p>

<ul>
<li>
		يستمع العنصر <code>&lt;form&gt;</code> إلى الحدث <code>submit</code>، والنتيجة هي استدعاء التابع <code>onSubmit()‎</code> الذي يتحقق مما إذا كانت قيمة العنوان الجديدة غير فارغة وليست مماثلةً للقيمة القديمة، فإذا كان الأمر كذلك، فسيصدر الحدث <code>item-edited</code> الذي يمكن الاستماع إليه لاحقًا ضمن المكوِّن <code>ToDoItem.vue</code> كما ذكرنا سابقًا.
	</li>
	<li>
		يستمع <a href="https://wiki.hsoub.com/HTML/button" rel="external">زر &lt;button&gt;</a> "الإلغاء Cancel" إلى الحدث <code>click</code>، والنتيجة هي استدعاء التابع <code>onCancel()‎</code> الذي يصدر الحدث <code>edit-cancelled</code> الذي يمكن الاستماع إليه لاحقًا في المكون <code>ToDoItem.vue</code> كما ذكرنا سابقًا.
	</li>
</ul>
<h2>
	الخلاصة
</h2>

<p>
	أصبح لدينا الآن وظائف التعديل والحذف في تطبيقنا، وبالتالي سنقترب من نهاية سلسلة Vue، إذ يجب الآن تعلّم كيفية إدارة التركيز أو كيف يمكننا تحسين الشمولية لمستخدمي لوحة المفاتيح في تطبيقنا.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering" rel="external nofollow">Vue conditional rendering: editing existing todos</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A9-computed-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1683/" rel="">إضافة تنسيق للمكونات واستعمال الخاصية computed في تطبيق Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%B9%D8%B1%D8%B6-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-vuejs-r1666/" rel="">عرض مكونات Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r1036/" rel="">استخدام Vue.js للاتصال بالإنترنت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1684</guid><pubDate>Thu, 25 Aug 2022 09:36:39 +0000</pubDate></item><item><title>&#x625;&#x636;&#x627;&#x641;&#x629; &#x62A;&#x646;&#x633;&#x64A;&#x642; &#x644;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x648;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x627;&#x644;&#x62E;&#x627;&#x635;&#x64A;&#x629; computed &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D9%8A%D8%A9-computed-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1683/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/630613fb0f83e_----Vue---CSS---computed----.png.5f778ef535008320e9d06d70099afca0.png" /></p>

<p>
	لقد حان الوقت أخيرًا لجعل تطبيقنا يبدو أجمل قليلًا، إذ سنتعرّف في هذا المقال على الطرق المختلفة لتنسيق مكونات إطار العمل Vue باستخدام <a href="https://academy.hsoub.com/programming/css/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%AA%D9%86%D8%B3%D9%8A%D9%82-css-r551/" rel="">لغة CSS</a>، كما سنضيف عدّادًا يعرض عدد عناصر المهام المكتملة باستخدام ميزة في <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">إطار عمل Vue</a> تسمّى الخاصية <code>computed</code>، إذ تعمل هذه الخاصية بصورة مشابهة للتوابع، ولكن يُعاد تشغيلها فقط عندما تتغير إحدى اعتمادياتها.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a> ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكونات Vue بوصفها مجموعةً من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%AC%D8%B1%D9%8A%D8%A9-%D9%84%D9%80-dom-r646/" rel="">بنية DOM</a> الأساسية، كما ستحتاج إلى طرفية مثبَّت عليها node و <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">npm</a> لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكونات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: التعرف على مكونات التنسيق وتعلّم كيفية استخدام خاصيات <code>computed</code> في Vue.
	</li>
</ul>
<p>
	يجب إضافة <a href="https://academy.hsoub.com/programming/css/%D8%AA%D9%82%D9%86%D9%8A%D8%A7%D8%AA-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%B4%D9%8A%D9%81%D8%B1%D8%A7%D8%AA-css-%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81%D9%8A%D8%A9-%D9%88%D8%B3%D9%87%D9%84%D8%A9-%D8%A7%D9%84%D8%B5%D9%91%D9%8A%D8%A7%D9%86%D8%A9-r428/" rel="">شيفرة CSS</a> الأساسية إلى تطبيقنا لجعله يبدو أفضل قبل إضافة مزيد من الميزات المتقدمة إليه، إذ يمتلك إطار العمل Vue ثلاث طرق شائعة لتنسيق التطبيقات:
</p>

<ul>
<li>
		ملفات CSS الخارجية.
	</li>
	<li>
		التنسيقات العام في مكونات الملف المفرد، أي الملفات ذات اللاحقة <code>‎.vue</code>.
	</li>
	<li>
		التنسيقات على مستوى المكونات في مكونات الملف المفرد.
	</li>
</ul>
<p>
	سنستخدِم مزيجًا من الطرق الثلاثة لإضفاء مظهر وتنسيق أفضل على تطبيقنا للتعرف على هذه الطرق.
</p>

<h2>
	التنسيق باستخدام ملفات CSS الخارجية
</h2>

<p>
	يمكنك تضمين ملفات CSS الخارجية وتطبيقها بطريقة عامة على تطبيقك، لذا أنشئ ملفًا بالاسم reset.css في المجلد src/assets، إذ تُعالَج الملفات الموجودة في هذا المجلد باستخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-webpack-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-r866/" rel="">Webpack</a>، وبالتالي يمكننا استخدام معالجات CSS المسبقَة مثل <a href="https://wiki.hsoub.com/Sass" rel="external">SCSS</a> أو معالجات ملحقَة مثل PostCSS. لن نستخدِم في هذا المقال مثل هذه الأدوات، ولكن يجب معرفة أنه ستُعالَج الشيفرة تلقائيًا عند تضمينها في المجلد assets.
</p>

<p>
	أضِف المحتويات التالية في الملف reset.css:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_602_13" style="">
<span class="com">/*reset.css*/</span><span class="pln">
</span><span class="com">/* إعادة الضبط */</span><span class="pln">
</span><span class="pun">*,</span><span class="pln">
</span><span class="pun">*::</span><span class="pln">before</span><span class="pun">,</span><span class="pln">
</span><span class="pun">*::</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">*:</span><span class="pln">focus </span><span class="pun">{</span><span class="pln">
  outline</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pln"> dashed </span><span class="com">#228bec;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
html </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">:</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">%</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">1.15</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
h1</span><span class="pun">,</span><span class="pln">
h2 </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
ul </span><span class="pun">{</span><span class="pln">
  list</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  overflow</span><span class="pun">:</span><span class="pln"> visible</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> normal</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">appearance</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button</span><span class="pun">::-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">focus</span><span class="pun">-</span><span class="pln">inner </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button</span><span class="pun">,</span><span class="pln">
input</span><span class="pun">,</span><span class="pln">
optgroup</span><span class="pun">,</span><span class="pln">
</span><span class="kwd">select</span><span class="pun">,</span><span class="pln">
textarea </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.15</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
button</span><span class="pun">,</span><span class="pln">
input </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* 1 */</span><span class="pln">
  overflow</span><span class="pun">:</span><span class="pln"> visible</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"text"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
body </span><span class="pun">{</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">68rem</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.6rem</span><span class="pun">/</span><span class="lit">1.25</span><span class="pln"> </span><span class="str">"Helvetica Neue"</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Helvetica</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#f5f5f5;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#4d4d4d;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">620px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  body </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.9rem</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.31579</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/*نهاية إعادة الضبط*/</span></pre>

<p>
	استورد بعد ذلك الملف reset.css في الملف src/main.js كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_602_15" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="str">'./assets/reset.css'</span><span class="pun">;</span></pre>

<p>
	سيؤدي ذلك إلى نقل الملف أثناء خطوة البناء وإضافته تلقائيًا إلى موقعنا.
</p>

<p>
	يجب تطبيق التنسيقات المُعاد ضبطها على التطبيق الآن، إذ تُظهر الصور التالية مظهر التطبيق قبل وبعد تطبيق إعادة الضبط.
</p>

<p>
	قبل إعادة ضبط التنسيق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="106274" href="https://academy.hsoub.com/uploads/monthly_2022_08/01_todo-app-unstyled.png.7587e0e28142f0bd580edf024ea3f948.png" rel=""><img alt="01_todo-app-unstyled.png" class="ipsImage ipsImage_thumbnailed" data-fileid="106274" data-unique="pas600l5i" src="https://academy.hsoub.com/uploads/monthly_2022_08/01_todo-app-unstyled.thumb.png.752f82f9ed6fd2175fccc7411e0a98cc.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	بعد إعادة ضبط التنسيق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="106275" href="https://academy.hsoub.com/uploads/monthly_2022_08/02_todo-app-reset-styles.png.ef9a2a00737e1725916f4a50a216a7e0.png" rel=""><img alt="02_todo-app-reset-styles.png" class="ipsImage ipsImage_thumbnailed" data-fileid="106275" data-unique="pxh2mencf" src="https://academy.hsoub.com/uploads/monthly_2022_08/02_todo-app-reset-styles.thumb.png.af4ef1997f5aa71aaff14413b427c5f2.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	تشمل التغييرات الملحوظة إزالة نقط تعداد للقائمة وتغييرات لون الخلفية والتغييرات في الزر الأساسي وتنسيقات حقل الإدخال.
</p>

<h2>
	إضافة التنسيقات العامة إلى مكونات الملف المفرد
</h2>

<p>
	أعدنا ضبط شيفرة CSS لتكون موحدةًَ في المتصفحات ويجب الآن تخصيص التنسيقات، فهناك بعض التنسيقات التي نريد تطبيقها على مستوى المكونات في تطبيقنا من خلال إضافة التنسيقات إلى وسوم <code>&lt;style&gt;</code> في الملف App.vue بدلًا من إضافتها مباشرةً إلى ملف التنسيقات reset.css.
</p>

<p>
	توجد مسبقًا بعض التنسيقات في الملف App.vue، فلنحذفها ونستبدلها بالتنسيقات التالية التي تضيف تنسيقًا إلى الأزرار وحقول الإدخال وتخصّص العنصر <code>‎#app</code> وأبناءه، لذا عدِّل العنصر <code>&lt;style&gt;</code> في الملف App.vue بحيث يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_602_24" style="">
<span class="str">&lt;style&gt;</span><span class="pln">
</span><span class="com">/* التنسيقات العامة */</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pln"> </span><span class="lit">1rem</span><span class="pln"> </span><span class="lit">0.7rem</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.2rem</span><span class="pln"> solid </span><span class="com">#4d4d4d;</span><span class="pln">
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">transform</span><span class="pun">:</span><span class="pln"> capitalize</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__danger </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ca3c3c;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#bd2130;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__filter </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> lightgrey</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__danger</span><span class="pun">:</span><span class="pln">focus </span><span class="pun">{</span><span class="pln">
  outline</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#c82333;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn__primary </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
  background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#000;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">-</span><span class="pln">group </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  justify</span><span class="pun">-</span><span class="pln">content</span><span class="pun">:</span><span class="pln"> space</span><span class="pun">-</span><span class="pln">between</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">-</span><span class="pln">group </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  flex</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">btn</span><span class="pun">-</span><span class="pln">group </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.8rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">label</span><span class="pun">-</span><span class="pln">wrapper </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  flex</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"__lg"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.9rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"__lg"</span><span class="pun">]:</span><span class="pln">not</span><span class="pun">(:</span><span class="pln">last</span><span class="pun">-</span><span class="pln">child</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen and </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">620px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"__lg"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">visually</span><span class="pun">-</span><span class="pln">hidden </span><span class="pun">{</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
  overflow</span><span class="pun">:</span><span class="pln"> hidden</span><span class="pun">;</span><span class="pln">
  clip</span><span class="pun">:</span><span class="pln"> rect</span><span class="pun">(</span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">);</span><span class="pln">
  clip</span><span class="pun">:</span><span class="pln"> rect</span><span class="pun">(</span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">);</span><span class="pln">
  clip</span><span class="pun">-</span><span class="pln">path</span><span class="pun">:</span><span class="pln"> rect</span><span class="pun">(</span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">);</span><span class="pln">
  white</span><span class="pun">-</span><span class="pln">space</span><span class="pun">:</span><span class="pln"> nowrap</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">[</span><span class="kwd">class</span><span class="pun">*=</span><span class="str">"stack"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="typ">stack</span><span class="pun">-</span><span class="pln">small </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.25rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="typ">stack</span><span class="pun">-</span><span class="pln">large </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.5rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen and </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">550px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">.</span><span class="typ">stack</span><span class="pun">-</span><span class="pln">small </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">.</span><span class="typ">stack</span><span class="pun">-</span><span class="pln">large </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.8rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">/* نهاية التنسيقات العامة */</span><span class="pln">
</span><span class="com">#app {</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2rem</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">4rem</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2.5rem</span><span class="pln"> </span><span class="lit">5rem</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0.1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> screen and </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">550px</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">#app {</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4rem</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#app &gt; * {</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50rem</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#app &gt; form {</span><span class="pln">
  max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#app h1 {</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
  min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">style</span><span class="pun">&gt;</span></pre>

<p>
	إذا اختبرت التطبيق، فسترى أنّ قائمة المهام موجودة ضمن قسم خاص به الآن مع بعض التنسيقات الأفضل لعناصر المهام كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="106276" href="https://academy.hsoub.com/uploads/monthly_2022_08/03_todo-app-partial-styles.png.faad92c31aa2ef41e26bfff4f4dc0ffe.png" rel=""><img alt="03_todo-app-partial-styles.png" class="ipsImage ipsImage_thumbnailed" data-fileid="106276" data-unique="drmzklfw3" src="https://academy.hsoub.com/uploads/monthly_2022_08/03_todo-app-partial-styles.thumb.png.4156f43eec55c1b9cc2c563a615272b8.png" style="width: 700px; height: auto;"></a>
</p>

<h3>
	إضافة أصناف CSS في إطار العمل Vue
</h3>

<p>
	سنطبّق أصناف <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> على عنصر الزر <code>&lt;button&gt;</code> في المكوِّن <code>ToDoForm</code>، وبما أنّ قوالب Vue تستخدِم لغة HTML، فسنستخدِم الطريقة نفسها عن طريق إضافة السمة <code>class=""‎</code> إلى العنصر، لذا أضِف السمة <code>class="btn btn__primary btn__lg"‎</code> إلى العنصر <code>&lt;button&gt;</code> في نموذجك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_28" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn__primary btn__lg"</span><span class="tag">&gt;</span><span class="pln">
  Add
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	هناك تغيير آخر يمكن إجراؤه، فبما أنّ النموذج يشير إلى قسم معيّن من الصفحة، فيمكن استخدام العنصر <code>&lt;h2&gt;</code>، ولكن يشير العنصر <code>label</code> إلى الغرض من النموذج مسبقًا، لذلك يجب تجنب التكرار من خلال تغليف العنصر <code>label</code> ضمن <a href="https://wiki.hsoub.com/HTML/h1-h6" rel="external">العنصر &lt;h2&gt;</a>، كما يمكننا إضافة بعض تنسيقات CSS العامة الأخرى، إذ سنضيف الصنف <code>input__lg</code> إلى العنصر <code>&lt;input&gt;</code>، لذا عدِّل قالب المكوّن <code>ToDoForm</code> بحيث يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_602_31" style="">
<span class="str">&lt;template&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">form </span><span class="lit">@submit</span><span class="pun">.</span><span class="pln">prevent</span><span class="pun">=</span><span class="str">"onSubmit"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h2 </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"label-wrapper"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">label </span><span class="kwd">for</span><span class="pun">=</span><span class="str">"new-todo-input"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"label__lg"</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">What</span><span class="pln"> needs to be done</span><span class="pun">?</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">input
      type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
      id</span><span class="pun">=</span><span class="str">"new-todo-input"</span><span class="pln">
      name</span><span class="pun">=</span><span class="str">"new-todo"</span><span class="pln">
      autocomplete</span><span class="pun">=</span><span class="str">"off"</span><span class="pln">
      v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">.</span><span class="pln">lazy</span><span class="pun">.</span><span class="pln">trim</span><span class="pun">=</span><span class="str">"label"</span><span class="pln">
      </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"input__lg"</span><span class="pln">
    </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"btn btn__primary btn__lg"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="typ">Add</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="kwd">template</span><span class="pun">&gt;</span></pre>

<p>
	كما سنضيف الصنف <code>stack-large</code> إلى الوسم <code><a href="https://wiki.hsoub.com/HTML/ul" rel="external">&lt;ul&gt;</a></code> في الملف App.vue كما يلي، مما يساعد في تحسين التباعد بين عناصر المهام:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_34" style="">
<span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-summary"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-large"</span><span class="tag">&gt;</span></pre>

<h2>
	إضافة التنسيقات ذات النطاق المحدد
</h2>

<p>
	نريد الآن تنسيق المكوِِّن <code>ToDoItem</code>، إذ يمكننا إضافة العنصر <code>&lt;style&gt;</code> ضمنه لتكون تعريفات التنسيقات قريبةً من المكوِّن، لكن إذا غيرت هذه التنسيقات أشياءً خارج هذا المكوِّن، فسيكون تعقّب التنسيقات المسؤولة عن ذلك وإصلاح المشكلة أمرًا صعبًا.
</p>

<p>
	سنستخدِم السمة <code>scoped</code> حيث يرتبط محدِّد سمة HTML الفريدة <code>data</code> مع جميع التنسيقات، مما يمنعها من التعارض على المستوى العام، كما يمكنك استخدام معدِّل <code>scoped</code> من خلال إنشاء العنصر <code>&lt;style&gt;</code> ضمن المكوِّن <code>ToDoItem.vue</code>، ثم منحه السمة <code>scoped</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_36" style="">
<span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	انسخ بعد ذلك شيفرة CSS التالية والصقها في العنصر <code>&lt;style&gt;</code> الذي أنشأناه للتو:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_602_38" style="">
<span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">.</span><span class="pln">checkbox</span><span class="pun">-</span><span class="pln">label </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16px</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.25</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#0b0c0c;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">.</span><span class="pln">checkbox </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16px</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.25</span><span class="pun">;</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.5rem</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid </span><span class="com">#0b0c0c;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">appearance</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">appearance</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  appearance</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">:</span><span class="pln">focus </span><span class="pun">{</span><span class="pln">
  outline</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pln"> dashed </span><span class="com">#fd0;</span><span class="pln">
  outline</span><span class="pun">-</span><span class="pln">offset</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> inset </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">400</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.6rem</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.25</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
  min</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  clear</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  z</span><span class="pun">-</span><span class="pln">index</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">44px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">44px</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">.</span><span class="pln">checkbox</span><span class="pun">-</span><span class="pln">label </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> inherit</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
  touch</span><span class="pun">-</span><span class="pln">action</span><span class="pun">:</span><span class="pln"> manipulation</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">before </span><span class="pun">{</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid currentColor</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]:</span><span class="pln">focus </span><span class="pun">+</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">before </span><span class="pun">{</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4px</span><span class="pun">;</span><span class="pln">
  outline</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pln"> dashed </span><span class="com">#228bec;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> content</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
  content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">11px</span><span class="pun">;</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9px</span><span class="pun">;</span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18px</span><span class="pun">;</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7px</span><span class="pun">;</span><span class="pln">
  transform</span><span class="pun">:</span><span class="pln"> rotate</span><span class="pun">(-</span><span class="lit">45deg</span><span class="pun">);</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> solid</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">top</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> transparent</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pun">]:</span><span class="kwd">checked</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> label</span><span class="pun">::</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
  opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="lit">@media</span><span class="pln"> only screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40rem</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  label</span><span class="pun">,</span><span class="pln">
  input</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">custom</span><span class="pun">-</span><span class="pln">checkbox </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">19px</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.9rem</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.31579</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب الآن إضافة أصناف CSS إلى القالب لربط التنسيقات، لذا انتقل إلى <a href="https://wiki.hsoub.com/HTML/div" rel="external">العنصر &lt;div&gt;</a> الجذر ثم أضِف الصنف <code>custom-checkbox</code>، وأضف الصنف <code>checkbox</code> إلى العنصر <code>&lt;input&gt;</code> ثم أضف الصنف إلى العنصر <code>&lt;label&gt;</code>، وبالتالي سيحتوي التطبيق على مربعات اختيار مخصَّصة، كما يجب أن يبدو تطبيقك الآن كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="106277" href="https://academy.hsoub.com/uploads/monthly_2022_08/04_todo-app-complete-styles.png.c1b16cbaac25993639dd13a9379a584a.png" rel=""><img alt="04_todo-app-complete-styles.png" class="ipsImage ipsImage_thumbnailed" data-fileid="106277" data-unique="ivjozkhra" src="https://academy.hsoub.com/uploads/monthly_2022_08/04_todo-app-complete-styles.thumb.png.1bdcffe010aae86ffc416e96660e8d89.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	انتهينا من تنسيق تطبيقنا، وسنعود الآن إلى إضافة مزيد من الوظائف إليه، أي استخدام الخاصية <code>computed</code> لإضافة عدد عناصر المهام المكتملة إلى تطبيقنا.
</p>

<h2>
	استخدام الخاصية computed في إطار العمل Vue
</h2>

<p>
	نريد إضافة عدّاد counter يلخّص عدد العناصر في قائمة المهام، مما يساعد التقنيات المساعدة في معرفة عدد المهام المكتملة، فإذا كان لدينا عنصران مكتملان من أصل خمسة في قائمة المهام، فسنرى العبارة "2‎ items completed out of 5" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_44" style="">
<span class="tag">&lt;h2&gt;</span><span class="pln">{{ToDoItems.filter(item =&gt; item.done).length}} out of {{ToDoItems.length}} items completed</span><span class="tag">&lt;/h2&gt;</span></pre>

<p>
	سيُعاد حساب هذا العدد في كل عملية تصيير، ويمكن أن يكون ذلك غير مهم بالنسبة إلى تطبيق صغير مثل تطبيقنا، ولكنه سيتسبب في مشكلة خطيرة في الأداء بالنسبة للتطبيقات الأكبر حجمًا أو عندما يكون التعبير أكثر تعقيدًا، لذا يكون الحل الأفضل هو استخدام خاصيات <code>computed</code> في إطار العمل Vue، إذ تعمل هذه الخاصيات بصورة مشابهة للتوابع، ولكن يُعاد تشغيلها فقط عندما تتغير إحدى اعتمادياتها، إذ سيُعاد تشغيلها في حالتنا عندما تتغير المصفوفة <code>ToDoItems</code> فقط.
</p>

<p>
	يمكن إنشاء الخاصية <code>computed</code> من خلال إضافتها إلى كائن المكوِّن مثل الخاصية <code>methods</code> التي استخدمناها سابقًا.
</p>

<h2>
	إضافة عداد
</h2>

<p>
	أضِف الشيفرة البرمجية التالية إلى كائن المكوِّن <code>App</code> بعد الخاصية <code>methods</code>، إذ يأخذ التابع <code>listSummary()‎</code> عدد عناصر <code>ToDoItems</code> المنتهية، ويعيد سلسلةً نصيةً تمثّل ذلك.
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_602_50" style="">
<span class="pln">computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  listSummary</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> numberFinishedItems </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln">item</span><span class="pun">.</span><span class="kwd">done</span><span class="pun">).</span><span class="pln">length
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">`${numberFinishedItems} out of ${this.ToDoItems.length} items completed`</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا الآن إضافة <code>{{listSummary}}</code> مباشرةً إلى نموذجنا، إذ سنضيفه ضمن العنصر <code>&lt;h2&gt;</code> قبل العنصر <code>&lt;ul&gt;</code> مباشرةً، كما سنضيف السمة <code>id</code> والسمة <code>aria-labelledby</code> لتكون محتويات العنصر <code>&lt;h2&gt;</code> عنوانًا <code>label</code> للعنصر <code>&lt;ul&gt;</code>، لذا أضِف العنصر <code>&lt;h2&gt;</code> وعدّل العنصر <code>&lt;ul&gt;</code> ضمن قالب المكون <code>App</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_52" style="">
<span class="tag">&lt;h2</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"list-summary"</span><span class="tag">&gt;</span><span class="pln">{{listSummary}}</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
</span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">aria-labelledby</span><span class="pun">=</span><span class="atv">"list-summary"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"stack-large"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"item in ToDoItems"</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;to-do-item</span><span class="pln"> :</span><span class="atn">label</span><span class="pun">=</span><span class="atv">"item.label"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"item.done"</span><span class="pln"> :</span><span class="atn">id</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;&lt;/to-do-item&gt;</span><span class="pln">
  </span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	يجب أن تشاهد الآن ملخص القائمة في تطبيقك مع تحديث عدد العناصر الإجمالي كلما أضفت مزيدًا من عناصر المهام، ولكن إذا حاولت تحديد بعض العناصر ثم إلغاء تحديدها، فسيظهر خطأ لأننا لم نتعقّب بعد البيانات "المكتملة" فعليًا، لذلك لن يتغير عدد العناصر المكتملة.
</p>

<h2>
	تعقب تغيرات عدد العناصر المكتملة
</h2>

<p>
	يمكننا استخدام الأحداث لالتقاط تحديث مربع الاختيار وإدارة القائمة وفقًا لذلك، كما يمكننا ربط معالج الحدث <code>‎@change</code> مع كل مربع اختيار بدلًا من استخدام الموجِّه <code>v-model</code> لأننا لا نعتمد على ضغط الزر لبدء التغيير.
</p>

<p>
	عدّل العنصر <code>&lt;input&gt;</code> في المكون <code>ToDoItem.vue</code> ليبدو كما يلي، كما يمكننا تضمين <code>‎$emit()‎</code> لأنّ كل ما يجب فعله هو إرسال أن مربع الاختيار محدَّد فقط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_54" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> :</span><span class="atn">id</span><span class="pun">=</span><span class="atv">"id"</span><span class="pln"> :</span><span class="atn">checked</span><span class="pun">=</span><span class="atv">"isDone"</span><span class="pln">
       @</span><span class="atn">change</span><span class="pun">=</span><span class="atv">"$emit('checkbox-changed')"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	أضف تابعًا جديدًا بالاسم <code>updateDoneStatus()‎</code> في المكوِّن <code>App.vue</code> بعد التابع <code>addToDo()‎</code>، إذ يجب أن يأخذ هذا التابع معامِلًا واحدًا هو معرّف عنصر المهمة، كما نريد العثور على العنصر ذي المعرّف <code>id</code> المطابق وتحديث حالته <code>done</code> لتكون معاكسةً لحالته الحالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_602_62" style="">
<span class="pln">updateDoneStatus</span><span class="pun">(</span><span class="pln">toDoId</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> toDoToUpdate </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">item </span><span class="pun">=&gt;</span><span class="pln"> item</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> toDoId</span><span class="pun">)</span><span class="pln">
  toDoToUpdate</span><span class="pun">.</span><span class="kwd">done</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">toDoToUpdate</span><span class="pun">.</span><span class="kwd">done</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب تشغيل هذا التابع كلما أصدر المكوِّن <code>ToDoItem</code> الحدث <code>checkbox-changed</code>، وتمرير معرّفه <code>item.id</code> بوصفه معاملًا، لذا عدّل الاستدعاء <code>&lt;to-do-item&gt;&lt;/to-do-item&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_602_60" style="">
<span class="tag">&lt;to-do-item</span><span class="pln"> :</span><span class="atn">label</span><span class="pun">=</span><span class="atv">"item.label"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"item.done"</span><span class="pln"> :</span><span class="atn">id</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="pln">
            @</span><span class="atn">checkbox-changed</span><span class="pun">=</span><span class="atv">"updateDoneStatus(item.id)"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/to-do-item&gt;</span></pre>

<p>
	إذا اختبرت العنصر <code>ToDoItem</code> الآن، فيجب أن تشاهد تحديث العدّاد الملخِّص بطريقة صحيحة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="106278" href="https://academy.hsoub.com/uploads/monthly_2022_08/05_todo-counter.png.83fb9171077d89eb9d14dffbf4776944.png" rel=""><img alt="05_todo-counter.png" class="ipsImage ipsImage_thumbnailed" data-fileid="106278" data-unique="bjr1992p4" src="https://academy.hsoub.com/uploads/monthly_2022_08/05_todo-counter.thumb.png.9755f2e7d0315a98ef0d104ceb8f996b.png" style="width: 380px; height: auto;"></a>
</p>

<h2>
	الخلاصة
</h2>

<p>
	تعرّفنا في هذا المقال على تنسيق مكوّنات إطار العمل Vue باستخدام لغة CSS، واستخدمنا الخاصية <code>computed</code> لإضافة ميزة مفيدة إلى تطبيقنا وهي حساب عدد عناصر المهام المكتملة، وسنتعرّف في المقال التالي على التصيير أو العرض الشرطي Conditional Rendering وكيفية استخدامه لإظهار نموذج التعديل عندما نريد تعديل عناصر المهام الحالية.
</p>

<p>
	ترجمة -وبتصرّف- للمقالين <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling" rel="external nofollow">Styling Vue components with CSS</a> و<a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties" rel="external nofollow">Using Vue computed properties</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1665/" rel="">إنشاء المكونات في تطبيق Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%B9%D8%B1%D8%B6-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-vuejs-r1666/" rel="">عرض مكونات Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%B4%D8%B1%D8%AD-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D9%88%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D9%81%D9%8A-vuejs-r1676/" rel="">شرح مفهوم الأحداث والتوابع والنماذج في Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1683</guid><pubDate>Wed, 24 Aug 2022 12:28:26 +0000</pubDate></item><item><title>&#x634;&#x631;&#x62D; &#x645;&#x641;&#x647;&#x648;&#x645; &#x627;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62B; &#x648;&#x627;&#x644;&#x62A;&#x648;&#x627;&#x628;&#x639; &#x648;&#x627;&#x644;&#x646;&#x645;&#x627;&#x630;&#x62C; &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%B4%D8%B1%D8%AD-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%88%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-%D9%88%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D9%81%D9%8A-vuejs-r1676/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/62fb96a54cd4d_----------Vue.png.f4ccefbd02551be8d744db58e260da01.png" /></p>

<p>
	لدينا الآن عينة من البيانات وحلقة تأخذ كل جزء من هذه البيانات وتصيّره أو تعرضه Render ضمن المكوِّن <code>ToDoItem</code> في تطبيقنا، كما نريد السماح لمستخدِمينا بإدخال عناصر مهامهم في التطبيق، لذلك سنحتاج إلى نص إدخال <code>&lt;input&gt;</code> وحدث يُطلَق عند إرسال البيانات وتابع لإطلاق الإرسال بهدف إضافة البيانات وتصيير القائمة ونموذج للتحكم في البيانات، وهذا هو موضوعنا في هذا المقال.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكوّنات Vue بوصفها مجموعةً من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع بنية <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a> الأساسية، وستحتاج إلى طرفية مثبَّت عليها node و <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">npm</a> لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكوّنات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية التعامل مع الاستمارات Forms في Vue والأحداث Events والنماذج Models والتوابع Methods المرتبطة بها.
	</li>
</ul>
<h2>
	إنشاء استمارة مهام جديدة
</h2>

<p>
	لدينا الآن تطبيق يعرض قائمةً بعناصر المهام، ولكن لا يمكننا تعديل قائمة العناصر دون تغيير شيفرتنا البرمجية يدويًا، إذًا لنصلح ذلك ولْننشئ مكوِّنًا جديدًا يسمح لنا بإضافة عنصر مهام جديد.
</p>

<p>
	أنشئ ملفًا جديدًا يسمى <code>ToDoForm.vue</code> في مجلد المكوّنات، ثم أضِف عنصر <code>&lt;template&gt;</code> فارغًا ووسم <code>&lt;script&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_8" style="">
<span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	أضِف استمارة HTML الذي يتيح إدخال عنصر مهام جديد وإرساله إلى التطبيق، كما نحتاج إلى العنصر <code><a href="https://wiki.hsoub.com/HTML/form" rel="external">&lt;form&gt;</a></code> مع العناصر <code><a href="https://wiki.hsoub.com/HTML/label" rel="external">&lt;label&gt;</a></code> و<code><a href="https://wiki.hsoub.com/HTML/input" rel="external">&lt;input&gt;</a></code> و<code><a href="https://wiki.hsoub.com/HTML/button" rel="external">&lt;button&gt;</a></code>، لذا عدِّل قالبك ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1108_12" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;form&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"new-todo-input"</span><span class="tag">&gt;</span><span class="pln">
      What needs to be done?
    </span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
      </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln">
      </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"new-todo-input"</span><span class="pln">
      </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"new-todo"</span><span class="pln">
      </span><span class="atn">autocomplete</span><span class="pun">=</span><span class="atv">"off"</span><span class="pln">
    </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="tag">&gt;</span><span class="pln">
      Add
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/form&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span></pre>

<p>
	لدينا الآن مكوِّن استمارة يمكننا من خلاله إدخال عنوان عنصر مهام جديد والذي سيصبح عنوانًا أو تسمية <code>label</code> للمكوِّن <code>ToDoItem</code> المقابل عند تصييره لاحقًا، ولنحمِّل هذا المكوِّن في تطبيقنا، لذا ارجع إلى الملف App.vue وأضف تعليمة الاستيراد <code>import</code> التالية بعد تعليمة الاستيراد السابقة مباشرةً ضمن العنصر <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_18" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">ToDoForm</span><span class="pln"> from </span><span class="str">'./components/ToDoForm'</span><span class="pun">;</span></pre>

<p>
	يجب تسجيل المكوِّن الجديد في المكون <code>App</code> من خلال تعديل الخاصية <code>components</code> الخاصة بكائن المكوِّن بحيث تبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_26" style="">
<span class="pln">components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">ToDoItem</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">ToDoForm</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	صيّر المكوِّن <code>ToDoForm</code> ضمن تطبيقك من خلال إضافة العنصر <code>&lt;to-do-form /‎&gt;</code> إلى العنصر <code>&lt;template&gt;</code> ضمن المكوِّن <code>App</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1108_22" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">My To-Do List</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;to-do-form&gt;&lt;/to-do-form&gt;</span><span class="pln">
    </span><span class="tag">&lt;ul&gt;</span><span class="pln">
      </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"item in ToDoItems"</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;to-do-item</span><span class="pln"> :</span><span class="atn">label</span><span class="pun">=</span><span class="atv">"item.label"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"item.done"</span><span class="pln"> :</span><span class="atn">id</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;&lt;/to-do-item&gt;</span><span class="pln">
      </span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span></pre>

<p>
	إذا شغّلت موقعك الآن، فيجب أن ترى الاستمارة الجديدة كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="105665" href="https://academy.hsoub.com/uploads/monthly_2022_08/01_rendered-form-with-text-input.png.dad7e5ddc9c9a430c80be9a9387a2585.png" rel=""><img alt="01_rendered-form-with-text-input.png" class="ipsImage ipsImage_thumbnailed" data-fileid="105665" data-unique="xz2nchayi" src="https://academy.hsoub.com/uploads/monthly_2022_08/01_rendered-form-with-text-input.png.dad7e5ddc9c9a430c80be9a9387a2585.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	إذا ملأت الاستمارة ونقرت على زر "الإضافة Add"، فستسرسل الصفحة الاستمارة مرةً أخرى إلى <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a>، ولكننا لا نريد ذلك، وإنما نريد تشغيل تابع على الحدث <code>submit</code> الذي سيضيف المهام الجديدة إلى قائمة بيانات <code>ToDoItem</code> المُعرَّفة ضمن المكوِّن <code>App</code>، لذلك يجب إضافة تابع إلى نسخة المكوِّن.
</p>

<h2>
	إنشاء تابع وربطه بحدث باستخدام الموجه v-on
</h2>

<p>
	يمكن إتاحة تابع للمكوِّن <code>ToDoForm</code> من خلال إضافته إلى كائن المكوِّن ضمن الخاصية <code>methods</code> التي تشبه الخاصيات <code>data()‎</code> و <code>props</code> وما إلى ذلك، إذ تحتوي الخاصية <code>methods</code> على أيّ تابع قد نحتاجه لاستدعاء مكوننا. كما تُشغَّل جميع التوابع عند استدعاء هذه الخاصية، لذلك لا يُعَدّ استخدامها لعرض المعلومات ضمن القالب أمرًا جيدًا، وبالتالي يجب استخدام الخاصية <code>computed</code> -التي سنتحدث عنها لاحقًا- لعرض البيانات الناتجة عن العمليات الحسابية.
</p>

<p>
	يجب إضافة التابع <code>onSubmit()‎</code> إلى الخاصية <code>methods</code> ضمن كائن المكوِّن <code>ToDoForm</code>، إذ سنستخدِم هذا التابع للتعامل مع إجراء الإرسال، لذا أضف هذا التابع كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_30" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'form submitted'</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب بعد ذلك ربط التابع بمعالج حدث الإرسال <code>submit</code> للعنصر <code>&lt;form&gt;</code>، ويشبه ذلك إلى حد كبير كيفية استخدام إطار العمل Vue لصيغة v-bind بهدف ربط السمات، إذ يمتلك Vue موجِّهًا خاصًا لمعالجة الأحداث وهو <code>v-on</code> الذي يعمل باستخدام الصيغة <code>v-on:event="method"‎</code>، كما توجد صيغة مختصرة هي <code>‎@event="method"‎</code>، إذ سنستخدِم الصيغة المختصرة في هذا المقال، وبالتالي أضف معالج حدث الإرسال <code>submit</code> إلى العنصر <code>&lt;form&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_32" style="">
<span class="pun">&lt;</span><span class="pln">form </span><span class="lit">@submit</span><span class="pun">=</span><span class="str">"onSubmit"</span><span class="pun">&gt;</span></pre>

<p>
	إذا شغّلنا معالج حدث الإرسال، فلا يزال التطبيق يرسل البيانات إلى الخادم مما يتسبب في تحديث الصفحة، وبما أننا نطبّق كل عمليات المعالجة على العميل، فلا يوجد خادم ليتعامل مع إعادة الإرسال وسنفقد جميع الحالات المحلية عند تحديث الصفحة، إذ يمكن منع المتصفح من الإرسال إلى الخادم من خلال إيقاف إجراء الحدث الافتراضي أثناء <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%87%D9%85-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%86%D8%AA%D8%B4%D8%A7%D8%B1-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D9%88%D8%A7%D9%84%D8%AA%D8%AD%D9%83%D9%85-%D9%81%D9%8A%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1141/" rel="">انتشاره للأعلى Bubbling Up</a> في الصفحة باستخدام التابع <code>Event.preventDefault()‎</code> في لغة جافاسكربت الصرفة Vanilla JavaScript مثلًا. كما يحتوي إطار عمل Vue على صيغة خاصة تُسمَّى معدِّلات الأحداث Event Modifiers التي يمكنها معالجة هذا الأمر مباشرةً في قالبنا، في حين تُضاف المُعدِّلات إلى نهاية الحدث مع نقطة بالصورة <code>‎@event.modifier</code>، ونوضِّح فيما يلي قائمةً بمعدِّلات الأحداث:
</p>

<ol>
<li>
		<code>‎.stop</code>: يوقِف انتشار الحدث ويكافئ التابع <code>Event.stopPropagation()‎</code> في أحداث جافاسكربت العادية.
	</li>
	<li>
		<code>‎.prevent</code>: يمنع سلوك الحدث الافتراضي ويكافئ التابع <code>Event.preventDefault()‎</code>.
	</li>
	<li>
		<code>‎.self</code>: يؤدي إلى تشغيل المعالج فقط إذا أُرسِل الحدث من هذا العنصر المُحدَّد.
	</li>
	<li>
		<code>{‎.key}</code>: يؤدي إلى تشغيل معالج الأحداث باستخدام مفتاح محدَّد فقط، ويحتوي <a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values" rel="external nofollow">موقع MDN على قائمة بقيم المفاتيح الصالحة</a>، ولكن يجب تحويل المفاتيح متعددة الكلمات إلى حالة الأحرف التي تسمى نمط أسياخ الشواء Kebab Case مثل <code>page-down</code>.
	</li>
	<li>
		<code>‎.native</code>: يستمع إلى الحدث الأصيل Native في عنصر الجذر أو الغلاف الخارجي Outer-most Wrapping لمكوِّنك.
	</li>
	<li>
		<code>‎.once</code>: يستمع إلى الحدث حتى تشغيله لمرة واحدة فقط لا أكثر.
	</li>
	<li>
		<code>‎.left</code>: يشغِّل المعالج باستخدام حدث زر الفأرة الأيسر فقط.
	</li>
	<li>
		<code>‎.right</code>: يشغِّل المعالج باستخدام حدث زر الفأرة الأيمن فقط.
	</li>
	<li>
		<code>‎.middle</code>: يشغِّل المعالج باستخدام حدث زر الفأرة الأوسط فقط.
	</li>
	<li>
		<code>‎.passive</code>: يكافئ استخدام المعامِل <code>{ passive: true }</code> عند إنشاء مستمع حدث في لغة جافاسكربت الصرفة Vanilla JavaScript باستخدام التابع <code>addEventListener()‎</code>.
	</li>
</ol>
<p>
	سنستخدِم في حالتنا المعالِج <code>‎.prevent</code> لإيقاف إجراء الإرسال الافتراضي للمتصفح، لذا أضِف <code>‎.prevent</code> إلى معالج الإرسال <code>‎@submit</code> في قالبك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_34" style="">
<span class="pun">&lt;</span><span class="pln">form </span><span class="lit">@submit</span><span class="pun">.</span><span class="pln">prevent</span><span class="pun">=</span><span class="str">"onSubmit"</span><span class="pun">&gt;</span></pre>

<p>
	إذا حاولت إرسال الاستمارة الآن، فستلاحظ عدم إعادة تحميل الصفحة، وإذا فتحت الطرفية، فيمكنك رؤية نتائج التابع <code>console.log()‎</code> التي أضفناها ضمن التابع <code>onSubmit()‎</code>.
</p>

<h2>
	ربط البيانات مع الدخل باستخدام الموجه v-model
</h2>

<p>
	نحتاج الآن إلى طريقة للحصول على القيمة الموجودة في حقل الإدخال <code>&lt;input&gt;</code> من الاستمارة لنتمكّن من إضافة عنصر المهام الجديد إلى قائمة بيانات <code>ToDoItems</code>، إذ يكون أول شيء نحتاجه هو الخاصية <code>data</code> في استمارتنا لتعقّب قيمة المهمة.
</p>

<p>
	أضِف التابع <code>data()‎</code> إلى كائن مكون <code>ToDoForm</code> الذي يعيد الحقل <code>label</code>، إذ يمكننا ضبط قيمة الحقل <code>label</code> الأولية بوصفها سلسلة نصية فارغة، ويجب أن يبدو كائن المكوِّن الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_36" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">"form submitted"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      label</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	نحتاج الآن إلى طريقة ما لربط قيمة حقل الإدخال <code>&lt;input&gt;</code> ذي المعرِّف <code>new-todo-input</code> بالحقل <code>label</code>، إذ يمتلك إطار العمل Vue موجِّهًا خاصًا لذلك وهو <code>v-model</code> الذي يرتبط مع خاصية البيانات التي ضبطتها عليه ويبقيها متزامنةً مع حقل الإدخال <code>&lt;input&gt;</code>، في حين يعمل الموجّه <code>v-model</code> مع جميع أنواع حقول الإدخال المختلفة بما في ذلك مربعات الاختيار Checkboxes وأزرار الانتقاء Radios وحقول الاختيار Select Inputs، كما يُستخدَم هذا الموجِّه من خلال إضافة سمة بالصورة <code>v-model="variable"‎</code> إلى العنصر <code>&lt;input&gt;</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_38" style="">
<span class="pun">&lt;</span><span class="pln">input
  type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
  id</span><span class="pun">=</span><span class="str">"new-todo-input"</span><span class="pln">
  name</span><span class="pun">=</span><span class="str">"new-todo"</span><span class="pln">
  autocomplete</span><span class="pun">=</span><span class="str">"off"</span><span class="pln">
  v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">=</span><span class="str">"label"</span><span class="pln"> </span><span class="pun">/&gt;</span></pre>

<p>
	<strong>ملاحظة</strong>: يمكنك مزامنة البيانات مع قيم العنصر <code>&lt;input&gt;</code> باستخدام تركيبة من الأحداث مع سمات <code>v-bind</code> وهذا ما يفعله الموجّه <code>v-model</code>، كما تختلف تركيبة الأحداث والسمات وفقًا لنوع حقل الإدخال وستتطلب شيفرةً برمجيةً أكبر من مجرد استخدام صيغة <code>v-model</code> المختصرة.
</p>

<p>
	لنختبر استخدام الموجِّه <code>v-model</code> عن طريق تسجيل قيمة البيانات المقدَّمة في التابع <code>onSubmit()‎</code>، إذ يمكن الوصول إلى سمات البيانات في المكوّنات باستخدام الكلمة <code>this</code>، وبالتالي يمكن الوصول إلى الحقل <code>label</code> بالصورة <code>this.label</code>، لذا عدّل التابع <code>onSubmit()‎</code> ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_40" style="">
<span class="pln">methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Label value: '</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	عد الآن إلى تطبيقك المُشغَّل، وأضِف نصًا في الحقل <code>&lt;input&gt;</code> ثم انقر على زر "الإضافة Add"، إذ يجب أن ترى القيمة التي أدخلتها مسجلةً في الطرفية كما يلي على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_42" style="">
<span class="typ">Label</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">My</span><span class="pln"> value</span></pre>

<h2>
	تغيير سلوك الموجه v-model باستخدام المعدلات
</h2>

<p>
	يمكننا إضافة معدِّلات Modifiers لتغيير سلوك الموجِّه <code>v-model</code> بطريقة مماثلة لمعدِّلات الأحداث، ومن أبزر هذه المعدِّلات:
</p>

<ul>
<li>
		<code>‎.trim</code>: يزيل المسافة الفارغة الموجودة قبل نص الإدخال أو بعده، ويمكننا إضافة هذا المُعدِّل إلى تعليمة <code>v-model</code> بالصورة <code>v-model.trim="label"‎</code>
	</li>
	<li>
		<code>‎.lazy</code>: يتغير هذا المعدِّل عندما يتزامن <code>v-model</code> مع قيمة نص حقل الإدخال، كما يمكن مزامنة الموجِّه <code>v-model</code> عن طريق تحديث المتغير الذي يستخدم الأحداث، بينما تحدُث هذه المزامنة مع نص حقل الإدخال باستخدام الحدث <code>input</code>، ويعني ذلك أنّ إطار عمل Vue يزامن البيانات بعد كل ضغطة مفتاح، في حين يتسبب المعدِّل <code>‎.lazy</code> في أن يستخدِم الموجّه <code>v-model</code> الحدث <code>change</code> بدلًا من ذلك، وهذا يعني أنّ Vue لن يزامن البيانات إلّا عندما يفقد حقل الإدخال التركيز أو عند إرسال الاستمارة، وهذا منطقي أكثر لأننا نحتاج إلى البيانات النهائية فقط.
	</li>
</ul>
<p>
	<strong>ملاحظة</strong>: يمكن استخدام المعدِّلَين <code>‎.trim</code> و<code>‎.lazy</code> مع بعضهما البعض من خلال استخدامهما بالشكل <code>v-model.lazy.trim="label"‎</code>.
</p>

<p>
	عدّل السمة <code>v-model</code> إلى سلسلة <code>lazy</code> و <code>trim</code> كما هو موضَّح أعلاه، ثم اختبر تطبيقك مرةً أخرى، وجرّب إرسال قيمة بمسافة فارغة في كل نهاية مثلًا.
</p>

<h2>
	تمرير البيانات إلى العناصر الآباء مع الأحداث المخصصة
</h2>

<p>
	يجب الآن تمرير عنصر المهام الذي أنشأناه إلى المكوِّن <code>App</code> من خلال جعل المكوِّن <code>ToDoForm</code> يصدر حدثًا مخصَّصًا يمرِّر البيانات، وجعل المكون <code>App</code> يستمع إلى هذا الحدث، وتعمل هذه الطريقة بصورة مشابهة جدًا للأحداث الأصيلة مع عناصر HTML، إذ يمكن للمكوِّن الابن إصدار حدث يمكن الاستماع إليه باستخدام الموجِّه <code>v-on</code>.
</p>

<p>
	لنضِف الحدث <code>todo-added</code> إلى الحدث <code>onSubmit</code> الخاص بالمكوِّن <code>ToDoForm</code>، كما يمكن إصدار الأحداث المخصَّصة بالصورة <code>this.$emit("event-name")‎</code>، ويجدر بالذكر أنّ معالجات الأحداث حساسة لحالة الأحرف ولا يمكن أن تتضمن مسافات، وتُحوَّل قوالب Vue إلى أحرف صغيرة، مما يعني أنها لا تستطيع الاستماع إلى الأحداث المُسمَّاة بأحرف كبيرة.
</p>

<p>
	ضَع ما يلي بدلًا من التابع <code>console.log()‎</code> الموجود في التابع <code>onSubmit()‎</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_44" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">"todo-added"</span><span class="pun">);</span></pre>

<p>
	ارجع بعد ذلك إلى المكوِّن <code>App.vue</code> وأضِف الخاصية <code>methods</code> إلى كائن المكوِّن الذي يحتوي على التابع <code>addToDo()‎</code> كما هو موضّح أدناه، إذ يمكن لهذا التابع فقط إظهار العبارة <code>To-do added</code> على الطرفية حاليًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_46" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">ToDoItem</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">ToDoForm</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
 data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">ToDoItems</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln">uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Learn Vue'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln">uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Create a Vue project with the CLI'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln">uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Have fun'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln">uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Create a to-do list'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    addToDo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'To-do added'</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	أضِف بعد ذلك مستمع حدث إلى الحدث <code>todo-added</code> في العنصر <code>&lt;to-do-form&gt;&lt;/to-do-form&gt;</code>، إذ يستدعي هذا المستمع التابع <code>addToDo()‎</code> عند إطلاق الحدث، وسيبدو المستمع بالصورة <code>‎@todo-added="addToDo"‎</code> باستخدام الاختصار <code>@</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_48" style="">
<span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">form </span><span class="lit">@todo</span><span class="pun">-</span><span class="pln">added</span><span class="pun">=</span><span class="str">"addToDo"</span><span class="pun">&gt;&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">form</span><span class="pun">&gt;</span></pre>

<p>
	يجب أن ترى سجل الطرفية من التابع <code>addToDo()‎</code> عند إرسال المكوِّن <code>ToDoForm</code>، ويُعَدّ ذلك أمرًا جيدًا، لكننا ما زلنا لا نعيد أيّ بيانات إلى المكوِّن <code>App.vue</code>، ويمكن ذلك عن طريق إعادة وسائط إضافية إلى الدالة <code>this.$emit()‎</code> في المكوِّن <code>ToDoForm</code>، إذ نريد في حالتنا تمرير بيانات العنصر <code>label</code> مع الحدث عند إطلاقه من خلال تضمين البيانات التي نريد تمريرها بوصفها معاملًا آخرًا في التابع <code>‎$emit()‎</code> بالصورة <code>this.$emit("todo-added", this.label)‎</code>، وهذا مشابه لكيفية تضمين أحداث جافاسكربت الأصيلة للبيانات باستثناء أنّ أحداث Vue المخصَّصة التي لا تتضمن أيّ كائن حدث افتراضيًا، وبالتالي سيتطابق الحدث المنطلق مع أيّ كائن ترسله مباشرةً، كما سيكون كائن الحدث في حالتنا سلسلةً نصيةً فقط، لذا عدِّل التابع <code>onSubmit()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_50" style="">
<span class="pln">onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'todo-added'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن التقاط هذه البيانات ضمن المكوِّن <code>App.vue</code> من خلال إضافة معامِل إلى التابع <code>addToDo()‎</code> الذي يتضمن عنصر <code>label</code> خاص بعنصر المهام الجديد، لذا ارجع إلى المكوِّن <code>App.vue</code> وعدّله ليبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_52" style="">
<span class="pln">methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  addToDo</span><span class="pun">(</span><span class="pln">toDoLabel</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'To-do added:'</span><span class="pun">,</span><span class="pln"> toDoLabel</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا اختبرت استمارتك مرةً أخرى، فسترى أنّ أيّ نص تدخله مسجَّل في الطرفية عند الإرسال، كما يمرِّر Vue تلقائيًا الوسائط بعد أن يكون اسم الحدث في <code>this.$emit()‎</code> هو معالِج الأحداث خاصتك.
</p>

<h2>
	إضافة المهام الجديدة إلى بياناتنا
</h2>

<p>
	يجب الآن إضافة عنصر يمثِّل بيانات المكوِّن <code>ToDoForm</code> التي أصبحت متوفرةً في المكوِّن <code>App.vue</code> في المصفوفة <code>ToDoItems</code>، ويمكن ذلك عن طريق دفع كائن عنصر مهام جديد إلى المصفوفة التي تحتوي على البيانات الجديدة.
</p>

<p>
	عدِّل التابع <code>addToDo()‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_54" style="">
<span class="pln">addToDo</span><span class="pun">(</span><span class="pln">toDoLabel</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">ToDoItems</span><span class="pun">.</span><span class="pln">push</span><span class="pun">({</span><span class="pln">id</span><span class="pun">:</span><span class="pln">uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> toDoLabel</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	اختبر الاستمارة مرةً أخرى، إذ يُفترَض أن ترى عناصر مهام جديدة تُلحَق بنهاية القائمة، وإذا أرسلتَ الاستمارة وحقل الإدخال فارغ، فستُضاف عناصر المهام التي لا تحتوي على نص إلى القائمة، ويمكن إصلاح ذلك من خلال منع تشغيل الحدث <code>todo-added</code> عندما يكون الاسم فارغًا، وبما أنّ الاسم قد أزيل باستخدام الموجِّه <code>‎.trim</code>، فيجب اختبار السلسلة النصية الفارغة فقط، لذا ارجع إلى المكوِّن <code>ToDoForm</code> وعدِّل التابع <code>onSubmit()‎</code> كما يلي، وإذا كانت قيمة الحقل <code>label</code> فارغةً، فيجب عدم إصدار الحدث <code>todo-added</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_56" style="">
<span class="pln">onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label </span><span class="pun">===</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'todo-added'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	جرّب استمارتك مرةً أخرى، إذ لن تتمكّن الآن من إضافة عناصر فارغة إلى قائمة المهام.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="105666" href="https://academy.hsoub.com/uploads/monthly_2022_08/02_rendered-form-with-new-items.png.bca7701a586629aeffc87f02dc196baa.png" rel=""><img alt="02_rendered-form-with-new-items.png" class="ipsImage ipsImage_thumbnailed" data-fileid="105666" data-unique="hxu2c6f3o" src="https://academy.hsoub.com/uploads/monthly_2022_08/02_rendered-form-with-new-items.png.bca7701a586629aeffc87f02dc196baa.png" style="width: 400px; height: auto;"></a>
</p>

<h2>
	استخدام الموجه v-model لتحديث قيمة حقل الإدخال
</h2>

<p>
	لا يزال العنصر <code>&lt;input&gt;</code> يحتوي على القيمة القديمة بعد الإرسال، ويمكن إصلاح ذلك لأننا نستخدم الموجّه <code>v-model</code> لربط البيانات بالعنصر <code>&lt;input&gt;</code> في المكوِّن <code>ToDoForm</code>، فإذا ضبطنا معامِل الاسم <code>name</code> ليكون سلسلة نصية فارغة، فسيُحدَّث حقل الإدخال.
</p>

<p>
	عدِّل التابع <code>onSubmit()‎</code> الخاص بالمكوِّن <code>ToDoForm</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1108_60" style="">
<span class="pln">onSubmit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label </span><span class="pun">===</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'todo-added'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا نقرتَ الآن على زر "الإضافة Add"، فسيمسح حقل إدخال المهمة الجديدة "new-todo-input" نفسه.
</p>

<h2>
	الخلاصة
</h2>

<p>
	يمكننا الآن إضافة عناصر المهام إلى استمارتنا، وبالتالي بدأ تطبيقنا الآن يصبح تفاعليًا، ولكننا تجاهلنا شكله وتنسيقه تمامًا، وسنركز في المقال التالي على إصلاح ذلك، كما سنتعرف على الطرق المختلفة التي يوفرها إطار العمل Vue لمكوّنات التنسيق.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models" rel="external nofollow">Adding a new todo form: Vue events, methods, and models</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%B9%D8%B1%D8%B6-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-vuejs-r1666/" rel="">عرض مكونات Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1665/" rel="">إنشاء المكونات في تطبيق Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-vuejs-r991/" rel="">الموجهات الشرطية والتكرارية في Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1676</guid><pubDate>Tue, 16 Aug 2022 13:33:51 +0000</pubDate></item><item><title>&#x639;&#x631;&#x636; &#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%B9%D8%B1%D8%B6-%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-vuejs-r1666/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/62f78f5b50fc3_---Vue.png.bdb6968568780c0e59c20110592f6e33.png" /></p>

<p>
	لدينا حتى الآن مكوِّن يعمل بنجاح، ونحن الآن جاهزون لإضافة عدة مكوّنات <code>ToDoItem</code> إلى تطبيقنا، إذ سنتعلّم في هذا المقال كيفية إضافة مجموعة من بيانات عناصر المهام إلى المكوِّن <code>App.vue</code> التي سنكرّرها ونعرضها ضمن المكونات <code>ToDoItem</code> باستخدام الموجّه <code>v-for</code>.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكوِّنات Vue بوصفها مجموعةً من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع بنية <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a> الأساسية، وستحتاج إلى طرفية مثبَّت عليها node و <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">npm</a> لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكوّنات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية تكرار مصفوفة من البيانات وتصييرها أو عرضها وإخراجها في مكوّنات متعددة.
	</li>
</ul>
<h2>
	عرض القوائم باستخدام الموجه v-for
</h2>

<p>
	يجب أن نكون قادرين على تصيير عناصر مهام متعددة باستخدام الموجِّه <code>v-for</code> في Vue لكي تكون قائمة المهام فعّالةً، إذ يسمح هذا الموجِّه المبني مسبقًا بتضمين حلقة ضمن قالبنا مع تكرار تصيير ميزة القالب لكل عنصر في المصفوفة، إذ سنستخدِمه للتكرار ضمن مصفوفة من عناصر المهام وعرضها في تطبيقنا ضمن مكوّنات <code>ToDoItem</code> منفصلة.
</p>

<h3>
	إضافة بعض البيانات لعرضها
</h3>

<p>
	يجب أولًا الحصول على مصفوفة من عناصر المهام من خلال إضافة الخاصية <code>data</code> إلى كائن المكوّن <code>App.vue</code>، وتحتوي هذه الخاصية على الحقل <code>ToDoItems</code> الذي تكون قيمته مصفوفةً من عناصر المهام، كما سنضيف لاحقًا آليةً لإضافة عناصر مهام جديدة، ولكن يمكننا البدء ببعض عناصر المهام المقلِّدة Mock Items، إذ سيُمثَّل كل عنصر من عناصر المهام بكائن له الخاصيتان <code>name</code> و <code>done</code>.
</p>

<p>
	أضِف بعض نماذج عناصر المهام كما يلي، وبالتالي تكون لديك بعض البيانات المتاحة للتصيير باستخدام الموجّه <code>v-for</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8904_8" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">ToDoItem</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">ToDoItems</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Learn Vue'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Create a Vue project with the CLI'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Have fun'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Create a to-do list'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يمكننا الآن بعد أن أصبح لدينا قائمة بالعناصر، استخدام الموجِّه <code>v-for</code> لعرض هذه العناصر، إذ تُطبَّق الموجَّهات Directives على العناصر مثل السمات الأخرى، كما يمكنك في حالة الموجِّه <code>v-for</code> استخدام صيغة خاصة مشابهة لحلقة <code>for...in</code> في جافاسكربت هي <code>v-for="item in items"‎</code>، إذ تُعَدّ <code>items</code> هي المصفوفة التي نريد تكرار عناصرها؛ أما <code>item</code>، فهو مرجع للعنصر الحالي في المصفوفة.
</p>

<p>
	يرتبط الموجِّه <code>v-for</code> بالعنصر الذي تريد تكراره، ويصيّر ذلك العنصر وأبناؤه، كما نريد في حالتنا عرض العنصر <code>&lt;li&gt;</code> لكل عنصر مهمةً ضمن المصفوفة <code>ToDoItems</code>، ثم نريد تمرير البيانات من كل عنصر مهمة إلى المكوِّن <code>ToDoItem</code>.
</p>

<h3>
	السمة key
</h3>

<p>
	هناك جزء آخر من الصيغة المُستخدَمة مع الموجِّه <code>v-for</code> يجب معرفته وهو السمة <code>key</code>، إذ يحاول Vue تحسين تصيير العناصر في القائمة من خلال تصحيح عناصر القائمة حتى لا يعيد إنشاءها في كل مرة تتغير فيها القائمة، لذلك يحتاج إلى "مفتاح key" فريد للعنصر نفسه الذي يرتبط مع الموجِّه <code>v-for</code> للتأكد من أنه يعيد استخدام عناصر القائمة بطريقة مناسبة.
</p>

<p>
	يجب أن تكون قيم السمات <code>key</code> سلسلةً نصيةً أو قيمًا عدديةً للتأكد من أنّ Vue يمكنه الموازنة بين هذه السمات بدقة، كما يمكن أن يكون استخدام حقل الاسم <code>name</code> أمرًا رائعًا، ولكن يتحكّم به إدخال المستخدِم، مما يعني أنه لا يمكننا ضمان أن تكون الأسماء فريدةً، كما يمكننا استخدام التابع <code>lodash.uniqueid()‎</code> كما فعلنا في <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1665/" rel="">المقال السابق</a>.
</p>

<p>
	استورد أولًا <code>lodash.uniqueid</code> إلى المكوِّن <code>App</code> بالطريقة نفسها التي استخدمناها مع المكوِّن <code>ToDoItem</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8904_11" style="">
<span class="kwd">import</span><span class="pln"> uniqueId from </span><span class="str">'lodash.uniqueid'</span><span class="pun">;</span></pre>

<p>
	أضِف بعد ذلك حقل المعرّف <code>id</code> لكل عنصر في المصفوفة <code>ToDoItems</code>، وأسند القيمة <code>uniqueId('todo-')‎</code> لكل معرِّف، إذ يجب أن تبدو محتويات العنصر <code>&lt;script&gt;</code> في <code>App.vue</code> الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8904_19" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">ToDoItem</span><span class="pln"> from </span><span class="str">'./components/ToDoItem.vue'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> uniqueId from </span><span class="str">'lodash.uniqueid'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'app'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">ToDoItem</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="typ">ToDoItems</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Learn Vue'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Create a Vue project with the CLI'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Have fun'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">),</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Create a to-do list'</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	أضِف الموجِّه <code>v-for</code> والسمة <code>key</code> إلى العنصر <code>&lt;li&gt;</code> في قالب <code>App.vue</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8904_46" style="">
<span class="tag">&lt;ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"item in ToDoItems"</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;to-do-item</span><span class="pln"> </span><span class="atn">label</span><span class="pun">=</span><span class="atv">"My ToDo Item"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"true"</span><span class="tag">&gt;&lt;/to-do-item&gt;</span><span class="pln">
  </span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	إذا أجرينا هذا التغيير، فيمكن لكل تعبير جافاسكربت بين <a href="https://wiki.hsoub.com/HTML/li" rel="external">وسوم &lt;li&gt;</a> الوصول إلى قيمة <code>item</code> وإلى سمات المكوِّن الأخرى، وهذا يعني أنه يمكننا تمرير حقول كائنات العنصر إلى المكوِّن <code>ToDoItem</code> وتذكّر استخدام صيغة <code>v-bind</code>، ويُعَدّ ذلك مفيدًا حقًا لأننا نريد أن تعرض عناصر المهام خاصيات <code>label</code> بوصفها تسميةً أو عنوانًا لها وليس عنوانًا ثابتًا "My Todo Item"، كما نريد أن تعكس حالة التحديد الخاصيات <code>done</code> بحيث لا تُضبَط دائمًا على القيمة <code>done="false"‎</code>.
</p>

<p>
	عدِّل السمة <code>label="My ToDo Item"‎</code> إلى <code>‎:label="item.label"‎</code> والسمة <code>‎:done="false"‎</code> إلى <code>‎:done="item.done"‎</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8904_26" style="">
<span class="tag">&lt;ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"item in ToDoItems"</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;</span><span class="pln">
     </span><span class="tag">&lt;to-do-item</span><span class="pln"> :</span><span class="atn">label</span><span class="pun">=</span><span class="atv">"item.label"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"item.done"</span><span class="tag">&gt;&lt;/to-do-item&gt;</span><span class="pln">
  </span><span class="tag">&lt;/li&gt;</span><span class="pln">
</span><span class="tag">&lt;/ul&gt;</span></pre>

<p>
	إذا نظرت إلى تطبيقك المُشغَّل الآن، فسيُظهِر عناصر المهام بأسمائها الصحيحة، وإذا فحصت الشيفرة البرمجية، فسترى أنّ جميع المدخلات لها معرِّفات فريدة مأخوذة من الكائن في المكوِّن <code>App</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="105339" href="https://academy.hsoub.com/uploads/monthly_2022_08/01_rendered-todo-items.png.1c5f5e8d143205204a40c3221866ff33.png" rel=""><img alt="01_rendered-todo-items.png" class="ipsImage ipsImage_thumbnailed" data-fileid="105339" data-unique="lf5l4mwsm" src="https://academy.hsoub.com/uploads/monthly_2022_08/01_rendered-todo-items.png.1c5f5e8d143205204a40c3221866ff33.png" style="width: 500px; height: auto;"></a>
</p>

<h2>
	إجراء بعض التعديلات
</h2>

<p>
	يمكنك إجراء عملية إعادة البناء Refactoring هنا، إذ يمكننا تحويل المعرِّف إلى خاصية بدلًا من إنشاء معرِّفات لمربعات الاختيار ضمن المكوِّن <code>ToDoItem</code>، وبالرعم من أنّ ذلك لا يُعَدّ ضروريًا، إلّا أنه يسهّل علينا إدارته نظرًا لأنه يجب إنشاء معرِّف فريد لكل عنصر مهمة على أية حال.
</p>

<ol>
<li>
		أضف خاصية <code>id</code> الجديدة إلى المكون <code>ToDoItem</code>.
	</li>
	<li>
		اجعل هذه الخاصية إجباريةً واجعل نوعها <code>String</code>.
	</li>
	<li>
		احذف الحقل <code>id</code> من السمة <code>data</code> لمنع تعارض الأسماء.
	</li>
	<li>
		لم نَعُد نستخدِم التابع <code>uniqueId</code>، لذلك يجب إزالة السطر التالي، وإلا فسيعطي تطبيقك خطأً.
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8904_30" style="">
<span class="kwd">import</span><span class="pln"> uniqueId from </span><span class="str">'lodash.uniqueid'</span><span class="pun">;‎</span></pre>

<p>
	يجب أن تبدو محتويات العنصر <code>&lt;script&gt;</code> في المكوِّن <code>ToDoItem</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8904_34" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        label</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">},</span><span class="pln">
        done</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pun">},</span><span class="pln">
        id</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           isDone </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">done</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	مرّر <code>item.id</code> الآن في المكون <code>App.vue</code> بوصفه خاصيةً إلى المكوِّن <code>ToDoItem</code>، إذ يجب أن يبدو قالب <code>App.vue</code> الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8904_44" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">My To-Do List</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;ul&gt;</span><span class="pln">
      </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"item in ToDoItems"</span><span class="pln"> :</span><span class="atn">key</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;to-do-item</span><span class="pln"> :</span><span class="atn">label</span><span class="pun">=</span><span class="atv">"item.label"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"item.done"</span><span class="pln"> :</span><span class="atn">id</span><span class="pun">=</span><span class="atv">"item.id"</span><span class="tag">&gt;&lt;/to-do-item&gt;</span><span class="pln">
      </span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span></pre>

<p>
	إذا نظرت إلى موقعك المُصيَّر الآن، فيجب أن يبدو كما هو، ولكن تعني عملية إعادة البناء أن معرّفنا <code>id</code> مأخوذ من البيانات الموجودة ضمن <code>App.vue</code> وهو مُمرَّر إلى المكون <code>ToDoItem</code> بوصفه خاصية Prop مثل أي شيء آخر، لذلك أصبحت الأمور الآن منطقيةً ومتناسقةً أكثر.
</p>

<h2>
	الخلاصة
</h2>

<p>
	لدينا الآن عينة من البيانات وحلقة تأخذ كل جزء من هذه البيانات وتصيّره ضمن المكوِّن <code>ToDoItem</code> في تطبيقنا، إذ يجب الآن السماح لمستخدمينا بإدخال عناصر مهامهم في التطبيق، ولذلك سنحتاج إلى نص حقل الإدخال <code><a href="https://wiki.hsoub.com/HTML/input" rel="external">&lt;input&gt;</a></code> وحدث يُطلَق عند إرسال البيانات وتابع للإطلاق بهدف إضافة البيانات وتصيير القائمة بالإضافة إلى نموذج للتحكم في البيانات، وهذا هو موضوعنا في المقال التالي.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists" rel="external nofollow">Rendering a list of Vue components</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1665/" rel="">إنشاء المكونات في تطبيق Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/" rel="">مدخل إلى التعامل مع المكونات في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">أساسيات إطار العمل Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1666</guid><pubDate>Sat, 13 Aug 2022 12:01:25 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-r1665/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/62f78b14a59ca_-------Vue.png.20bf44076769070622341eea8ec8624a.png" /></p>

<p>
	حان الوقت الآن للتعمق أكثر في <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-vuejs-r989/" rel="">إطار العمل Vue</a> وإنشاء مكوّن مخصَّص، إذ سنبدأ بإنشاء مكوِّن لتمثيل كل عنصر في قائمة المهام، كما سنتعرّف على بعض المفاهيم المهمة مثل استدعاء المكونات ضمن مكونات أخرى وتمرير البيانات إليها باستخدام الخاصيات Props وحفظ حالة البيانات.
</p>

<p>
	<strong>ملاحظة</strong>: إذا كنت بحاجة إلى التحقق من شيفرتك مقابل نسخة شيفرتنا، فيمكنك العثور على نسخة نهائية من نموذج شيفرة تطبيق Vue في <a href="https://github.com/mdn/todo-vue" rel="external nofollow">المستودع todo-vue</a> أو يمكنك الحصول على <a href="https://mdn.github.io/todo-vue/dist/" rel="external nofollow">إصدار حي وقيد التشغيل منه</a>.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكونات Vue بوصفها مجموعة من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع بنية <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a> الأساسية، وستحتاج إلى طرفية مثبَّت عليها node و <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">npm</a> لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكونات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: تعلّم كيفية إنشاء مكوِّن Vue وتصييره ضمن مكوِّن آخر، وتمرير البيانات إليه باستخدام الخاصيات، وحفظ حالته.
	</li>
</ul>
<h2>
	إنشاء المكون ToDoItem
</h2>

<p>
	لننشئ مكوننا الأول الذي سيعرض عنصر مهمة واحدًا، إذ سنستخدمه لبناء قائمة المهام.
</p>

<ol>
<li>
		أنشئ ملفًا جديدًا بالاسم ToDoItem.vue في المجلد moz-todo-vue/src/components، ثم افتح الملف في محرّر الشيفرات.
	</li>
	<li>
		أنشئ قسم قالب المكوِّن من خلال إضافة العنصر <code>&lt;template&gt;&lt;/template&gt;</code> في أعلى الملف.
	</li>
	<li>
		أنشئ القسم <code>&lt;script&gt;&lt;/script&gt;</code> بعد قسم القالب، ثم أضف فيه كائن تصدير افتراضي <code>export default {}‎</code>، وهو كائن مكوِّنك.
	</li>
</ol>
<p>
	يجب أن يبدو ملفك الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_11" style="">
 <span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{};</span><span class="pln"> </span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	يمكننا الآن إضافة محتوى فعلي إلى الملف ToDoItem، إذ يُسمَح حاليًا لقوالب Vue بإضافة عنصر جذر واحد فقط، كما يجب استخدام عنصر واحد لتغليف كل شيء ضمن قسم القالب، ولكن سيتغير ذلك في الإصدار رقم 3 من Vue،إذ سنستخدِم العنصر <code>&lt;div&gt;</code> لهذا العنصر الجذر.
</p>

<ol>
<li>
		أضف عنصر <code>&lt;div&gt;</code> فارغ ضمن قالب المكوِّن.
	</li>
	<li>
		أضِف مربع اختيار وعنوانًا <code>label</code> مقابلًا ضمن العنصر <code>&lt;div&gt;</code>. أضِف السمة <code>id</code> إلى مربع الاختيار، والسمة <code>for</code> التي تربط مربع الاختيار مع العنوان <code>label</code> كما هو موضّح فيما يلي:
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_13" style="">
 <span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pln"> id</span><span class="pun">=</span><span class="str">"todo-item"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">label </span><span class="kwd">for</span><span class="pun">=</span><span class="str">"todo-item"</span><span class="pun">&gt;</span><span class="typ">My</span><span class="pln"> </span><span class="typ">Todo</span><span class="pln"> </span><span class="typ">Item</span><span class="pun">&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span></pre>

<h3>
	استخدام المكون TodoItem ضمن تطبيقك
</h3>

<p>
	لم نضِف المكوِّن إلى تطبيقنا حتى الآن، لذلك لا توجد طريقة لاختباره ومعرفة ما إذا كان كل شيء على ما يرام أم لا، إذًا لنضفه الآن.
</p>

<ol>
<li>
		افتح الملف App.vue مرة أخرى.
	</li>
	<li>
		أضِف السطر التالي لاستيراد المكون <code>ToDoItem</code> في أعلى الوسم <code>&lt;script&gt;</code>:
	</li>
</ol>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_15" style="">
 <span class="kwd">import</span><span class="pln"> </span><span class="typ">ToDoItem</span><span class="pln"> from </span><span class="str">'./components/ToDoItem.vue'</span><span class="pun">;</span></pre>

<ol start="3">
<li>
		أضِف الخاصية <code>components</code> ضمن كائن المكوِّن ثم أضِف ضمنها المكوِّن <code>ToDoItem</code> لتسجيله.
	</li>
</ol>
<p>
	يجب أن تبدو محتويات الوسم <code>&lt;script&gt;</code> الآن كما يلي:
</p>

<pre class="ipsCode">
 import ToDoItem from './components/ToDoItem.vue'; export default { name: 'app', components: { ToDoItem } }; </pre>

<p>
	هذه هي الطريقة نفسها التي سُجِّل بها المكوِّن <code>HelloWorld</code> بواسطة واجهة CLI الخاصة بإطار العمل Vue سابقًا.
</p>

<p>
	يمكنك تصيير المكوِّن <code>ToDoItem</code> فعليًا في التطبيق من خلال الانتقال إلى العنصر <code>&lt;template&gt;</code> واستدعائه بوصفه عنصر بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_17" style="">
<span class="pln"> </span><span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="pln"> </span></pre>

<p>
	ولاحظ أنّ اسم ملف المكوِّن وتمثيله في جافاسكربت يكون دائمًا في حالة أحرف باسكال PascalCase مثل <code>ToDoList</code>، ويكون العنصر المخصّص المكافئ دائمًا في نمط أحرف أسياخ الشواء Kebab-case مثل <code>&lt;to-do-list&gt;</code>.
</p>

<ol>
<li>
		أنشئ قائمةً غير مرتبة <code><a href="https://wiki.hsoub.com/HTML/ul" rel="external">&lt;ul&gt;</a></code> بعد العنصر <code><a href="https://wiki.hsoub.com/HTML/h1-h6" rel="external">&lt;h1&gt;</a></code> تحتوي على عنصر قائمة واحد <code><a href="https://wiki.hsoub.com/HTML/li" rel="external">&lt;li&gt;</a></code>.
	</li>
	<li>
		أضِف العنصر <code>&lt;to-do-item&gt;&lt;/to-do-item&gt;</code> ضمن عنصر القائمة.
	</li>
</ol>
<p>
	يجب أن تبدو محتويات العنصر <code>&lt;template&gt;</code> في الملف App.vue الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_22" style="">
<span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"app"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">To</span><span class="pun">-</span><span class="typ">Do</span><span class="pln"> </span><span class="typ">List</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<p>
	إذا تحقّقتَ من تطبيقك المُصيَّر مرةً أخرى، فيجب أن ترى الآن العنصر <code>ToDoItem</code> المُصيَّر الذي يتكون من مربع اختيار وعنوان <code>label</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="105336" href="https://academy.hsoub.com/uploads/monthly_2022_08/01_rendered-todoitem.png.88ccb75848fc3aab26835a193c71d8b5.png" rel=""><img alt="01_rendered-todoitem.png" class="ipsImage ipsImage_thumbnailed" data-fileid="105336" data-unique="zlhl6hwib" src="https://academy.hsoub.com/uploads/monthly_2022_08/01_rendered-todoitem.png.88ccb75848fc3aab26835a193c71d8b5.png"></a>
</p>

<h2>
	إضافة خاصيات للمكونات
</h2>

<p>
	لا يزال المكوِّن <code>ToDoItem</code> غير مفيد للغاية لأنه يمكننا تضمينه مرةً واحدة فقط في الصفحة، إذ يجب أن تكون المعرّفات فريدةً، وليس لدينا طريقة لضبط نص العنوان ولا يُعَدّ ذلك ديناميكيًا.
</p>

<p>
	ما نحتاجه الآن هو حالة المكوِّن التي يمكن تحقيقها من خلال إضافة الخاصيات Props إلى المكوِّن، إذ تشبه الخاصيات مدخلات دالة ما، وتعطي قيمة الخاصية للمكونات حالة أولية تؤثر على عرضها.
</p>

<h3>
	تسجيل الخاصيات
</h3>

<p>
	هناك طريقتان لتسجيل الخاصيات في Vue هما:
</p>

<ul>
<li>
		الطريقة الأولى هي سرد الخاصيات بوصفها مصفوفةً من السلاسل النصية فقط، إذ تقابل كل مدخلة في المصفوفة اسم خاصية.
	</li>
	<li>
		الطريقة الثانية هي تعريف الخاصيات بوصفها كائنات، إذ يقابل كل مفتاح اسم الخاصية، كما يسمح سرد الخاصيات بوصفها كائنات بتحديد القيم الافتراضية وتحديد الخاصيات بأنها إجبارية وتطبيق أنواع الكائن الأساسية (أنواع جافاسكربت الأولية تحديدًا)، بالإضافة إلى إجراء تحقق بسيط من صحة الخاصية.
	</li>
</ul>
<p>
	<strong>ملاحظة</strong>: لا يحدث التحقق من صحة الخاصية إلا في وضع التطوير، لذلك لا يمكنك الاعتماد عليها بصورة صارمة في عملية الإنتاج، كما تُستدعَى دوال التحقق من صحة الخاصية قبل إنشاء نسخة من المكوِّن، لذلك لا يمكنها الوصول إلى حالة المكوِّن أو الخاصيات الأخرى، وسنستخدِم تابع تسجيل الكائن بالنسبة لهذا المكوِّن.
</p>

<p>
	ارجع إلى الملف ToDoItem.vue، ثم أضِف الخاصية <code>props</code> ضمن كائن التصدير <code>default {}‎</code> الذي يحتوي على كائن فارغ، وبعدها أضف ضمن هذا الكائن خاصيتين مع المفتاحين <code>label</code> و <code>done</code>، وتذكَّر أنّ قيمة المفتاح <code>label</code> يجب أن تكون كائنًا مع خاصيتن (أو Props كما يطلق عليها في سياق توفرهما للمكوّنات) وهما:
</p>

<ol>
<li>
		الأولى هي الخاصية <code>required</code> التي ستكون لها القيمة <code>true</code>مما يخبر Vue أننا نتوقع أن يكون لكل نسخة من هذا المكوِّن حقل عنوان أو تسمية <code>label</code>، وسيعطي Vue تحذيرًا إذا لم يتضمن المكوِّن <code>ToDoItem</code> على حقل عنوان.
	</li>
	<li>
		الثانية هي خاصية النوع <code>type</code>. اضبط قيمة هذه الخاصية على نوع <a href="https://www.bing.com/search?q=site%3Aacademy.hsoub.com+%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA&amp;go=Rechercher&amp;qs=ds&amp;form=QBRE" rel="external nofollow">جافاسكربت</a> <code>String</code> (لاحظ الحرف الكبير "S")، وهذا يخبر Vue أننا نتوقع أن تكون قيمة هذه الخاصية سلسلةً نصيةً.
	</li>
</ol>
<p>
	أما بالنسبة للخاصية <code>done</code>، فأضِف أولًا الحقل <code>default</code> مع القيمة <code>false</code>، وهذا يعني أنّ الخاصية <code>done</code> ستكون لها القيمة <code>false</code> عند عدم تمريرها إلى المكوِّن <code>ToDoItem</code>، وضَع في الحسبان أنّ هذا ليس مطلوبًا، إذ نحتاج فقط إلى الحقل <code>default</code> مع الخاصيات غير المطلوبة، وأضف بعد ذلك حقل النوع <code>type </code>مع القيمة <code>Boolean</code>، وهذا يخبر Vue أننا نتوقع أن يكون لخاصية القيمة value <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r672/" rel="">النوع المنطقي boolean في جافاسكربت</a>.
</p>

<p>
	يجب أن يبدو كائن المكوِّن الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_26" style="">
<span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      label</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
      done</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<h3>
	استخدام الخاصيات المسجلة
</h3>

<p>
	يمكننا الآن بعد تعريف هذه الخاصيات ضمن كائن المكوِّن استخدام هذه القيم المتغيرة في قالبنا ولنبدأ بإضافة الخاصية <code>label</code> إلى قالب المكوِّن.
</p>

<p>
	ضع مكان محتويات العنصر <code>&lt;label&gt;</code> القيمة <code>{{label}}</code> في عنصر القالب <code>&lt;template&gt;</code>، إذ تُعَدّ <code>{{}}</code> صيغة قوالب خاصة في Vue تتيح طباعة نتيجة تعابير جافاسكربت المُعرَّفة في الصنف Class ضمن القالب، بما في ذلك القيم والتوابع، كما يُعرَض المحتوى ضمن <code>{{}}</code> بوصفه نصًا وليس شيفرة HTML، وبالتالي سنطبع قيمة الخاصية <code>label</code> في هذه الحالة.
</p>

<p>
	يجب أن يبدو قسم قالب المكوِّن الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_28" style="">
<span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pln"> id</span><span class="pun">=</span><span class="str">"todo-item"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">label </span><span class="kwd">for</span><span class="pun">=</span><span class="str">"todo-item"</span><span class="pun">&gt;{{</span><span class="pln">label</span><span class="pun">}}&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span></pre>

<p>
	ارجع إلى متصفحك وسترى عنصر المهام مُصيَّرًا كما كان سابقًا، ولكن بدون العنصر <code>label</code>، وانتقل إلى أدوات التطوير DevTools في متصفحك وسترى تحذيرًا في الطرفية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_30" style="">
<span class="pun">[</span><span class="typ">Vue</span><span class="pln"> warn</span><span class="pun">]:</span><span class="pln"> </span><span class="typ">Missing</span><span class="pln"> required prop</span><span class="pun">:</span><span class="pln"> </span><span class="str">"label"</span><span class="pln">

found in

</span><span class="pun">---&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">ToDoItem</span><span class="pun">&gt;</span><span class="pln"> at src</span><span class="pun">/</span><span class="pln">components</span><span class="pun">/</span><span class="typ">ToDoItem</span><span class="pun">.</span><span class="pln">vue
        </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pun">&gt;</span><span class="pln"> at src</span><span class="pun">/</span><span class="typ">App</span><span class="pun">.</span><span class="pln">vue
          </span><span class="pun">&lt;</span><span class="typ">Root</span><span class="pun">&gt;</span></pre>

<p>
	يكون هذا بسبب أننا ميّزنا الخاصية <code>label</code> بوصفها خاصيةً مطلوبةً أو إجباريةً، لكننا لم نعطِ المكوِّن هذه الخاصية مطلقًا، إذ حدّدنا المكان الذي نريد استخدامه ضمن القالب، لكننا لم نمرّره إلى المكوِّن عند استدعائه، إذًا لنصلح ذلك.
</p>

<p>
	أضف الخاصية <code>label</code> إلى المكوِّن <code>&lt;to-do-item&gt;</code> في الملف App.vue مثل سمة HTML العادية تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_32" style="">
<span class="pun">&lt;</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item label</span><span class="pun">=</span><span class="str">"My ToDo Item"</span><span class="pun">&gt;&lt;/</span><span class="pln">to</span><span class="pun">-</span><span class="kwd">do</span><span class="pun">-</span><span class="pln">item</span><span class="pun">&gt;</span></pre>

<p>
	سترى الآن العنصر <code>label</code> في تطبيقك دون تحذير في الطرفية مرةً أخرى.
</p>

<h2>
	كائن الخاصية data في Vue
</h2>

<p>
	إذا عدّلتَ قيمة الخاصية <code>label</code> المُمرَّرة إلى المكون <code>&lt;to-do-item&gt;</code> في تطبيقك، فيجب أن تراها مُحدَّثةً.
</p>

<p>
	لدينا الآن مربع اختيار مع عنصر <code>label</code> قابل للتحديث، ولكننا لا نطبّق حاليًا أيّ شيء باستخدام الخاصية <code>done</code>، إذ يمكننا تحديد مربعات الاختيار في واجهة المستخدِم، ولكن لا يوجد مكان في التطبيق نسجل فيه ما إذا كان عنصر المهام المطلوب قد اكتمل فعليًا أم لا.
</p>

<p>
	يمكنك تحقيق ذلك من خلال ربط الخاصية <code>done</code> الخاصة بالمكوِّن مع السمة <code>checked</code> في <a href="https://wiki.hsoub.com/HTML/input" rel="external">العنصر &lt;input</a><code>&gt;</code>، بحيث يمكن أن تكون بمثابة سجل لما إذا كان مربع الاختيار محددًا أم لا، إذ يجب أن تعمل الخاصيات بوصفها رابط بيانات أحادي الاتجاه، ويجب ألّا يغير المكوِّن قيمة خاصياته أبدًا، إذ يمكن أن تجعل خاصيات تعديل المكونات تنقيح الأخطاء تحديًا، فإذا مُرِّرت قيمةً إلى عدة أبناء، فيمكن أن يكون تتبُّع مصدر تغييرات هذه القيمة أمرًا صعبًا، كما يمكن أن يؤدي تغيير الخاصيات إلى إعادة تصيير المكوّنات، لذا فسيؤدي تغيّر خاصيات المكوِّن إلى إعادة تصييره، مما يؤدي بدوره إلى حدوث التغيّر مرةً أخرى.
</p>

<p>
	يمكننا حل هذه المشكلة من خلال إدارة الحالة <code>done</code> باستخدام الخاصية <code>data</code> في Vue، إذ تُعَدّ الخاصية <code>data</code> المكان الذي يمكنك من خلاله إدارة حالة المكوِّن المحلية، فهي توجد ضمن كائن المكوِّن جنبًا إلى جنب مع الخاصية <code>props</code> ولها البنية التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_37" style="">
<span class="pln">data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    key</span><span class="pun">:</span><span class="pln"> value
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أنّ الخاصية <code>data</code> هي دالة للحفاظ على قيم البيانات فريدة لكل نسخة من المكوِّن في وقت التشغيل، إذ تُستدعَى الدالة بصورة منفصلة لكل نسخة من المكوِّن. فإذا عرّفتَ الخاصية <code>data</code> بوصفها كائن فقط، فستشترك جميع نسخ هذا المكوِّن في القيم نفسها، وهذا أحد الآثار الجانبية التي لا نريدها للطريقة التي يسجِّل بها Vue المكوّنات، كما يمكنك استخدام <code>this</code> للوصول إلى خاصيات المكوّن والخاصيات الأخرى من <code>data</code> وسنرى مثالًا عن ذلك لاحقًا.
</p>

<p>
	<strong>ملاحظة</strong>: بما أن الطريقة التي يعمل بها <code>this</code> يمكن استخدامها في الدوال السهمية Arrow Function أو الارتباط بسياق الآباء، فلن تتمكن من الوصول إلى أيّ من السمات الضرورية من <code>data</code> إذا استخدمتَ هذه الدالة، لذلك لا تستخدِمها مع الخاصية <code>data</code>.
</p>

<p>
	لنضِف الخاصية <code>data</code> إلى المكوِّن <code>ToDoItem</code>، إذ سيعيد ذلك كائنًا يحتوي على خاصية واحدة سنسميها <code>isDone</code> التي تكون قيمتها <code>this.done</code>.
</p>

<p>
	عدّل كائن المكوِّن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_40" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    label</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    done</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      isDone</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">done
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يربط Vue جميع خاصياتك بنسخة المكوِّن مباشرةً، لذلك لا يتعين علينا استدعاء <code>this.props.done</code>، ويربط السمات الأخرى مثل <code>data</code> و <code>methods</code> و <code>computed</code> وغيرها مباشرةً بنسخة المكوِّن لجعلها متاحةً لقالبك، لكن يجب الاحتفاظ بالمفاتيح فريدة لهذه السمات، وهذا هو السبب في أننا أطلقنا على سمة <code>data</code> الاسم <code>isDone</code> عوضًا عن <code>done</code>.
</p>

<p>
	يجب الآن ربط الخاصية <code>isDone</code> بالمكوِّن، إذ يملك Vue بنية صيغة لربط تعابير جافاسكربت بعناصر ومكونات HTML بطريقة مشابهة لكيفية استخدام Vue لتعابير <code>{{}}</code> لعرض تعابير جافاسكربت ضمن القوالب، وهذه الصيغة هي <code>v-bind</code> التي تبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_42" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">attribute</span><span class="pun">=</span><span class="str">"expression"</span></pre>

<p>
	وبالتالي ستسبق العبارة <code>v-bind:‎</code> أيّ سمة أو خاصية تريد ربطها، ويمكنك استخدام اختصار للخاصية <code>v-bind</code> في أغلب الأحيان، وهذا الاختصار هو استخدام تقطتين قبل السمة أو الخاصية، لذلك تعمل العبارة <code>‎:attribute="expression"‎</code> بطريقة مشابهة للعبارة <code>v-bind:attribute="expression"‎</code>، لذلك يمكننا استخدام <code>v-bind</code> لربط الخاصية <code>isDone</code> مع السمة <code>checked</code> في العنصر <code>&lt;input&gt;</code> في حالة استخدام مربع اختيار ضمن المكوِّن <code>ToDoItem</code>، كما أنّ الأمرَين التاليَين متكافئان:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6295_44" style="">
<span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-item"</span><span class="pln"> </span><span class="atn">v-bind:checked</span><span class="pun">=</span><span class="atv">"isDone"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

</span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"todo-item"</span><span class="pln"> :</span><span class="atn">checked</span><span class="pun">=</span><span class="atv">"isDone"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	أنت حر في استخدام النمط الذي تريده، ولكن يُفضَّل الحفاظ على كل شيء متسقًا قدر الإمكان، وبما أنّ استخدام صيغة الاختصار أكثر شيوعًا، فسنلتزم بهذا النمط في هذا المقال.
</p>

<p>
	عدّل العنصر <code>&lt;input&gt;</code> الآن ليشمل <code>‎:checked="isDone"‎</code>.
</p>

<p>
	اختبر مكوِّنك عن طريق تمرير <code>‎:done="true"‎</code> إلى استدعاء المكوِّن <code>ToDoItem</code> في الملف App.vue، ولاحظ أنك تحتاج إلى استخدام صيغة <code>v-bind</code>، لأنّ القيمة <code>true</code> ستُمرَّر بوصفها سلسلةً نصيةً بخلاف ذلك، كما يجب تحديد مربع الاختيار المعروض.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6295_46" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">My To-Do List</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;ul&gt;</span><span class="pln">
      </span><span class="tag">&lt;li&gt;</span><span class="pln">
        </span><span class="tag">&lt;to-do-item</span><span class="pln"> </span><span class="atn">label</span><span class="pun">=</span><span class="atv">"My ToDo Item"</span><span class="pln"> :</span><span class="atn">done</span><span class="pun">=</span><span class="atv">"true"</span><span class="tag">&gt;&lt;/to-do-item&gt;</span><span class="pln">
      </span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span></pre>

<p>
	حاول تغيير القيمة <code>true</code> إلى <code>false</code>، ثم أعِد تحميل تطبيقك لترى كيفية تغيّر الحالة.
</p>

<h2>
	إعطاء المهام معرفا فريدا
</h2>

<p>
	رائع، أصبح لدينا الآن مربع اختيار يعمل بنجاح، إذ يمكننا ضبط الحالة برمجيًا، لكن يمكننا حاليًا إضافة مكوِّن <code>ToDoList</code> واحد فقط إلى الصفحة لأن المعرّف <code>id</code> ثابت، مما يؤدي إلى حدوث أخطاء في التقنية المساعدة لأننا بحاجة هذا المعرّف لربط العناوين أو التسميات إلى مربعات الاختيار المقابلة لها بصورة صحيحة، ويمكن إصلاح هذا الخطأ من خلال ضبط المعرّف <code>id</code> برمجيًا في بيانات المكوِّن.
</p>

<p>
	يمكننا استخدام التابع <code>uniqueid()‎</code> الخاص بحزمة Lodash للمساعدة في إبقاء الفهرس فريدًا، إذ تصدِّر هذه الحزمة دالةً تأخذ سلسلةً نصيةً وتضيف عددًا صحيحًا فريدًا إلى نهاية البادئة، وسيكون هذا كافيًا لإبقاء معرِّفات المكوّنات فريدة.
</p>

<p>
	يجب إضافة هذه الحزمة إلى مشروعنا باستخدام npm، لذا أوقف خادمك وأدخِل الأمر التالي في طرفيتك:
</p>

<pre class="ipsCode">
npm install --save lodash.uniqueid
</pre>

<p>
	<strong>ملاحظة</strong>: إذا أردت استخدام yarn، فيمكنك كتابة الأمر <code>yarn add lodash.uniqueid</code>.
</p>

<p>
	يمكننا الآن استيراد هذه الحزمة إلى المكوِّن <code>ToDoItem</code>، لذا أضِف السطر التالي قبل العنصر <code>&lt;script&gt;</code> في الملف ToDoItem.vue:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_48" style="">
<span class="kwd">import</span><span class="pln"> uniqueId from </span><span class="str">'lodash.uniqueid'</span><span class="pun">;</span></pre>

<p>
	أضِف بعد ذلك الحقل <code>id</code> إلى الخاصية <code>data</code> بحيث يبدو كائن المكوِّن بالصورة التالية، إذ يعيد التابع <code>uniqueId()‎</code> البادئة <code>todo-‎</code> مع سلسلة نصية فريدة ملحقَة بها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6295_50" style="">
<span class="kwd">import</span><span class="pln"> uniqueId from </span><span class="str">'lodash.uniqueid'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    label</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> required</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    done</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      isDone</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">done</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> uniqueId</span><span class="pun">(</span><span class="str">'todo-'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	اربط بعد ذلك المعرِّف <code>id</code> مع كل سمة <code>id</code> الخاصة بمربع الاختيار والسمة <code>for</code> الخاصة بالعنوان أو التسمية، وعدِّل السمات <code>id</code> و <code>for</code> الحالية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6295_52" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> :</span><span class="atn">id</span><span class="pun">=</span><span class="atv">"id"</span><span class="pln"> :</span><span class="atn">checked</span><span class="pun">=</span><span class="atv">"isDone"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> :</span><span class="atn">for</span><span class="pun">=</span><span class="atv">"id"</span><span class="tag">&gt;</span><span class="pln">{{label}}</span><span class="tag">&lt;/label&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span></pre>

<h2>
	الخلاصة
</h2>

<p>
	لدينا حتى الآن المكوِّن <code>ToDoItem</code> الذي يعمل بنجاح، ويمكنه تمرير عنوان أو تسمية لعرضها، كما سيخزّن حالته المحدَّدة، وسيُصيَّر مع معرِّف <code>id</code> فريد في كل مرة يُستدعَى فيها، كما يمكنك التحقق مما إذا كانت المعرّفات الفريدة تعمل عن طريق إضافة المزيد من استدعاءات المكونات <code>&lt;to-do-item&gt;</code> مؤقتًا في الملف App.vue ثم التحقق من خرجها المُصيَّر باستخدام أدوات التطوير DevTools في متصفحك.
</p>

<p>
	نحن الآن جاهزون لإضافة عدة مكونات <code>ToDoItem</code> إلى تطبيقنا، إذ سنتعلّم في المقال التالي كيفية إضافة مجموعة من بيانات عناصر المهام إلى المكوِّن <code>App.vue</code>، والتي سنكرّرها ونعرضها ضمن المكوّنات <code>ToDoItem</code> باستخدام الموجّه <code>v-for</code>.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component" rel="external nofollow">Creating our first Vue component</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">مدخل إلى إطار العمل Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/" rel="">مدخل إلى التعامل مع المكونات في Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/" rel="">التعامل مع دخل المستخدم عن طريق نماذج الإدخال في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1665</guid><pubDate>Wed, 24 Aug 2022 16:08:01 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x625;&#x637;&#x627;&#x631; &#x627;&#x644;&#x639;&#x645;&#x644; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs-r1664/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/62f7868ab0687_-----Vue.png.2b7f5bd8c1d5f5ee6ff1c75fc7852606.png" /></p>

<p>
	سنلقي في هذا المقال نظرةً على خلفية <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-vuejs-r989/" rel="">إطار العمل Vue.js</a>، وسنتعلمّ كيفية تثبيته وإنشاء مشروع جديد ودراسة بنية المشروع بأكمله مع مكوّناته، بالإضافة إلى كيفية تشغيله محليًا وتجهيزه للبناء.
</p>

<ul>
<li>
		<strong>المتطلبات الأساسية</strong>: الإلمام بأساسيات لغات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت JavaScript</a>، ومعرفة استخدام <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">سطر الأوامر أو الطرفية</a>، إذ تُكتَب مكونات Vue بوصفها مجموعةً من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع بنية نموذج <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a> الأساسية، كما ستحتاج إلى طرفية مثبَّتٌ عليها node و npm لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكوّنات الملف المفرد Single File Components أو دوال التصيير Render.
	</li>
	<li>
		<strong>الهدف</strong>: إعداد بيئة تطوير Vue المحلية وإنشاء تطبيق بسيط وفهم أساسيات كيفية عمله.
	</li>
</ul>
<p>
	يُعَدّ Vue.js إطار عمل جافاسكربت حديث يوفِّر تسهيلات مفيدةً للتحسين التدريجي على عكس العديد من أطر العمل الأخرى، إذ يمكنك استخدام إطار عمل Vue لتحسين شيفرة HTML الحالية، وبالتالي يمكنك استخدامه بوصفه بديلًا مؤقتًا لمكتبة ما مثل مكتبة <a href="https://wiki.hsoub.com/jQuery" rel="external">jQuery</a>.
</p>

<p>
	كما يمكنك استخدام Vue لكتابة تطبيقات الصفحة الواحدة Single Page Applications -أو SPA اختصارًا-، مما يتيح لك إنشاء شيفرة توصيف يديرها Vue بالكامل، كما يمكن أن يحسّن ذلك من تجربة المطوِّر وأدائه عند التعامل مع التطبيقات المعقّدة، كما يتيح لك الاستفادة من المكتبات للتوجيه من طرف العميل وإدارة الحالة عندما تحتاج ذلك، إذ يتخذ Vue نهجًا وسطيًا لاستخدام الأدوات مثل التوجيه من طرف العميل وإدارة الحالة، في حين يحتفظ فريق Vue الأساسي بالمكتبات المقترحة لهذه الوظائف، إلا أنها ليست مجمعةً مباشرةً ضمنه، مما يتيح اختيار مكتبة إدارة توجيه أو حالة مختلفة إذا ناسبت تطبيقك أكثر.
</p>

<p>
	كما يوفِّر Vue نهجًا تقدميًا لكتابة شيفرة التوصيف، ويتيح مثل معظم الإطارات العمل الأخرى إنشاء كتل قابلة لإعادة الاستخدام من شيفرة التوصيف باستخدام المكونات، كما تُكتَب مكونات Vue باستخدام صيغة قوالب HTML خاصةً، وإذا احتجت إلى تحكِّم أكبر مما تسمح به صيغة HTML، فيمكنك كتابة دوال <a href="https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B5%D9%8A%D8%BA%D8%A9-javascript-syntax-extension-jsx-r777/" rel="">JSX</a> أو <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-r620/" rel="">جافاسكربت</a> الصرفة لتعريف مكوناتك.
</p>

<p>
	يمكن أن ترغب لاحقًا في إبقاء كتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js</a> من أكاديمية حسوب و<a href="https://vuejs.org/v2/api/" rel="external nofollow">توثيق <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> مفتوحَين في تبويبات أخرى، بحيث يمكنك الرجوع إليهما إذا أردتَ مزيدًا من المعلومات حول أيّ موضوع فرعي، كما يمكنك الاطلاع على موازنة جيدة بين Vue والعديد من الأطر الأخرى في <a href="https://vuejs.org/v2/guide/comparison.html" rel="external nofollow">توثيق Vue</a>، ولكن يُحتمَل أن تكون هذه الموازنة منحازة.
</p>

<p>
	هذه المقالة جزء من سلسلة تمهيدية حول إطار العمل Vue.js وإليك كامل مقالات السلسلة:
</p>

<ul>
<li>
		مدخل إلى إطار العمل Vue.js
	</li>
	<li>
		إنشاء المكونات في تطبيق Vue.js
	</li>
	<li>
		عرض مكونات Vue.js
	</li>
	<li>
		شرح مفهوم الأحداث والتوابع والنماذج في Vue.js
	</li>
	<li>
		إضافة تنسيق للمكونات واستعمال الخاصية computed في تطبيق Vue.js
	</li>
	<li>
		العرض الشرطي في إطار العمل Vue.js
	</li>
	<li>
		إدارة العناصر باستخدام خاصيات ref في إطار العمل Vue.js
	</li>
</ul>
<h2>
	تثبيت Vue.js
</h2>

<p>
	يمكنك استخدام إطار عمل Vue في موقع قائم من خلال وضع أحد عناصر <code>&lt;script&gt;</code> التالية في الصفحة، مما يتيح بدء استخدام Vue على المواقع الحالية، لذلك يفتخر Vue بكونه إطار عمل تقدمي، إذ يُعَدّ ذلك خيارًا رائعًا عند نقل مشروع موجود مسبقًا باستخدام مكتبة مثل مكتبة <a href="https://wiki.hsoub.com/jQuery" rel="external">jQuery</a> إلى Vue، وبالتالي يمكنك استخدام الكثير من ميزات Vue الأساسية مثل السمات والمكونات المُخصَّصة وإدارة البيانات.
</p>

<ul>
<li>
		سكربت التطوير Development Script: غير مُحسَّن، ولكنه يتضمن تحذيرات الطرفية، وهذا رائع لعملية التطوير.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_12" style="">
<span class="pun">&lt;</span><span class="pln">script src</span><span class="pun">=</span><span class="str">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<ul>
<li>
		سكربت الإنتاج Production Script: إصدار مُحسَّن، ويتضمّن الحد الأدنى من تحذيرات الطرفية، كما يوصَى بتحديد رقم الإصدار عند تضمين Vue في موقعك بحيث لا تؤدي أيّ تحديثات لإطار العمل إلى تعطيل موقعك المباشر دون علمك.
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_14" style="">
<span class="pun">&lt;</span><span class="pln">script src</span><span class="pun">=</span><span class="str">"https://cdn.jsdelivr.net/npm/vue@2"</span><span class="pun">&gt;&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لكن هذا النهج له بعض القيود، إذ ستحتاج إلى استخدام <a href="https://academy.hsoub.com/programming/javascript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-r1225/" rel="">حزمة NPM</a> الخاصة بإطار عمل Vue لإنشاء تطبيقات أكثر تعقيدًا، مما سيتيح استخدام ميزات Vue المتقدمة والاستفادة من الحزم مثل WebPack، كما توجد واجهة سطر الأوامر CLI لتبسيط عملية التطوير، مما يسهّل إنشاء التطبيقات باستخدام Vue، إذ ستحتاج إلى ما يلي لاستخدام حزمة npm وواجهة CLI:
</p>

<ol>
<li>
		تثبيت Node.js 8.11+‎.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-%D9%85%D8%AF%D9%8A%D8%B1-%D8%A7%D9%84%D8%AD%D8%B2%D9%85-npm-%D9%88-yarn-r1597/" rel="">npm أو yarn</a>.
	</li>
</ol>
<p>
	<strong>ملاحظة</strong>: إن لم تثبّت ما سبق مسبقًا، فتعرف على المزيد حول <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%85%D9%86-%D8%B7%D8%B1%D9%81-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r1471/" rel="">تثبيت npm و Node.js</a>.
</p>

<p>
	شغّل الأمر التالي في طرفيتك لتثبيت CLI:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_18" style="">
<span class="pln">npm install </span><span class="pun">--</span><span class="pln">global </span><span class="lit">@vue</span><span class="pun">/</span><span class="pln">cli</span></pre>

<p>
	أو استخدم yarn:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_20" style="">
<span class="pln">yarn global add </span><span class="lit">@vue</span><span class="pun">/</span><span class="pln">cli</span></pre>

<p>
	يمكنك بعد ذلك فتح الطرفية في المجلد الذي تريد إنشاء المشروع فيه، وتشغيل الأمر <code>vue create &lt;project-name&gt;‎</code>، ثم ستعطيك واجهة CLI قائمةً بإعدادات المشروع التي يمكنك استخدامها، وهناك عدد قليل منها مُعَدّ مسبقًا، ويمكنك إعدادها بنفسك، إذ تتيح لك هذه الخيارات إعداد أشياء مثل شيفرة <a href="https://wiki.hsoub.com/TypeScript" rel="external">TypeScript</a> وكشف الأخطاء المحتمَلة Linting والتوجيه vue-router والاختبار وغير ذلك.
</p>

<h2>
	تهيئة مشروع جديد
</h2>

<p>
	سننشئ نموذجًا لتطبيق قائمة المهام لاستكشاف ميزات Vue المختلفة، إذ سنبدأ باستخدام واجهة سطر أوامر Vue لإنشاء إطار عمل تطبيق جديد لبناء تطبيقنا فيه، لذا اتبع الخطوات التالية:
</p>

<ol>
<li>
		اكتب الأمر <code>cd</code> في الطرفية للانتقال إلى المكان الذي تريد فيه إنشاء تطبيقك، ثم شغّل الأمر <code>vue create moz-todo-vue</code>.
	</li>
	<li>
		استخدم مفاتيح الأسهم ومفتاح <code>Enter</code> لتحديد خيار "تحديد الميزات يدويًا Manually select features".
	</li>
	<li>
		تسمح لك القائمة الأولى التي ستظهر لك باختيار الميزات التي تريد تضمينها في مشروعك، وتأكد من تحديد "Babel" و "Linter / Formatter"، فإذا لم تكن مُحدَّدةً، فاستخدم مفاتيح الأسهم ومفتاح المسافة للتبديل فيما بينها، ثم اضغط <code>Enter</code> للمتابعة.
	</li>
	<li>
		ستحدِّد بعد ذلك إعدادًا للميزة "linter / formatter"، لذا انتقل إلى الخيار "Eslint مع منع الأخطاء فقط Eslint with error prevention only" واضغط على <code>Enter</code> مرةً أخرى، إذ سيساعدنا ذلك على اكتشاف الأخطاء الشائعة دون مبالغة في الصرامة.
	</li>
	<li>
		سيُطلَب منك بعد ذلك ضبط نوع كشف الأخطاء المحتمَلة linting الآلي الذي تريده، لذا حدِّد الخيار "فحص الأخطاء عند الحفظ Lint on save"، مما سيؤدي إلى التحقق من وجود أخطاء عند حفظ ملف ضمن المشروع، ثم اضغط على <code>Enter</code> للمتابعة.
	</li>
	<li>
		ستحدِّد الآن كيف تريد إدارة ملفات الإعداد الخاصة بك، لذا سيضع الخيار "In dedicated config files" إعدادات الضبط الخاصة بك لأشياء مثل ESLint في ملفاتها المخصَّصة، وسيضع الخيار الآخر "In package.json" جميع إعدادات الضبط الخاصة بك في الملف package.json الخاص بالتطبيق، لذا حدِّد الخيار "In dedicated config files" واضغط على <code>Enter</code>.
	</li>
	<li>
		أخيرًا، ستُسأَل عن الحفظ على أساس إعداد مسبق للخيارات المستقبلية، فإذا أردتَ استخدام هذه الإعدادات وإلغاء الإعدادات المسبقة الحالية وتريد استخدامها مرةً أخرى، فاكتب <code>y</code>؛ وإلّا فاكتب <code>n</code>.
	</li>
</ol>
<p>
	ستبدأ واجهة CLI الآن في إنشاء الشيفرة المساعدة Scaffolding لمشروعك، وتثبيت كل اعتمادياتك.
</p>

<p>
	إذا لم تشغّل واجهة CLI الخاصة بإطار العمل Vue سابقًا، فسيظهر سؤال آخر، إذ سيُطلَب منك اختيار مدير الحزم، ويمكنك استخدام مفاتيح الأسهم لتحديد مدير الحزم الذي تفضله ليكون مدير الحزم الافتراضي من الآن فصاعدًا، فإذا احتجتَ استخدام مدير حزم مختلف بعد ذلك، فيمكنك تمرير الراية التالية عند تشغيل الأمر <code>vue create</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_23" style="">
<span class="pun">‎--</span><span class="pln">packageManager</span><span class="pun">=&lt;</span><span class="pln">package</span><span class="pun">-</span><span class="pln">manager</span><span class="pun">&gt;‎</span></pre>

<p>
	وبالتالي إذا أردت إنشاء مشروع <code>moz-todo-vue</code> باستخدام مدير الحزم npm واخترت yarn سابقًا، فيمكنك تشغيل الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_26" style="">
<span class="pln">vue create moz</span><span class="pun">-</span><span class="pln">todo</span><span class="pun">-</span><span class="pln">vue </span><span class="pun">--</span><span class="pln">packageManager</span><span class="pun">=</span><span class="pln">npm</span></pre>

<h2>
	بنية المشروع
</h2>

<p>
	إذا سار كل شيء على ما يرام، فيُفترَض إنشاء سلسلة من الملفات والمجلدات لمشروعك أهمها ما يلي:
</p>

<ul>
<li>
		<code>‎.eslintrc.js</code>: ملف إعداد أداة ESLint الذي يمكنك استخدامه لإدارة قواعد كشف الأخطاء المحتملة.
	</li>
	<li>
		<code>babel.config.js</code>: ملف إعداد Babel الذي يحوِّل ميزات جافاسكربت الحديثة المستخدَمة في شيفرة التطوير إلى صيغة أقدم أكثر توافقًا مع المتصفحات في شيفرة الإنتاج، ويمكنك تسجيل إضافات Babel الإضافية في هذا الملف.
	</li>
	<li>
		<code>‎.browserslistrc</code>: هو إعداد لقائمة المتصفحات، ويمكنك استخدامه للتحكُّم في المتصفحات التي تعمل أدواتك على تحسينها.
	</li>
	<li>
		public: يحتوي هذا المجلد على الأصول الساكنة المنشورة، ولكن لم يعالجها Webpack أثناء البناء باستثناء الملف index.html الذي يحصل على بعض المعالجة.
		<ul>
<li>
				<code>favicon.ico</code>: الرمز أو الأيقونة المفضلة Favicon لتطبيقك، وهو شعار Vue حاليًا.
			</li>
			<li>
				<code>index.html</code>: هو قالب تطبيقك، حيث يُشغَّل تطبيق Vue من صفحة HTML هذه، ويمكنك استخدام صيغة قوالب Lodash لتعديل القيم فيها، ولاحظ أنه لا يُستخدَم هذا القالب لإدارة تخطيط تطبيقك، بل هو مخصَّص لإدارة ملفات HTML الساكنة الموجودة خارج تطبيق Vue، إذ يُعدَّل هذا الملف في حالات الاستخدام المتقدِّمة فقط.
			</li>
		</ul>
</li>
	<li>
		<p>
			src: يحتوي هذا المجلد على مركز تطبيق Vue.
		</p>

		<ul>
<li>
				main.js: هو نقطة الدخول إلى تطبيقك، إذ يهيّئ هذا الملف حاليًا تطبيق Vue ويشير إلى عنصر HTML في الملف index.html الذي يجب ربطه مع تطبيقك، كما يُعَدّ هذا الملف المكانَ الذي تسجِّل فيه المكونات العامة أو مكتبات Vue الإضافية في أغلب الأحيان.
			</li>
			<li>
				App.vue: هو مكون المستوى الأعلى في تطبيق Vue.
			</li>
			<li>
				components: يُعَد هذا المجلد المكان الذي تحتفظ فيه بمكوناتك، ويحتوي حاليًا على مثال لمكوِّن واحد فقط.
			</li>
			<li>
				assets: هذا المجلد مخصص لتخزين الأصول الساكنة مثل ملفات <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a> والصور، وبما أنّ هذه الملفات موجودة في المجلد المصدر، فيمكن أن يعالجها Webpack، وهذا يعني أنه يمكنك استخدام المعالِجات المسبقة مثل <a href="https://wiki.hsoub.com/Sass" rel="external">Sass/SCSS</a> أو Stylus.
			</li>
		</ul>
</li>
</ul>
<p>
	<strong>ملاحظة</strong>: يمكن وجود مجلدات أخرى بناءً على الخيارات التي تحددها عند إنشاء مشروع جديد، فإذا اخترت موجّهًا مثلًا، فسيكون لديك أيضًا المجلد views.
</p>

<h2>
	ملفات ‎.vue مكونات الملف المفرد
</h2>

<p>
	تُعَدّ المكونات جزءًا أساسيًا من إنشاء التطبيقات في Vue كما هو الحال في العديد من أطر عمل الواجهة الأمامية، إذ تسمح هذه المكونات بتقسيم تطبيق كبير إلى كتل بناء منفصلة يمكن إنشاؤها وإدارتها، ونقل البيانات بين بعضها البعض كما هو مطلوب. يمكن أن تساعدك هذه الكتل الصغيرة في معرفة ما تفعله شيفرتك البرمجية واختبارها.
</p>

<p>
	يمكن أن تشجعك بعض أطر العمل على فصل شيفرات القالب والمنطق والتصميم إلى ملفات منفصلة، ولكن يتبع Vue النهج المعاكس، إذ يتيح لك باستخدام مكونات الملف المفرد Single File Components تجميع قوالبك والسكربتات المقابلة وشيفرة CSS معًا في ملف واحد ينتهي باللاحقة <code>‎.vue</code>، وتعالج أداة بناء JS -مثل Webpack- هذه الملفات، مما يعني أنه يمكنك الاستفادة من أدوات وقت البناء في مشروعك، وبالتالي يمكنك استخدام أدوات مثل Babel و TypeScript و SCSS وغيرها لإنشاء مكونات أكثر تعقيدًا.
</p>

<p>
	تُضبَط المشاريع المُنشَأة باستخدام واجهة CLI الخاصة بإطار عمل Vue لاستخدام ملفات <code>‎.vue</code> مع Webpack، فإذا نظرت ضمن المجلد <code>src</code> في المشروع الذي أنشأناه باستخدام CLI، فسترى أول ملف <code>‎.vue</code> وهو <code>App.vue</code>.
</p>

<h3>
	App.vue
</h3>

<p>
	افتح الملف App.vue وسترى أنه يتكون من ثلاثة أجزاء هي: <code>&lt;template&gt;</code> و <code>&lt;script&gt;</code> و <code>&lt;style&gt;</code> التي تحتوي على معلومات قالب المكوِّن وسكربتاته وتنسيقه، وتشترك كافة مكونات الملف المفرد في البنية الأساسية نفسها، كما يحتوي عنصر القالب <code>&lt;template&gt;</code> على بنية شيفرة التوصيف ومنطق عرض مكونك، كما يمكن أن يحتوي قالبك على أيّ شيفرة HTML صالحة، بالإضافة إلى بعض الصيغ الخاصة بإطار عمل Vue التي سنشرحها لاحقًا.
</p>

<p>
	<strong>ملاحظة</strong>: يمكنك استخدام صيغة قالب Pug بدلًا من لغة HTML القياسية من خلال ضبط السمة <code>lang</code> في الوسم <code>&lt;template&gt;</code> بالصورة <code>&lt;template lang="pug"‎&gt;</code>، إذ سنلتزم باستخدام لغة HTML القياسية في هذا المقال، ولكن يجب أن تعرف أنّ ذلك ممكن.
</p>

<p>
	يحتوي العنصر <code>&lt;script&gt;</code> على المنطق الذي لا يُعرَض من المكوِّن، إذ يجب أن يحتوي الوسم <code>&lt;script&gt;</code> على كائن جافاسكربت JS افتراضي مُصدَّر، ويُعَدّ هذا الكائن المكان الذي تسجِّل فيه المكونات محليًا، وتعرِّف مدخلات المكوّن (الخاصيات Props)، وتتعامل مع الحالة المحلية، وتعرِّف التوابع وغير ذلك، كما ستعمل خطوة البناء على معالجة هذا الكائن وتحويله مع قالبك إلى مكوّن Vue باستخدام الدالة <code>render()‎</code>.
</p>

<p>
	يضبط التصدير الافتراضي في حالة App.vue اسم المكوّن على <code>App</code> ويسجّل المكوّن <code>HelloWorld</code> من خلال إضافته إلى الخاصية <code>components</code>، فإذا سجّلتَ أحد المكوّنات بهذه الطريقة، فهذا يعني أنك تسجله محليًا، ولا يمكن استخدام المكوّنات المسجلة محليًا إلا ضمن المكوّنات التي تسجلها، لذلك يجب استيرادها وتسجيلها في كل ملف مكوّن يستخدمها. يمكن أن يكون هذا مفيدًا لتقسيم الحزم أو تقنية هز الشجرة Tree Shaking، إذ لا تحتاج كل صفحة في تطبيقك إلى جميع المكوّنات بالضرورة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_29" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">HelloWorld</span><span class="pln"> from </span><span class="str">'./components/HelloWorld.vue'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'App'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ‫يمكنك تسجيل المكونات محليًا هنا.</span><span class="pln">
    </span><span class="typ">HelloWorld</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	<strong>ملاحظة</strong>: إذا أردت استخدام صيغة لغة <a href="https://wiki.hsoub.com/TypeScript" rel="external">TypeScript</a>، فيجب ضبط السمة <code>lang</code> في الوسم <code>&lt;script&gt;</code> للإشارة إلى المصرِّف الذي تستخدمه لغة TypeScript بالصورة: <code>&lt;script lang="ts"‎&gt;</code>.
</p>

<p>
	يُعَدّ العنصر <code>&lt;style&gt;</code> المكان الذي تكتب فيه شيفرة CSS الخاصة بالمكوّن، فإذا أضفتَ السمة <code>scoped</code> بالصورة <code>&lt;style scoped&gt;</code>، فسيحدِّد إطار العمل Vue نطاق التنسيقات لمحتويات مكوّن الملف المفرد SFC، إذ يعمل هذا العنصر بطريقة مشابهة لحلول CSS في JS، ولكنه يسمح لك فقط بكتابة شيفرة CSS عادية.
</p>

<p>
	<strong>ملاحظة</strong>: إذا اخترتَ معالج CSS مسبَق عند إنشاء المشروع باستخدام واجهة سطر الأوامر CLI، فيمكنك إضافة السمة <code>lang</code> إلى الوسم <code>&lt;style&gt;</code> بحيث يمكن معالجة المحتويات باستخدام Webpack في وقت البناء مثل الوسم <code>&lt;style lang="scss"‎&gt;</code> الذي يسمح باستخدام صيغة SCSS في معلومات التنسيق.
</p>

<h2>
	تشغيل التطبيق محليا
</h2>

<p>
	تأتي واجهة CLI الخاصة بإطار العمل Vue مع خادم تطوير مضمَّن، مما يتيح تشغيل تطبيقك محليًا لتتمكّن من اختباره بسهولة دون الحاجة إلى إعداد خادم بنفسك، إذ تضيف CLI الأمر <code>serve</code> إلى الملف package.json الخاص بالمشروع بوصفه سكربت npm بحيث يمكنك تشغيله بسهولة.
</p>

<p>
	شغّل الأمر <code>npm run serve</code> في طرفيتك أو الأمر <code>yarn serve</code> إذا أردت استخدام yarn، إذ يجب أن ينتج شيء يشبه ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_31" style="">
<span class="pln">INFO  </span><span class="typ">Starting</span><span class="pln"> development server</span><span class="pun">...</span><span class="pln">
</span><span class="lit">98</span><span class="pun">%</span><span class="pln"> after emitting </span><span class="typ">CopyPlugin</span><span class="pln">

 DONE  </span><span class="typ">Compiled</span><span class="pln"> successfully in </span><span class="lit">18121ms</span><span class="pln">

  </span><span class="typ">App</span><span class="pln"> running at</span><span class="pun">:</span><span class="pln">
  </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Local</span><span class="pun">:</span><span class="pln">   </span><span class="pun">&lt;</span><span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:8080/&gt;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Network</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">http</span><span class="pun">:</span><span class="com">//192.168.1.9:8080/&gt;</span><span class="pln">

  </span><span class="typ">Note</span><span class="pln"> that the development build is not optimized</span><span class="pun">.</span><span class="pln">
  </span><span class="typ">To</span><span class="pln"> create a production build</span><span class="pun">,</span><span class="pln"> run npm run build</span><span class="pun">.</span></pre>

<p>
	إذا انتقلت إلى العنوان المحلي في تبويب متصفح جديد مثل العنوان <code><a href="http://localhost:8080" ipsnoembed="false" rel="external nofollow">http://localhost:8080</a></code> أو يمكن أن يختلف بناءً على إعداداتك، فيجب أن ترى تطبيقك، إذ يجب أن يحتوي التطبيق حاليًا على رسالة ترحيب، ورابطًا إلى توثيق Vue، وروابطًا إلى الإضافات التي أضفتها عند تهيئة التطبيق باستخدام CLI، بالإضافة إلى بعض الروابط المفيدة الأخرى إلى مجتمع Vue ونظامه البيئي.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="105335" href="https://academy.hsoub.com/uploads/monthly_2022_08/01_vue-default-app.png.15949303777c689dacfd6c1b59ccb8d0.png" rel=""><img alt="01_vue-default-app.png" class="ipsImage ipsImage_thumbnailed" data-fileid="105335" data-unique="h5otdc0iv" src="https://academy.hsoub.com/uploads/monthly_2022_08/01_vue-default-app.thumb.png.af323a0cc904575bd6f62f4c94304362.png" style="width: 700px; height: auto;"></a>
</p>

<h2>
	إجراء بعض التعديلات على التطبيق
</h2>

<p>
	التعديل الأول الذي سنجريه على التطبيق هو حذف شعار Vue، لذا افتح الملف App.vue واحذف العنصر <code>&lt;img&gt;</code> من قسم القالب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6359_35" style="">
<span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">"Vue logo"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"./assets/logo.png"</span><span class="tag">&gt;</span></pre>

<p>
	إذا كان خادمك قيد التشغيل، فيُفترَض أن ترى الشعار محذوفًا من الموقع المُصيَّر مباشرةً تقريبًا، فلنحذف الآن المكوّن <code>HelloWorld</code> من القالب.
</p>

<p>
	أولًا احذف السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_37" style="">
<span class="pun">&lt;</span><span class="typ">HelloWorld</span><span class="pln"> msg</span><span class="pun">=</span><span class="str">"Welcome to Your Vue.js App"</span><span class="pun">/&gt;</span></pre>

<p>
	إذا حفظت الملف App.vue الآن، فسيعطي التطبيق المُصيَّر خطأً لأننا سجَّلنا المكوّن ولكننا لم نستخدِمه، إذ يجب أيضًا إزالة الأسطر الموجودة ضمن العنصر <code>&lt;script&gt;</code> الذي يستورِد المكوّن ويسجله، لذا احذف الأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_39" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">HelloWorld</span><span class="pln"> from </span><span class="str">'./components/HelloWorld.vue'</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_41" style="">
<span class="pln">components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">HelloWorld</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب ألّا يعرض تطبيقك المُصيَّر أيّ خطأ حاليًا، وإنما سيعرض صفحةً فارغةً فقط، إذ لا يوجد حاليًا محتوًى مرئيًا ضمن عنصر القالب <code>&lt;template&gt;</code>.
</p>

<p>
	لنضِف عنصر <code>&lt;h1&gt;</code> جديد ضمن العنصر <code>&lt;div id="app"‎&gt;</code>، وبما أننا سننشئ تطبيق قائمة المهام، فلنضبط نص العنوان ليكون "To-Do List" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6359_43" style="">
<span class="pun">&lt;</span><span class="pln">template</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"app"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">To</span><span class="pun">-</span><span class="typ">Do</span><span class="pln"> </span><span class="typ">List</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">template</span><span class="pun">&gt;</span></pre>

<p>
	سيعرض التطبيق العنوان كما هو متوقع.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تعلّمنا في هذا المقال بعض أفكار إطار العمل Vue وأنشأنا شيفرة تطبيقنا المساعدة وفحصناه وأجرينا بعض التعديلات الأولية؛ أما الآن فسنذهب إلى أبعد من ذلك وننشئ تطبيق قائمة المهام الأساسي الذي يسمح بتخزين قائمة بالعناصر وإلغاء تحديدها عند الانتهاء وترشيح جميع المهام والمهام المكتملة والمهام غير المكتملة في القائمة، كما سنبني في المقال التالي أول مكوّن مخصَّص، وسنتعرّف على بعض المفاهيم المهمة مثل تمرير الخاصيات وحفظ حالة البيانات.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started" rel="external nofollow">Getting started with Vue</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/" rel="">مدخل إلى التعامل مع المكونات في Vue.js</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AF%D8%AE%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%B9%D9%86-%D8%B7%D8%B1%D9%8A%D9%82-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%A5%D8%AF%D8%AE%D8%A7%D9%84-%D9%81%D9%8A-vuejs-r1034/" rel="">التعامل مع دخل المستخدم عن طريق نماذج الإدخال في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1664</guid><pubDate>Sat, 13 Aug 2022 11:25:36 +0000</pubDate></item><item><title>&#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642; Vue.js &#x625;&#x644;&#x649; &#x627;&#x644;&#x625;&#x646;&#x62A;&#x631;&#x646;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r1038/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/12.png.972815c37e152b8cb0f0677050b7a3fe.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		تجهيز التطبيق قبل النشر
	</li>
	<li>
		إنشاء موقع جديد على منصة Netlify بالإستناد إلى مستودع GitHub
	</li>
</ul>
<p>
	هذا الدرس هو الأخير ضمن <a href="https://academy.hsoub.com/tags/%D9%85%D9%82%D8%AF%D9%85%D8%A9%20%D8%A5%D9%84%D9%89%20vuejs/" rel="">سلسلة Vue.js</a>، حيث سنتوّج هذه السلسلة بشرح كيفية نشر التطبيق الوارد في الدرس السابق، وهو عبارة عن تطبيق SPA يدعم التخاطب مع قاعدة بيانات موجودة على Firebase كما تذكر. بعد بناء التطبيق ونشره، سيتمكّن أي مستخدم حول العالم من الوصول إلى تطبيقنا هذا والتفاعل معه. سأعتمد استخدام المنصّة المجانية Netlify لهذا الغرض، ويمكنك بالطبع استخدام أي منصّة أو خادوم مخصّص ترغب به.
</p>

<h2>
	تجهيز التطبيق قبل النشر
</h2>

<p>
	كما ذكرت قبل قليل، سنعتمد التطبيق المبني في الدرس السابق لتشغيله على خدمة Netlify. بغية ذلك، عملت على رفع هذا التطبيق بشكل كامل على مستودع Github التالي: <a href="https://github.com/HsoubAcademy/vuejs-spa" rel="external nofollow">HsoubAcademy/vuejs-spa</a>
</p>

<p>
	سبب ذلك هو أنّ Netlify يسحب التطبيقات الموجودة على خدمات Git مثل GitHub. ستحتاج بالطبع إلى أن يكون لديك حساب على GitHub. زُر المستودع السابق، وسجّل دخولك على GitHub إذا لم تكن قد فعلت ذلك مسبقًا، ومن الصفحة الرئيسية لمستودعنا، انقر الزر Fork في الزاوية اليمنى العليا لإنشاء تفريعة جديدة من الشيفرة البرمجية الحالية.
</p>

<p>
	سيتطلب الأمر لحظات حتى يتم إنشاء التفريعة من الشيفرة البرمجية ووضعها ضمن حسابك الخاص.
</p>

<h2>
	إنشاء موقع جديد على منصة Netlify بالإستناد إلى مستودع GitHub
</h2>

<p>
	أنشئ حسابًا جديدًا على Netlify عن طريق زيارة الصفحة الرئيسية له <a href="https://www.netlify.com/" rel="external nofollow">الموقع الرسمي</a>. انقر Sign up من الزاوية اليمنى العليا لتظهر لك الصفحة الخاصة بإنشاء اشتراك جديد. تبدو هذه الصفحة حاليًا على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52274" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.f26444a0c2e4128d15e89ce8075bd3a3.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52274" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.d213beff804f8fff6b63606990e4e6a5.png"></a>
</p>

<p>
	لاحظ معي وجود خيارات متعددة للتسجيل. سنستخدم في حالتنا هذه التسجيل باستخدام البريد الإلكتروني. انقر الخيار الأخير "Email".
</p>

<p>
	بعد كتابة البريد الإلكتروني الذي تودّ التسجيل عن طريقه، سيرسل الموقع رسالة تحقق إلى هذا البريد تحتوي على رابط لتفعيل الحساب الجديد، انقر ذلك الرابط المرسَل إلى بريدك، وبعد تسجيل الدخول إلى Netlify باستخدام حسابك الجديد ستظهر صفحة مشابهة لما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52275" href="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.d643779c325aebd037a8e6185879f81c.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52275" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/2.thumb.png.438956ccd318cd4c4db7e0bcc47c93b1.png"></a>
</p>

<p>
	هذه هي الصفحة الرئيسية والتي تحتوي على جميع عناصر التحكم الخاصة بحسابك. نحن الآن موجودون ضمن الصفحة الخاصة بمواقع الويب التي أنشأتها أنت مسبقًا، وهي فارغة الآن بطبيعة الحال. انقر الزر "New site from Git" من الطرف الأيمن في الأعلى، للإتصال بمستودع من النوع Git. ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52276" href="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.6eafef29e8cd6a2826c18d937cc89fce.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52276" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/3.thumb.png.cff963b14df6cf1dd2798c862507e524.png"></a>
</p>

<p>
	انقر الزر GitHub الموجود في الأسفل، سيؤدي ذلك إلى فتح نافذة جديدة قد تطلب منك تسجيل الدخول بحسابك على GitHub في حال لم تكن مسجلًا دخولك على GitHub بعد (ذلك الحساب الذي أنشأت التفريعة ضمنه):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52277" href="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.ca1c57ec1f892bd89fc4806d1b5edc3d.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52277" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/4.thumb.png.6aa6fcd692c130c9c34b93502bf1dd3c.png"></a>
</p>

<p>
	انقر الزر Authorize Netlify للسماح لـ Netlify بالوصول إلى حساب GitHub الخاص بك. بعد إكمال عملية الاستيثاق (Authorization)، ستظهر لك صفحة تسمح لك بالاختيار بين السماح الكامل لـ Netlify للوصول إلى جميع المستودعات ضمن حسابك أو السماح بالوصول إلى مستودع محدّد. بالنسبة إلي، سأسمح له بالوصول إلى المستودع vuejs-spa فقط، وهو المستودع الذي أنشأناه كتفريعة قبل قليل من الفقرة السابقة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52278" href="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.eb477b630521ff3a896c3f8f0205cbd0.png" rel=""><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52278" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/5.thumb.png.b3bc270b7fda23f7ba6ca1419f7ce310.png"></a>
</p>

<p>
	انقر زر Install لتبدأ عملية التنصيب التي تتضمّن الانتقال إلى موقع GitHub بشكل تلقائي وذلك لإكمال عملية الربط (قد يطلب منك كلمة المرور لحسابك في GitHub مرة أخرى).
</p>

<p>
	بعد الإنتهاء من العملية السابقة ستحتاج إلى العودة إلى الصفحة الرئيسية لموقع Netlify وتكرار عملية إنشاء موقع من مستودع GitHub (الشكل رقم 3). هذه المرة سيظهر لنا المستودع الذي نرغب باستيراده. انظر إلى الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52279" href="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.47f66afd5bcfac9575b4dc2f1cd27032.png" rel=""><img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52279" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/6.thumb.png.daae877e659520f9debc0bec90a268c8.png"></a>
</p>

<p>
	لاحظ معي كيف ظهر المستودع vuejs-spa مع اسم حساب GitHub التابع لي husamburhan. سأختار هذا المستودع بالنقر عليه، سيؤدي ذلك إلى الخطوة النهائية والتي تتمثّل بتحديد الفرع الرئيسي (Branch) التي سنستخدمه في عملية نشر التطبيق، بالإضافة إلى تحديد التعليمة الخاصة ببناء التطبيق، والمجلّد الخاص بالنشر. احرص على أن تحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52280" href="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.6132b61835a988035f409183cfc4078f.png" rel=""><img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52280" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/7.thumb.png.a9a3de0a91bb8051f24444bde48fd3e4.png"></a>
</p>

<p>
	أخيرًا، انقر الزر Deploy site لبناء التطبيق ونشر الموقع على الانترنت. ستأخذ هذه العملية القليل من الوقت، حيث ستنتقل إلى صفحة تخبرك بأنّ عملية البناء والنشر قيد التجهيز. بعد أن تنتهي عملية البناء والنشر ستحصل على رابط حي للصفحة تستطيع مشاركته مع من ترغب.
</p>

<p>
	بالنسبة إلي حصلت على الرابط التالي: <a href="https://suspicious-mahavira-10e9ac.netlify.app" rel="external nofollow">suspicious-mahavira-10e9ac.netlify.app</a>
</p>

<p>
	لاحظ أنّ اسم الموقع يُولَّد بشكل عشوائي. يمكنك بالطبع تغيير هذا الاسم بحيث يصبح منطقيًا أكثر. كما يمكنك إضافة اسم نطاق مخصّص مثل www.example.com وربطه مع هذا الموقع إن أحببت. جميع الخيارات السابقة وأكثر يمكن التحكم بها من خلال خيارات الموقع في Netlify.
</p>

<h2>
	ختامًا
</h2>

<p>
	ختمنا في هذا الدرس السلسلة التعليمية الخاصة بـ Vue.js بشرح كيفية نشر التطبيق إلى خدمة مجانية ليصبح تطبيقنا متاحًا على الانترنت. توجد العديد من الخدمات التي تسمح بالنشر المجاني، ولكنّني اخترت أبسطها وهي Netlify حسب رأيي.
</p>

<p>
	حاولت في <a href="https://academy.hsoub.com/tags/%D9%85%D9%82%D8%AF%D9%85%D8%A9%20%D8%A5%D9%84%D9%89%20vuejs/" rel="">هذه السلسلة</a> تغطية الأمور الأساسية فقط في Vue.js، لذلك فأمامك الكثير بكل تأكيد لتتعلّمه حول هذه التقنية الواعدة. يمكنك زيارة <a href="https://vuejs.org/v2/guide/" rel="external nofollow">الموقع الرسمي</a> لإطار العمل Vue.js والاستزادة حوله.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B0%D8%A7%D8%AA-%D8%B5%D9%81%D8%AD%D8%A9-%D9%88%D8%A7%D8%AD%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%8A%D9%87-routing-%D9%81%D9%8A-vuejs-r1037/" rel="">بناء تطبيقات ذات صفحة واحدة باستخدام التوجيه Routing في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1038</guid><pubDate>Mon, 09 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x630;&#x627;&#x62A; &#x635;&#x641;&#x62D;&#x629; &#x648;&#x627;&#x62D;&#x62F;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x62A;&#x648;&#x62C;&#x64A;&#x647; Routing &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B0%D8%A7%D8%AA-%D8%B5%D9%81%D8%AD%D8%A9-%D9%88%D8%A7%D8%AD%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%8A%D9%87-routing-%D9%81%D9%8A-vuejs-r1037/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/11.png.5446b2a6e3ca9694a132463592bb6768.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		بناء هيكل التطبيق والتعرّف على أجزاءه الرئيسية.
	</li>
	<li>
		تحويل التطبيق الموجود في الدرس السابق إلى تطبيق SPA.
	</li>
</ul>
<p>
	سنتعلّم في هذا الدرس كيفية بناء تطبيقات تعتمد على صفحة واحدة فقط (Single Page Applications) أو اختصارًا SPA. توفّر Vue.js هذه الإمكانية من خلال مكتبة اسمها vue-router تسمح بتعريف مسارات داخلية ضمن التطبيق بهدف دعم مفهوم SPA. وتطبيقات SPA هي تطبيقات ويب عادية، لكنّها تختلف عن التطبيقات الكلاسيكية في أنّ الانتقال من صفحة إلى أخرى ضمن الموقع لا يحتاج إلى إعادة تحميل كامل الصفحة بما تحويه من ملفات شيفرة نصية وصور وغيرها من أصول الموقع. فالذي يحدث في تطبيقات SPA هو أنّ جميع الواجهات المفترض وجودها في الموقع ستكون معرّفة مسبقًا ومحمّلة إلى حاسوب المستخدم، فيعمل تطبيق SPA فقط على استبدال واجهة مكان واجهة أخرى دون الحاجة إلى تحميل الصفحة كاملةً من الخادوم.
</p>

<p>
	يرتبط هذا الدرس ارتباطًا وثيقًا بالدرس السابق لأنّه سيعمل على تحويل التطبيق المعتمد في الدرس السابق إلى تطبيق يدعم SPA لذلك أنصحك بمراجعة الدرس السابق قبل الاستمرار في هذا الدرس. على أية حال، أرجو أن يكون هذا الدرس ممتعًا ومفيدًا.
</p>

<h2>
	بناء هيكل التطبيق والتعرّف على أجزاءه الرئيسية
</h2>

<p>
	بنينا في الدرس السابق تطبيق تجريبي بسيط، هدفه التواصل مع قاعدة بيانات موجودة على الـ Firebase، ولعلّك تذكر، أنّني قد أشرت في ذلك الدرس إلى أنّ الأسلوب الذي اتبعناه في بناء ذلك التطبيق لم يكن عمليًّا بسبب أنّنا قد "حشرنا" جميع وظائف التطبيق ضمن واجهة واحدة وهذا أمر غير عملي بالطبع. حان الآن إصلاح ذلك العيب وذلك باستخدام تقنية SPA. سنحوّل جميع وظائف التطبيق السابق إلى تطبيق جديد سنبنيه في هذا الدرس.
</p>

<p>
	لنبدأ بإنشاء هيكل التطبيق الجديد بتنفيذ الأمر التالي ضمن موجّه الأوامر:
</p>

<pre class="ipsCode">
vue create vue-spa
</pre>

<p>
	لكي ننجز مفهوم SPA في تطبيقنا هذا، سنستخدام تقنية التوجيه (Routing) التي عن طريق المكتبة vue-router كما أشرنا قبل قليل. استخدم الأمر التالي لتنصيب المكتبة vue-router:
</p>

<pre class="ipsCode">
npm install vue-router
</pre>

<p>
	افتح مجلّد التطبيق باستخدام Visual Studio Code ثم احذف الملف HelloWorld.vue. سنحتاج إلى إنشاء مجموعة جديدة من الملفات والمجلّدات من أجل هذا التطبيق. انقر الآن بزر الفأرة الأيمن على المجلّد src واختر New Folder لإنشاء مجلّد جديد سمّه views. سنستخدم هذا المجلّد لتخزين الواجهات المختلفة للتطبيق الخاص بنا. أنشئ ضمن المجلّد views الذي أنشأناه توًّا الملفات التالية: AddUser.vue و EditUser.vue و AllUsers.vue و Home.vue. أنشئ أيضًا الملف routes.js ضمن المجلّد src. الملف routes.js سيحتوي على مسارات العناوين الداخلية التي سنستخدمها ضمن التطبيق.
</p>

<p>
	ستحصل بالنتيجة على البنية التالية من الملفات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52268" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.832d1f5e1da140995f1ca949403ac93c.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52268" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.832d1f5e1da140995f1ca949403ac93c.png"></a>
</p>

<h2>
	تحويل التطبيق الموجود في الدرس السابق إلى تطبيق SPA
</h2>

<p>
	لكي نبدأ باستخدام التوجيه، يجب أولًا أن نستورد المكتبة vue-router عن طريق عبارة الاستيراد التالية:
</p>

<pre class="ipsCode">
import VueRouter from "vue-router";
</pre>

<p>
	سنضع هذه العبارة (وبشكل مختلف عما اعتدنا عليه) ضمن الملف routes.js وسأوضّح سبب ذلك بعد قليل. انظر الآن إلى محتويات الملف routes.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_7" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln"> from </span><span class="str">"vue"</span><span class="pun">;</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VueRouter</span><span class="pln"> from </span><span class="str">"vue-router"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Home</span><span class="pln"> from </span><span class="str">"./views/Home"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">AddUser</span><span class="pln"> from </span><span class="str">"./views/AddUser"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">EditUser</span><span class="pln"> from </span><span class="str">"./views/EditUser"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">AllUsers</span><span class="pln"> from </span><span class="str">"./views/AllUsers"</span><span class="pun">;</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueRouter</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> routes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Home</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/AddUser"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"AddUser"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AddUser</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/EditUser"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"EditUser"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">EditUser</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/AllUsers"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"AllUsers"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AllUsers</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">VueRouter</span><span class="pun">({</span><span class="pln">
  routes
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> router</span><span class="pun">;</span></pre>

<p>
	أوضحنا قبل قليل، أنّ وظيفة الملف routes.js هي تعريف مسارات العناوين الداخلية التي سنستخدمها ضمن التطبيق. لننظر الآن إلى القسم الخاص بتعليمات الاستيراد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_9" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln"> from </span><span class="str">"vue"</span><span class="pun">;</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VueRouter</span><span class="pln"> from </span><span class="str">"vue-router"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Home</span><span class="pln"> from </span><span class="str">"./views/Home"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">AddUser</span><span class="pln"> from </span><span class="str">"./views/AddUser"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">EditUser</span><span class="pln"> from </span><span class="str">"./views/EditUser"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">AllUsers</span><span class="pln"> from </span><span class="str">"./views/AllUsers"</span><span class="pun">;</span></pre>

<p>
	أعتقد أنّ أوّل تعليمتين واضحتين. بالنسبة للتعليمات الأربع الأخرى، فهي لاستيراد الواجهات التي سنستخدمها في التطبيق. هذه الواجهات هي بطبيعة الحال مكوّنات (لأنّها موجودة ضمن ملفات تحمل الامتداد vue).
</p>

<p>
	بعد ذلك نُخبر Vue.js أن يستخدم التوجيه من خلال التعليمة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_11" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueRouter</span><span class="pun">);</span></pre>

<p>
	وبعد ذلك نصل إلى القسم الخاص بتعريف المسارات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_13" style="">
<span class="kwd">const</span><span class="pln"> routes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Home</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/AddUser"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"AddUser"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AddUser</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/EditUser"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"EditUser"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">EditUser</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/AllUsers"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"AllUsers"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">AllUsers</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	لاحظ معي أننا نضع المسارات التي سنستخدمها في التطبيق ضمن مصفوفة اسمها <code>routes</code>. كل عنصر من هذه المصفوفة عبارة عن كائن له الحقول: path و name و component. انظر مثلًا إلى الكائن الأوّل من هذه المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_15" style="">
<span class="pun">{</span><span class="pln">
    path</span><span class="pun">:</span><span class="pln"> </span><span class="str">"/"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home"</span><span class="pun">,</span><span class="pln">
    component</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Home</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمثّل هذا الكائن المسار الخاص بالصفحة الرئيسية للتطبيق. فهو يُعرّف المسار الخاص بها ليكون <code>/</code> ويمثّل الصفحة الرئيسية في تطبيقات الويب عادة. أي يمكن الوصول إلى هذه الواجهة من خلال الرابط التالي:
</p>

<pre class="ipsCode">
http://www.yourdomain.com/#/
</pre>

<p>
	أمّا اسم هذا المسار فهو <code>Home</code> (من الممكن أن نصل إلى أي مسار من خلال اسمه كما سنرى لاحقًا في هذا الدرس). بالنسبة للواجهة التي سترتبط بهذا المسار فهي <code>Home</code> (انظر إلى تعليمة الاستيراد الخاصة بالواجهة Home.vue).
</p>

<p>
	بالنسبة لباقي المسارات فتعمل بنفس الأسلوب تمامًا، فإذا أخذنا مثلًا المسار الثاني فنجد أنّ المسار الذي يُشير إليه هو <code>‎/AddUser</code> أي أنّنا نستطيع الوصول إليه عن طريق رابط مماثل لما يلي:
</p>

<pre class="ipsCode">
http://www.yourdomain.com/#/AddUser
</pre>

<p>
	نأتي إلى القسم التالي في الشيفرة البرمجية السابقة، حيث سنعرّف متغيّر جديد اسمه <code>router</code> ونسند إليه كائن جديد يمثّل الموجّه الذي سيدير عمليّات التوجيه ضمن التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_18" style="">
<span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">VueRouter</span><span class="pun">({</span><span class="pln">
  routes
</span><span class="pun">});</span></pre>

<p>
	لاحظ كيف مرّرنا المصفوفة التي عرفنا ضمنها المسارات توًّا إلى <code>VueRouter</code> (وهو معرّف ضمن إحدى تعليمات الاستيراد). وأخيرًا نضع التعليمة المسؤولة عن تصدير الموجّه <code>router</code> خارج هذا الملف.
</p>

<p>
	لننتقل الآن إلى الملف main.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_20" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln"> from </span><span class="str">'vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> router from </span><span class="str">'./routes.js'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"bootstrap/dist/css/bootstrap.min.css"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VueResource</span><span class="pln"> from </span><span class="str">'vue-resource'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VueSimpleAlert</span><span class="pln"> from </span><span class="str">"vue-simple-alert"</span><span class="pun">;</span><span class="pln">


</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">config</span><span class="pun">.</span><span class="pln">productionTip </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueResource</span><span class="pun">);</span><span class="pln">
</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueSimpleAlert</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  router</span><span class="pun">,</span><span class="pln">
  render</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=&gt;</span><span class="pln"> h</span><span class="pun">(</span><span class="typ">App</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}).</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">)</span></pre>

<p>
	نستورد ضمن هذا الملف المكتبات التي سنحتاجها ضمن التطبيق. أعتقد أنّ أوّل تعليمتي استيراد واضحتين أيضًا. بالنسبة للتعليمة الثالثة، فهنا نستورد الموجّه <code>router</code> التي بنيناه مسبقًا ضمن الملف routes.js، أمّا بالنسبة للتعليمات الثلاث الباقية فهي على الترتيب:
</p>

<ul>
<li>
		استيراد مكتبة Bootstrap للتنسيق.
	</li>
	<li>
		استيراد المكتبة vue-resource للاتصال بالخواديم البعيدة، والتي تعاملنا معها في الدرس السابق.
	</li>
	<li>
		استيراد مكتبة جديدة اسمها vue-simple-alert لم نتعامل معها مسبقًا. والهدف منها عرض رسائل ذات تنسيق جميل للمستخدم، سنتعلّم بعد قليل كيفية التعامل معها.
	</li>
</ul>
<p>
	ستحتاج بالتأكيد إلى تنصيب المكتبة vue-simple-alert بتنفيذ الأمر التالي ضمن موجّه الأوامر:
</p>

<pre class="ipsCode">
npm install vue-simple-alert
</pre>

<p>
	لاحظ الآن التعليمتين التاليتين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_22" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueResource</span><span class="pun">);</span><span class="pln">
</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueSimpleAlert</span><span class="pun">);</span></pre>

<p>
	هاتين التعليمتين لإخبار Vue.js أن يستخدم الكائنين: VueResource و VueSimpleAlert. نأتي الآن إلى آخر تعليمة ضمن هذا الملف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_24" style="">
<span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  router</span><span class="pun">,</span><span class="pln">
  render</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=&gt;</span><span class="pln"> h</span><span class="pun">(</span><span class="typ">App</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}).</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">)</span></pre>

<p>
	التعليمة السابقة مألوفة، وقد استخدمنا مثلها مرارًا، ولكن لاحظ معي هنا كيف أضفت كائن الموجّه <code>router</code> إليها. هذه الإضافة ضرورية، ولن يعمل التوجيه في التطبيق ما لم نضف كائن الموجّه بهذه الصورة.
</p>

<p>
	سنستعرض فيما يلي الملف App.vue بالإضافة إلى ملفات واجهات التطبيق.
</p>

<h3>
	الملف App.vue
</h3>

<p>
	ستكون محتويات هذا الملف على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_26" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;nav</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"nav"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"logo-place"</span><span class="tag">&gt;</span><span class="pln">Vue.js Remote Server (Enhanced)</span><span class="tag">&lt;/p&gt;</span><span class="pln">
      </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"nav-links"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"links"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">Home</span><span class="tag">&lt;/router-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"links"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/AddUser"</span><span class="tag">&gt;</span><span class="pln">Add User</span><span class="tag">&lt;/router-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"links"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/AllUsers"</span><span class="tag">&gt;</span><span class="pln">All User</span><span class="tag">&lt;/router-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;/li&gt;</span><span class="pln">
      </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;/nav&gt;</span><span class="pln">
    </span><span class="tag">&lt;router-view&gt;&lt;/router-view&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"App"</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">

</span><span class="com">#nav {</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">24px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">#nav a {</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> bold</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#2c3e50;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">decoration</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="lit">12px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">#nav a.router-link-active {</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ab26ab;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">nav</span><span class="pun">-</span><span class="pln">links </span><span class="pun">{</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
  list</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln">
  display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="lit">21px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">links</span><span class="pun">-</span><span class="pln">hover </span><span class="pun">{</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">decoration</span><span class="pun">:</span><span class="pln"> underline</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">logo</span><span class="pun">-</span><span class="pln">place </span><span class="pun">{</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> purple</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> bold</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="lit">16px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">16px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	هناك أمران جديدان سنتحدث عنهما بالنسبة لهذا الملف. لاحظ أولًا وجود وسم جديد اسمه <code>router-view</code>. في الحقيقة أنّ هذا الوسم ما هو إلّا مكوّن موجود ضمن المكتبة vue-router، ووظيفته تحديد مكان إدراج واجهات التطبيق المختلفة ضمن الصفحة الرئيسية. لأّن تطبيقات SPA كما أشرنا من قبل، لا تتطلب إعادة تحميل الصفحة بالكامل عندما يريد المستخدم الانتقال إلى واجهة مختلفة.
</p>

<p>
	الأمر الآخر هو وجود وسم جديد آخر وهو <code>router-link</code> وهو مكوّن أيضًا ضمن نفس المكتبة. وظيفة هذا المكوّن توليد عنصر ارتباط تشعبي <code>&lt;a&gt;</code> بحيث ينتقل إلى إحدى الواجهات المعرّفة ضمنه. فمثلًا لاحظ معي المكوّن <code>router-link</code> التالي التي أخذته من الشيفرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_28" style="">
<span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/AddUser"</span><span class="tag">&gt;</span><span class="pln">Add User</span><span class="tag">&lt;/router-link&gt;</span></pre>

<p>
	نجد من المقطع السابق وجود السمة <code>to</code> و هي مسؤولة عن تحديد المسار (Path) الذي سيُوجَّه إليه المستخدم عند نقر هذا الرابط. في المثال السابق سيُوجَّه المستخدم إلى المسار الكامل التالي:
</p>

<pre class="ipsCode">
http://www.yourdomain.com/#/AddUser
</pre>

<p>
	وذلك بسبب وجود <code>‎ /AddUser</code> كقيمة للسمة <code>to</code>.
</p>

<h3>
	الملف Home.vue
</h3>

<p>
	وهو ملف الصفحة الرئيسية في التطبيق وستكون محتوياته على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_30" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-6 offset-2"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h1&gt;</span><span class="pln">Welcome in our website!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="lit">30px</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18rem</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-body"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;h5</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-title"</span><span class="tag">&gt;</span><span class="pln">ِAdd User</span><span class="tag">&lt;/h5&gt;</span><span class="pln">
          </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-text"</span><span class="tag">&gt;</span><span class="pln">Add a new user to the Firebase experimental website.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
          </span><span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/AddUser"</span><span class="tag">&gt;</span><span class="pln">Add a user</span><span class="tag">&lt;/router-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">

      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">18rem</span><span class="pun">;</span><span class="pln"> margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="lit">18px</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-body"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;h5</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-title"</span><span class="tag">&gt;</span><span class="pln">All User</span><span class="tag">&lt;/h5&gt;</span><span class="pln">
          </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-text"</span><span class="tag">&gt;</span><span class="pln">Display all users info from the Firebase experimental website.</span><span class="tag">&lt;/p&gt;</span><span class="pln">
          </span><span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/AllUsers"</span><span class="tag">&gt;</span><span class="pln">Get all users</span><span class="tag">&lt;/router-link&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Home"</span><span class="pun">,</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	لا يوجد في الشيفرة السابقة أي جديد، سوى أنّك تمتلك الحق في إضافة أصناف تنسيقية إلى المكوّن <code>router-link</code> كما في:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_32" style="">
<span class="tag">&lt;router-link</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/AddUser"</span><span class="tag">&gt;</span><span class="pln">Add a user</span><span class="tag">&lt;/router-link&gt;</span></pre>

<p>
	ستبدو هذه الواجهة على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52269" href="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.8df23a0f2a94e8805ac302eb184ce7c2.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52269" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/2.thumb.png.050b40a0eb6ff362a1d7cd548a099867.png"></a>
</p>

<h3>
	الملف AddUser.vue
</h3>

<p>
	يحتوي هذا الملف على الواجهة المسؤولة عن إضافة مستخدم جديد. انظر معي إلى الشيفرة البرمجية الخاصّة به:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_34" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-6 offset-2"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h1&gt;</span><span class="pln">Add User</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-6 offset-2"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label&gt;</span><span class="pln">Username</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.username"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label&gt;</span><span class="pln">First name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.firstname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label&gt;</span><span class="pln">Last name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.lastname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary float-left"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="lit">12px</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"postUser()"</span><span class="tag">&gt;</span><span class="pln">Add</span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">


</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"AddUser"</span><span class="pun">,</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    postUser</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$alert</span><span class="pun">(</span><span class="str">"A new user is added."</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Operation Succeeded"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"success"</span><span class="pun">);</span><span class="pln">
          </span><span class="pun">},</span><span class="pln">
          </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      user</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">row </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	الشيفرة البرمجية الموجودة ضمن هذا الملف تماثل تقريبًا تلك التي كانت مسؤولة عن إضافة مستخدم جديد في الدرس الماضي. مع ملاحظة أنّ الشيفرة أصبحت أكثر تنظيمًا، بسبب أنّنا نعزل هنا عملية إضافة مستخدم جديد عن غيرها من العمليات.
</p>

<p>
	على أية حال توجد ميزة جديدة استُخدِمت ضمن هذه الواجهة، وهي رسالة ستُعرَض للمستخدم في حال نجاح عملية الإضافة إلى قاعدة بيانات Firebase:
</p>

<pre class="ipsCode">
this.$alert("A new user is added.", "Operation Succeeded", "success");
</pre>

<p>
	كما كان من الممكن إضافة رسالة شبيهة بالرسالة السابقة في حال فشلت عملية الإضافة للمستخدم (لم أُضف مثل هذه الرسالة إلى الشيفرة السابقة). التابع <code>‎ $alert</code> موجود ضمن المكتبة vue-simple-alert وظيفته كما هو واضح، هو في عرض رسالة منسّقة للمستخدم. بالنسبة لمثالنا هذا، سنعرض رسالة تُخبر المستخدم بأنّ عملية إضافة بيانات المستخدم إلى قاعدة بيانات Firebase قد تمت بنجاح. يمثّل الوسيط الأوّل للتابع <code>‎ $alert</code> الرسالة التي نريد عرضها، أما الوسيط الثاني فهو عنوان صندوق الرسالة، أمّا الوسيط الثالث فهو نوع الرسالة وهي في حالتنا هذه <code>success</code>. توجد أنواع أخرى للرسائل التي يمكن للتابع <code>‎ $alert</code> عرضها مثل <code>success</code> و <code>error</code>. للاطلاع على المزيد من الوثائق المتعلّقة بهذه المكتبة يمكنك زيارة <a href="https://github.com/constkhi/vue-simple-alert" rel="external nofollow">الصفحة الرسمية لها</a>.
</p>

<p>
	ستبدو هذه الواجهة على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52270" href="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.e6293606472f054b6f5efddc42e7d84b.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52270" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/3.thumb.png.ae42351b0e7b5ddb7d301a400e0b52bd.png"></a>
</p>

<h3>
	الملف AllUsers.vue
</h3>

<p>
	يحتوي هذا الملف على الواجهة الخاصة بعرض بيانات المستخدمين الذين سبق إضافتهم إلى قاعدة بيانات Firebase. انظر إلى الشيفرة البرمجيّة الخاصة به:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_36" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;h2&gt;</span><span class="pln">All Users</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
      </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="lit">16px</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"getData()"</span><span class="tag">&gt;</span><span class="pln">Retrieve</span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;hr</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"usr in users"</span><span class="pln"> </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"usr.username"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-2"</span><span class="tag">&gt;</span><span class="pln">{{usr.username}}</span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-4"</span><span class="tag">&gt;</span><span class="pln">{{usr.firstname}} {{usr.lastname}}</span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-1"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;router-link</span><span class="pln"> :</span><span class="atn">to</span><span class="pun">=</span><span class="atv">"{name: 'EditUser', params: {user:usr}}"</span><span class="tag">&gt;</span><span class="pln">Edit</span><span class="tag">&lt;/router-link&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      user</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      users</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    getData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> tmpArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

          </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            let withId </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">];</span><span class="pln">
            withId</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> key</span><span class="pun">;</span><span class="pln">
            tmpArray</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">

          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users </span><span class="pun">=</span><span class="pln"> tmpArray</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">row</span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	مرة أخرى، لا تختلف الشيفرة البرمجية الموجودة هنا عن تلك التي كانت موجودة في الدرس السابق. فعندما ينتقل المستخدم لهذه الواجهة وينقر على الزر Retrieve، ستُحدّث الواجهة بحيث تعرض جميع المستخدمين المخزنين حاليًا ضمن قاعدة بيانات Firebase. بعد عرض هؤلاء المستخدمين، ستلاحظ وجود رابط اسمه Edit يظهر بجوار كل مستخدم. عند نقر هذا الزر سينقلك التطبيق إلى واجهة تحرير بيانات المستخدم <code>EditUser</code> لإجراء التعديلات المطلوبة عليه.
</p>

<p>
	ولكنّ السؤال هنا، كيف ستتمكّن الواجهة <code>EditUser</code> من معرفة المستخدم المطلوب تحرير بياناته؟ الجواب هو في المكوّن <code>router-link</code> الموجود ضمن هذه الواجهة <code>AllUsers</code>. انظر معي إلى الاستخدام الجديد للمكوّن <code>router-link</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_38" style="">
<span class="tag">&lt;router-link</span><span class="pln"> :</span><span class="atn">to</span><span class="pun">=</span><span class="atv">"{name: 'EditUser', params: {user:usr}}"</span><span class="tag">&gt;</span><span class="pln">Edit</span><span class="tag">&lt;/router-link&gt;</span></pre>

<p>
	استخدمنا في المقطع السابق السمة <code>to</code> بشكل مختلف عن استخدامنا لها في الواجهات السابقة. لاحظ أولًا كيف وضعت نقطتين رأسيتين قبل كلمة <code>to</code> مباشرةً (وهما ضروريتان في هذه الحالة)، ثم أسندت إلى السمة <code>‎ :to</code> كائن وليس نص عادي كما فعلنا من قبل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_42" style="">
<span class="pun">{</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'EditUser'</span><span class="pun">,</span><span class="pln"> params</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">user</span><span class="pun">:</span><span class="pln">usr</span><span class="pun">}}</span></pre>

<p>
	هذا الكائن لديه مفتاحين. الأول هو <code>name</code> ويمتلك القيمة <code>'EditUser'</code>، ويمثّل اسم الواجهة التي نريد الانتقال إليها عندما ينقر المستخدم هذا الرابط. لاحظ أنّني قلت "اسم" وليس "مسار"، أي أنّ الاسم الذي نكتبه هنا يحب أن يكون موافقًا للقيمة <code>name</code> التي كانت موجودة ضمن ملف المسارات routes.js عندما عرفنا تلك المسارات إذا كنت تذكر.
</p>

<p>
	بالنسبة للمفتاح الثاني فهو <code>params</code> وهو مسؤول عن تمرير أية وسائط نرغبها إلى الواجهة التي نريد الانتقال إليها. في حالتنا هذه نرغب بتمرير بيانات المستخدم المراد تحريرها بشكل كامل. طريقة التمرير مفيدة للغاية، لاحظ كيف مرّرنا كائن جديد للمفتاح <code>params</code> يحتوي هذا الكائن في حالتنا هذه، على مفتاح وحيد اسمه <code>user</code> ونسند له القيمة <code>usr</code> التي تُعتبر كائنًا مستقلًا بحد ذاته يحتوي على بيانات المستخدم المراد تحرير بياناته. أي أنّ <code>{user:usr}</code> عبارة عن ثنائية تحوي اسم الوسيط <code>user</code> مع القيمة المرتبطة به <code>usr</code>.
</p>

<p>
	يمكن بالطبع تمرير أكثر من وسيط إلى الواجهة بالأسلوب السابق، وذلك بوضعها بجوار بعضها على شكل مفاتيح متعاقبة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_44" style="">
<span class="pln">params</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">key1</span><span class="pun">:</span><span class="pln">val1</span><span class="pun">,</span><span class="pln"> key2</span><span class="pun">:</span><span class="pln">val2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...}</span></pre>

<p>
	ستبدو الواجهة AllUsers على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52271" href="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.ae18be2915fa39f30e1d6ffb74b40d25.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52271" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/4.thumb.png.641793b2bd7177ef3a789bdb185d9ffc.png"></a>
</p>

<h3>
	الملف EditUser.vue
</h3>

<p>
	في هذه الواجهة يمكننا تعديل بيانات المستخدم، بالإضافة إلى إمكانية حذف بيانات هذا المستخدم بشكل كلّي من قاعدة البيانات (هذه ميزة جديدة لم تكن مُضافة مسبقًا في الدرس السابق).
</p>

<p>
	إليك الشيفرة البرمجية الخاصة بهذا الملف:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_46" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-6 offset-2"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h1&gt;</span><span class="pln">Edit User</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-6 offset-2"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12"</span><span class="tag">&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label&gt;</span><span class="pln">Username</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.username"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label&gt;</span><span class="pln">First name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.firstname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
              </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;label&gt;</span><span class="pln">Last name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.lastname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
              </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
          </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary float-left"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="lit">12px</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"putUser()"</span><span class="tag">&gt;</span><span class="pln">Save</span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln">
          </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-danger float-right"</span><span class="pln">
          </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="lit">12px</span><span class="pun">;</span><span class="atv">"</span><span class="pln">
          @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"deleteUser()"</span><span class="pln">
        </span><span class="tag">&gt;</span><span class="pln">Delete</span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">


</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"EditUser"</span><span class="pun">,</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    putUser</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">
          </span><span class="str">"https://vue-remote-servers.firebaseio.com/users/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$route</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">id </span><span class="pun">+</span><span class="pln">
            </span><span class="str">".json"</span><span class="pun">,</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user
        </span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$alert</span><span class="pun">(</span><span class="pln">
              </span><span class="str">"The user is updated."</span><span class="pun">,</span><span class="pln">
              </span><span class="str">"Operation Succeeded"</span><span class="pun">,</span><span class="pln">
              </span><span class="str">"success"</span><span class="pln">
            </span><span class="pun">);</span><span class="pln">
          </span><span class="pun">},</span><span class="pln">
          </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    deleteUser</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$confirm</span><span class="pun">(</span><span class="str">"Are you sure you want to delete the user?"</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
          </span><span class="pun">.</span><span class="kwd">delete</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"https://vue-remote-servers.firebaseio.com/users/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
              </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$route</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">id </span><span class="pun">+</span><span class="pln">
              </span><span class="str">".json"</span><span class="pln">
          </span><span class="pun">)</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$router</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'AllUsers'</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">},</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
          </span><span class="pun">);</span><span class="pln">
      </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    user</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$route</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">user</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">row </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	الشيء الذي أود التركيز عليه من الشيفرة السابقة هو كيفية استلام الوسائط الممرّرة لهذه الواجهة من الواجهة الخاصة بعرض بيانات جميع المستخدمين AllUsers ومن ثمّ تعبئة هذه البيانات ضمن حقول البيانات المناسبة لها، ليتمكّن المستخدم من تعديلها إن أحب. أنشأت لهذا الغرض خاصية محسوبة اسمها <code>user</code> إليك الشيفرة البرمجية الخاصة بها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_48" style="">
<span class="pln">user</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$route</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">user</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تحتوي هذه الخاصية المحسوبة على تعليمة برمجية واحدة ترُجع الوسيط الذي مرّرناه من الواجهة AllUsers قبل قليل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_50" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$route</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">user</span></pre>

<p>
	الوسيط هو <code>user</code> كما أسميناه ضمن الواجهة AllUsers، يحتوي هذا الوسيط على بيانات المستخدم <code>username</code> و <code>firstname</code> و <code>lastname</code> كما وردت من الواجهة AllUsers. هذا الوسيط موجود ضمن المفتاح <code>params</code> كما هو واضح، والموجود بدوره ضمن الكائن <code>‎ $route</code> (الموجود ضمن المكتبة vue-router). وبما أنّ الخاصية <code>user</code> محسوبة فإنّ البيانات المستخلصة منها ستُعمّم مباشرة على الحقول الثلاثة الموجودة ضمن الواجهة EditUser كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7712_52" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-12"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;label&gt;</span><span class="pln">Username</span><span class="tag">&lt;/label&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.username"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;label&gt;</span><span class="pln">First name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.firstname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;label&gt;</span><span class="pln">Last name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.lastname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	أود أيضًا التحدث عن التابع <code>‎ $confirm</code> الموجود ضمن المكتبة <code>vue-simple-alert</code> ووظيفته تخييرك بين أمرين. استخدمت التابع <code>‎ $confirm</code> ضمن التابع <code>deleteUser</code> وذلك لكي نطلب من المستخدم تأكيد أنّه يريد حذف المستخدم الحالي من قاعدة البيانات. انظر الشيفرة البرمجية للتابع <code>deleteUser</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_54" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$confirm</span><span class="pun">(</span><span class="str">"Are you sure you want to delete the user?"</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="kwd">delete</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"https://vue-remote-servers.firebaseio.com/users/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$route</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">id </span><span class="pun">+</span><span class="pln">
            </span><span class="str">".json"</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$router</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'AllUsers'</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">},</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	في حال تمت الموافقة على حذف المستخدم الحالي، سيُنفَّذ تابع السهم المُمرّر لتابع <code>then</code> الأوّل. يحتوي تابع السهم هذا على الشيفرة البرمجية التي ستحذف بيانات المستخدم من قاعدة بيانات Firebase وهي مألوفة وتشبه أخواتها من المقاطع البرمجية الأخرى المسؤولة عن التعامل مع قاعدة بيانات Firebase. لاحظ أنّنا ننفّذ تابع <code>then</code> آخر يحتوي على تعليمة برمجيّة أخرى وظيفتها تحويل المستخدم إلى الواجهة AllUsers بعد الانتهاء من حذف المستخدم الحالي.انظر لهذه التعليمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7712_56" style="">
<span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$router</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'AllUsers'</span><span class="pun">);</span></pre>

<p>
	هذا هو الأسلوب المتبع للانتقال بين الواجهات بشكل برمجي، وذلك عن طريق استخدام التابع <code>push</code> من الكائن <code>‎ $router</code>، حيث نمرّر "اسم" الواجهة التي نرغب بالانتقال إليها كوسيط للتابع <code>push</code>.
</p>

<h2>
	ختامًا
</h2>

<p>
	تناولنا في هذا الدرس مقدّمة إلى التوجيه في Vue.js. في الحقيقة يُعتبر هذا الموضوع كبيرًا بعض الشيء وله جوانب متعدّدة غطينا في هذا الدرس الأساسي منها. في حال احتجت إلى التوسّع في هذا الموضوع مستقبلًا، فأعتقد أنّ خير رفيق لك، سيكون الوثائق الرسمية للتوجيه على <a href="https://router.vuejs.org/" rel="external nofollow">هذا الموقع</a>. أقترح عليك بعد قراءة هذا الدرس أن تحاول تجريب بناء تطبيقات بسيطة تعتمد على التوجيه، لكي تعتاد على هذه التقنية.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-vuejs-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r1038/" rel="">نشر تطبيق Vue.js إلى الإنترنت</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r1036/" rel="">استخدام Vue.js للاتصال بالإنترنت</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1037</guid><pubDate>Fri, 06 Nov 2020 13:01:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Vue.js &#x644;&#x644;&#x627;&#x62A;&#x635;&#x627;&#x644; &#x628;&#x627;&#x644;&#x625;&#x646;&#x62A;&#x631;&#x646;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r1036/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/10.png.ed399109655c462baa81f53e4d394721.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		إنشاء قاعدة بيانات على Google Firebase
	</li>
	<li>
		تنصيب مكتبة الاتصال بالانترنت vue-resource
	</li>
	<li>
		بناء تطبيق باستخدام Vue.js للقراءة والإضافة من وإلى قاعدة البيانات
	</li>
	<li>
		إضافة ميزة تعديل البيانات للتطبيق السابق
	</li>
</ul>
<p>
	سنتعلم في هذا الدرس كيفية الاتصال بخواديم بعيدة باستخدام مكتبة مخصّصة لـ Vue.js لهذا الغرض. وبما أنّنا نهتم بتبسيط المعلومة من خلال التركيز على مفهوم جديد محدّد، فلن ندخل في مجال بناء تطبيق خلفية كامل (Backend Application) مخصّص لكي يتعامل معه تطبيق Vue.js، ولكن سنعتمد على إنشاء تطبيق بسيط مجاني على Google Firebase، وهو عبارة عن خدمة قاعدة بيانات سيتواصل معها تطبيقنا لتوضيح الفكرة المطلوبة.
</p>

<h2>
	إنشاء قاعدة بيانات على Google Firebase
</h2>

<p>
	لن نتوسّع في هذا الدرس في الشرح حول Google Firebase ومزاياها، إذ يمكنك الاطلاع حول المزيد عنها من خلال الوثائق الخاصة بها والتي سأزودك بالبعض منها بعد قليل. يكفيك الآن أن تعلم أنّ Google Firebase هي منصّة مملوكة من قبل Google وظيفتها مساعدة المطوّرين على بناء وتحسين وتنمية التطبيقات التي يعملون عليها، فهي عبارة عن خدمة خلفية (Backend Service) يمكنك من خلالها إنشاء قواعد بيانات وخدمات استيثاق (Authentication Services) وغيرها من المزايا المفيدة لتطبيقاتك المختلفة، سواء كانت تطبيقات لأجهزة الموبايل أو تطبيقات ويب أو غيرها.
</p>

<p>
	بالنسبة إلينا، سنستخدم Firebase في هذا الدرس لبناء قاعدة بيانات بسيطة كخدمة تمثّل دعمًا لتطبيق Vue.js بسيط. انتقل إلى <a href="https://firebase.google.com" rel="external nofollow">الموقع الرسمي لـ Firebase</a>، ثم من الزاوية اليمنى العليا اختر Sign in لتسجيل الدخول، ستحتاج إلى حساب Google للوصول إلى خدمات Firebase.
</p>

<p>
	بعد تسجيل الدخول بحساب Google ستظهر الصفحة الرئيسية التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52254" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.0c9c80a398cf3fa4fffe1b8ad473e73f.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52254" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.d71776f10401a70d1dedf5a60941d337.png"></a>
</p>

<p>
	انقر Go to console من الزاوية اليمنى العليا للانتقال إلى صفحة الخدمات، ثم انقر زر Add project (أو Create a project) لإضافة مشروع جديد، سيطلب منك بدايةً اسم المشروع بالإضافة إلى الموافقة على الاتفاقية كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52255" href="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.c086967497532e55a29315044ca31366.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52255" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/2.thumb.png.294114f2524308f651c5db71ea93d060.png"></a>
</p>

<p>
	لقد اخترت الاسم <code>vue-remote-servers</code> ستضطر بالطبع إلى استخدام اسم آخر لمشروعك لأن الاسم الحالي أصبح محجوزًا. بعد ذلك انقر زر Continue للانتقال إلى المرحلة الثانية التي سيخيرك فيها بتفعيل Google Analytics من أجل هذا المشروع. انقر الزر Continue مجددا للانتقال إلى المرحلة الأخيرة قبل إنشاء المشروع.
</p>

<p>
	في حال كنت قد اخترت تفعيل Google Analytics في المرحلة الثانية، فسيطلب منك في المرحلة الأخيرة تحديد الحساب الذي ترغب باستخدامه مع Google Analytics (سيوفر لك حساب افتراضي اسمه Default Account For Firebase أو سيسمح لك بإنشاء حساب جديد إن أحببت)، بعد تحديد الحساب، سيظهر زر Create project في الاسفل، انقره لإنشاء المشروع. أمّا إذا لم تفعّل Google Analytics من المرحلة الثانية، فسيؤدي ذلك إلى إنشاء المشروع المطلوب فورًا.
</p>

<p>
	<strong>ملاحظة</strong> إذا كنت تزور Firebase للمرة الأولى، فسيطلب منك في المرحلة الأخيرة تحديد المنطقة (الدولة) الخاصة بـ Google Analytics بالإضافة إلى الموافقة على بنود الاستخدام.
</p>

<p>
	بعد إنشاء المشروع سينتقل المتصفح إلى الصفحة الخاصة به. من القائمة اليسرى انقر الزر Develop ثم انقر Database لأنّنا لن نهتم الآن سوى بقاعدة البيانات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52257" href="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.cb119a3ebec5dd11c950d8653c4745e0.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52257" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/3.thumb.png.490c29bbcdaf5fb7bdd1f3aa93749b54.png"></a>
</p>

<p>
	بعد النقر على قاعدة البيانات ستحصل على واجهة تسمح لك ببناء قاعدة بيانات جديدة. استخدم شريط التمرير العمودي لكي تنتقل إلى أسفل الصفحة قليلًا حتى تصل إلى القسم الخاص بإنشاء قاعدة بيانات في الزمن الحقيقي (Realtime Database) كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52258" href="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.00418af7c60ff709cb0b7cd7de80fa82.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52258" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.00418af7c60ff709cb0b7cd7de80fa82.png"></a>
</p>

<p>
	انقر زر Create database لإنشاء قاعدة البيانات المطلوبة. ستظهر نافذة صغيرة تعرض فيما إذا كنت تريد أن تجعل قاعدة البيانات مفتوحة للجميع بهدف اختبارها، أم مقفلة تحتاج إلى تسجيل دخول. سنختار أن تكون مفتوحة لجعل الأمر أسهل. اختر Start in test mode:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52259" href="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.bccf352280e1c1f3fccf247b681755bf.png" rel=""><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52259" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.bccf352280e1c1f3fccf247b681755bf.png"></a>
</p>

<p>
	لاحظ التحذير الذي سيظهر باللون الأحمر والذي يفيد بأنّ أي شخص سيصبح قادرًا على تعديل قاعدة البيانات أو القراءة منها. بعد النقر على زر Enable ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52260" href="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.25167f88c86195ca05bc6a590a54856a.png" rel=""><img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52260" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/6.thumb.png.0beb3e4b449a18d48d119a30737a66b3.png"></a>
</p>

<p>
	أصبحت قاعدة البيانات جاهزة، لاحظ من جديد كيف يظهر تحذير باللون الأحمر يخبرك أنّ قاعدة البيانات مفتوحة ويمكن لأي شخص الوصول إليها. لاحظ أيضًا الرابط الذي يظهر مباشرة فوق التحذير:
</p>

<pre class="ipsCode">
https://vue-remote-servers.firebaseio.com/
</pre>

<p>
	هذا الرابط هو عنوان نقطة الاتصال لخدمة قاعدة البيانات (Database Service Endpoint) التي أنشأناها توًّا. سنحتاج إلى هذا الرابط لاحقًا في هذا الدرس.
</p>

<p>
	قد تتساءل أيضًا أين الجداول ضمن قاعدة البيانات هذه؟ الحقيقة أنّ قواعد البيانات ضمن Firebase عبارة عن قواعد بيانات NoSQL لمعرفة المزيد حول قواعد البيانات هذه يمكنك <a href="https://en.wikipedia.org/wiki/NoSQL" rel="external nofollow">زيارة هذه الصفحة</a>.
</p>

<p>
	<strong>ملاحظة</strong> يمكنك الحصول على المزيد من المعلومات حول Firebase من خلال <a href="https://firebase.google.com/docs" rel="external nofollow">هذا الرابط</a> الذي يحتوي على الوثائق الرسمية له.
</p>

<p>
	<strong>ملاحظة</strong> تحدث في بعض الأحيان تحديثات مستمرة على الواجهات الخاصة بـ Google Firebase، لذلك فقد يختلف الشرح الموجود هنا قليلًا عمّا تشاهده في الموقع. مع أنّني أرجو ألّا يحدث ذلك، منعًا لأي التباس قد يعتريك عزيزي القارئ.
</p>

<h2>
	تنصيب مكتبة الاتصال بالانترنت vue-resource
</h2>

<p>
	يمكن بالطبع استخدام أي طريقة للاتصال بالانترنت من خلال Vue.js، ولكنني سأختار في هذا الدرس أسلوب مخصص لـ Vue.js. سنستخدم مكتبة اسمها vue-resource يمكن من خلالها الاتصال بالخواديم بشكل سهل ومبسّط وبشكل منسجم تقريبًا مع المكتبات الشهيرة المستخدمة لهذا الغرض. يمكنك الوصول إلى المستودع الخاص بهذه المكتبة على Github من خلال <a href="https://github.com/pagekit/vue-resource" rel="external nofollow">هذا الرابط</a>. في الحقيقة، أنصحك بزيارة مستودع هذه المكتبة على Github بعد أن تنتهي من هذا الدرس، لتطلع عليها بشكل جيّد وتتعرف على جميع الإمكانيات التي تقدّمها والتي تسهل عملك كمبرمج. في هذا الدرس، سنتحدّث عن جزء محدود من هذه المزايا.
</p>

<p>
	لتنصيب vue-resource افتح موجّه الأوامر ونفّذ الأمر التالي:
</p>

<pre class="ipsCode">
npm install vue-resource
</pre>

<p>
	بعد الانتهاء من التنصيب يمكن الآن إضافة هذه المكتبة إلى تطبيق Vue.js وذلك بإضافة السطر التالي إلى قسم المكتبات المستوردة ضمن الملف main.js:
</p>

<pre class="ipsCode">
import VueResource from 'vue-resource';
</pre>

<p>
	واستخدام التعليمة التالية ضمن الملف main.js أيضًا:
</p>

<pre class="ipsCode">
Vue.use(VueResource);
</pre>

<p>
	أمّا كيفية الاستخدام الفعلي لهذه المكتبة فسنتعرف عليه في الفقرة التالية.
</p>

<h2>
	بناء تطبيق باستخدام Vue.js للقراءة والإضافة من وإلى قاعدة البيانات
</h2>

<p>
	كما جرت العادة، سنبني تطبيق عملي جديد باستخدام Vue CLI سنتعلّم من خلاله كيفية الاتصال بقاعدة البيانات التي أنشأناها في الفقرة الأولى من هذا الدرس على Google Firebase.
</p>

<p>
	أنشئ مشروع جديد اسمه vue-remote-servers عن طريق تنفيذ الأمر التالي ضمن موجّه الأوامر:
</p>

<pre class="ipsCode">
vue create vue-remote-servers
</pre>

<p>
	بعد إنشاء المشروع، افتح المجلّد الخاص به عن طريق Visual Studio Code. احذف الآن الملف HelloWorld.vue ثم احرص على أن تكون محتويات الملف main.js مماثلة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_7" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln"> from </span><span class="str">'vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VueResource</span><span class="pln"> from </span><span class="str">'vue-resource'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"bootstrap/dist/css/bootstrap.min.css"</span><span class="pun">;</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">config</span><span class="pun">.</span><span class="pln">productionTip </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="typ">VueResource</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  render</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=&gt;</span><span class="pln"> h</span><span class="pun">(</span><span class="typ">App</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}).</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">)</span></pre>

<p>
	واحرص أيضًا على أن تكون محتويات الملف App.vue مماثلة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3142_9" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h2&gt;</span><span class="pln">Vue.js Remote Server</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;label&gt;</span><span class="pln">Username</span><span class="tag">&lt;/label&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.username"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;label&gt;</span><span class="pln">First name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.firstname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;label&gt;</span><span class="pln">Last name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.lastname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"postData()"</span><span class="tag">&gt;</span><span class="pln">Add</span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"getData()"</span><span class="tag">&gt;</span><span class="pln">Retrieve</span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;ul</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"list-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;li</span><span class="pln">
            </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"list-group-item"</span><span class="pln">
            </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"usr in users"</span><span class="pln">
            </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"usr.username"</span><span class="pln">
          </span><span class="tag">&gt;</span><span class="pln">{{usr.username}} - {{usr.firstname}} {{usr.lastname}}</span><span class="tag">&lt;/li&gt;</span><span class="pln">
        </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"App"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      user</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      users</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    postData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
          </span><span class="pun">},</span><span class="pln">
          </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    getData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> tmpArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

          </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            tmpArray</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">

          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users </span><span class="pun">=</span><span class="pln"> tmpArray</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">

</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	ستعطي الشيفرة السابقة الواجهة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52261" href="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.09b4c079ff7a1584a4aecf0c1c2ff1a8.png" rel=""><img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52261" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.09b4c079ff7a1584a4aecf0c1c2ff1a8.png"></a>
</p>

<p>
	الفكرة من هذا التطبيق هي في إمكانية الإضافة المتعددة لمستخدمين افتراضيين. حيث تتكون بيانات كل مستخدم من: اسم المستخدم (Username) والاسم (First name) والكنية (Last name). سترسل بيانات كل مستخدم مفترض إلى قاعدة البيانات على Firebase. بعد ذلك يمكن استرداد بيانات المستخدمين المُضافة مسبقًا إلى قاعدة البيانات هذه، من خلال نقر الزر Retrieve.
</p>

<p>
	<strong>ملاحظة</strong> سنستخدم في هذا التطبيق تنسيقات Bootstrap على افتراض أنّك قد نصبته مسبقًا. وهذا ما يفسّر وجود السطر التالي ضمن ملف main.js:
</p>

<pre class="ipsCode">
import "bootstrap/dist/css/bootstrap.min.css";
</pre>

<p>
	إذا أردت أن تتذكر كيفية استخدام تنسيقات Bootstrap ضمن Vue.js يمكنك مراجعة الفقرة: "استخدام إطار العمل Bootstrap" ضمن الدرس: "التعامل مع دخل المستخدم عن طريق نماذج الإدخال".
</p>

<p>
	بالنسبة لآلية عمل التطبيق، لاحظ معي بدايةً أن شيفرة HTML الموجودة ضمن القسم <code>&lt;template&gt;</code> هي بسيطة وواضحة. بالنسبة لحقول البيانات المستخدمة، فهي معرفة ضمن القسم <code>&lt;script&gt;</code> حيث عرّفت جميع الحقول التي تعود للمستخدم المفترض ضمن كائن اسمه <code>user</code> موجود ضمن القسم <code>data</code> ضمن كائن Vue.js. يحتوي هذا الكائن على الحقول التالية: <code>username</code> و <code>firstname</code> و <code>lastname</code> كما هو واضح. كما يحتوي القسم <code>data</code> أيضًا على مصفوفة اسمها <code>users</code> سنخزّن ضمنها بيانات المستخدمين التي سنحصل عليها من قاعدة بيانات Firebase عند نقر زر Retrieve كما سنوضّح ذلك بعد قليل.
</p>

<p>
	أمّا بالنسبة للقسم <code>methods</code> فيحتوي على تابعين فقط: <code>postData</code> و <code>getData</code> وهما معالجين لحدثي النقر على الزرين Add و Retrieve على الترتيب.
</p>

<p>
	بالنسبة للتابع <code>postData</code> تأمل معي الشيفرة البرمجيّة الموجودة ضمنه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_11" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
          </span><span class="pun">},</span><span class="pln">
          </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">);</span></pre>

<p>
	استخدمت الكائن المبيّت <code>‎ $http</code> من الكائن this. في الحقيقة أنّ هذا الكائن مُتاح فقط من خلال المكتبة vue-resource التي أضفناها في هذا الدرس. يحتوي الكائن <code>‎ $http</code> على عدة توابع مفيدة في استقبال وإرسال البيانات عبر الإنترنت من وإلى خواديم أو خدمات (Services) كما هي خدمة Firebase. بما أنّنا نريد إضافة بيانات جديدة، فسنستخدم التابع <code>post</code> كما هو واضح. يقبل هذا التابع وسيطين:
</p>

<p>
	الوسيط الأول هو عنوان نقطة الاتصال للخدمة المراد التواصل معها، وهي في حالتنا هذه عنوان خدمة قاعدة البيانات على Firebase التي أنشأناها في هذا الدرس:
</p>

<pre class="ipsCode">
https://vue-remote-servers.firebaseio.com/users.json
</pre>

<p>
	الرابط السابق حصلت عليه من الصفحة الخاصة بقاعدة البيانات vue-remote-servers إذا كنت تذكر من الفقرة الأولى من هذا الدرس، ولكن أضفت عليه اسم المصدر users.json. بما أنّني أريد إضافة مستخدمين افتراضيين إلى قاعدة البيانات فمن المنطقي إضافة بيانات هؤلاء المستخدمين إلى جدول (إن صح التعبير) اسمه users. في الحقيقة في قواعد البيانات من النمط NoSQL نسمي مثل هذه الجداول بالمجموعات (Collections). إذًا فالاسم users هو اسم المجموعة التي سنخزّن ضمنها بيانات المستخدمين الافتراضيين، أمّا الامتداد ‎ .json فهو إلزامي.
</p>

<p>
	أمّا الوسيط الثاني فهو عبارة عن البيانات المراد إرسالها. وقد أرسلت الكائن <code>user</code> جملةً واحدة، لأنّه يحتوي على البيانات الفرعية المطلوبة والتي هي مربوطة بدورها عن طريق <code>v-model</code> بعناصر HTML الموافقة.
</p>

<p>
	يُرجع التابع <code>post</code> وعد (Promise) لذلك فإنّنا نُتبع استدعاء التابع <code>post</code> بنقطة مباشرة وبعدها نكتب التابع <code>then</code> كما هو مألوف تمامًا عند العمل مع مكتبات JavaScript الشهيرة الأخرى. يقبل التابع <code>then</code> وسيطين أيضًا: الوسيط الأوّل هو تابع يحتوي على شيفرة برمجيّة تُعالج الرد الذي حصلت عليه مكتبة vue-resource بعد اتصالها مع الخادوم البعيد. انظر إلى الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_13" style="">
<span class="pln"> </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
          </span><span class="pun">}</span></pre>

<p>
	مرّرنا التابع السابق كتابع سهم (Arrow Function) يقبل وسيطًا اسمه <code>response</code> وهو يمثّل الرد الذي حصلت عليه المكتبة من الخادوم. ضمن هذا التابع وفي السطر الأوّل منه نلاحظ وجود التعليمة <code>‎console.log(response)</code> لعرض محتوى البيانات الواردة من الخادوم ضمن الطرفية (Console) الخاصة بأدوات المطوّر ضمن متصفّح الويب. يمكنك إزالة هذا السطر إن أحببت. أمّا التعليمات الثلاث التالية فهدفها تفريغ حقول بيانات المستخدم للإشارة إلى نجاح العملية.
</p>

<p>
	أمّا الوسيط الثاني للتابع <code>then</code> فهو أيضًا تابع آخر، ولكنّه يحتوي على الشيفرة البرمجية التي تعالج حالة وجود خطأ ما في عملية الإرسال.
</p>

<p>
	عند هذه النقطة بالتحديد، أفضّل تشغيل التطبيق لنرى ماذا سيحدث عند إضافة مستخدم جديد. شغل التطبيق عن طريق تنفيذ الأمر التالي ضمن موجّه الأوامر وضمن المجلّد vue-remote-servers الذي يحوي ملفات التطبيق:
</p>

<pre class="ipsCode">
npm run serve
</pre>

<p>
	زُر الآن الصفحة <a href="http://localhost:8080" rel="external nofollow">http://localhost:8080</a> لتحصل على واجهة التطبيق. أدخل قيم مناسبة لاسم المستخدم و الاسم والكنية، ثم انقر الزر Add. إذا اختفت القيم التي أدخلتها توًّا فهذا دليل على نجاح العملية!
</p>

<p>
	انتقل الآن إلى الصفحة الخاصة بقاعدة البيانات vue-remote-servers (<a href="https://firebase.google.com/" rel="external nofollow">عليك زيارة الموقع</a> ثم نقر زر Go to console وبعد ذلك اختيار المشروع vue-remote-servers ثم نقر زر Database من القائمة اليسرى، وأخيرًا اختيار قاعدة البيانات الحقيقية (Realtime Database) التي تحمل نفس الاسم).
</p>

<p>
	بحسب البيانات التي أدخلتها أنا، حصلت على الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52262" href="https://academy.hsoub.com/uploads/monthly_2020_10/8.png.922e82fba92ff291a3ffd530717a0e19.png" rel=""><img alt="8.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52262" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/8.thumb.png.5c6e4284d5a0af44628d6fde34d86bb1.png"></a>
</p>

<p>
	لاحظ معي اسم قاعدة البيانات vue-remote-servers يظهر في أعلى الشجرة، ثم يظهر اسم المجموعة users في العقدة التي تليها. يتفرّع عن المجموعة users التي هي بمثابة جدول كما اتفقنا، عقدة تالية تحمل رموزًا مبهمة، يتفرّع عنها من جديد البيانات التي أرسلتها إلى قاعدة البيانات وهي: Husam للاسم و Burhan للكنية و husam79 لاسم المستخدم.
</p>

<p>
	بالنسبة للرموز المبهمة التي تظهر فهي بمثابة مفتاح رئيسي (Primary Key) أو معرّف (ID) للبيانات التي تقع ضمنها. لأنّه من البديهي إرسال العديد من بيانات المستخدمين، فسيعمل Firebase على تخصيص شيفرة فريدة تحوي مثل هذه الرموز المبهمة لكل مستخدم مفترض تتم إضافته إلى قاعدة البيانات. يمكنك إن أحببت إضافة مستخدم آخر لترى كيف يحدث ذلك.
</p>

<p>
	كل الكلام السابق كان للتابع <code>postData</code>. أمّا بالنسبة للتابع <code>getData</code> فها هي الشيفرة البرمجيّة الموجودة ضمنه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_15" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> tmpArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

          </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            tmpArray</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">

          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users </span><span class="pun">=</span><span class="pln"> tmpArray</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span></pre>

<p>
	سنستخدم هذه المرة التابع <code>get</code> من الكائن <code>‎ $http</code> وذلك للحصول على البيانات المخزّنة ضمن قاعدة البيانات. لا يحتاج هذا التابع كما هو واضح إلّا لوسيط واحد هو نفسه الوسيط الأوّل للتابع <code>post</code> الذي تحدثنا عنه قبل قليل.
</p>

<p>
	يُرجع التابع <code>get</code> أيضًا وعد (Promise)، لذلك وبنفس النقاش السابق فإنّنا نُتبع استدعاء التابع <code>get</code> بنقطة مباشرة وبعدها نكتب التابع <code>then</code>. اكتفيت هنا بكتابة وسيط واحد للتابع <code>then</code> -وهذا جائز تمامًا- وهو عبارة عن تابع سهم كما هو واضح يحتوي على تعليمة برمجية واحدة فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_17" style="">
<span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span></pre>

<p>
	وظيفة هذه التعليمة هي إرجاع تمثيل JSON للرد الذي حصلت عليه المكتبة بعد استدعاء التابع <code>get</code>. وذلك من خلال استدعاء التابع <code>json</code> من الكائن <code>response</code>. وهنا ينبغي التنويه إلى أنّ التابع <code>json</code> يُرجع هو أيضًا وعد (Promise). لذلك فإنّ التعليمة السابقة تُرجع هذا الوعد مما يسمح لنا بوضع نقطة مباشرةً بعد استدعاء التابع <code>then</code> ثم استدعاء تابع <code>then</code> جديد يقبل وسيط وهو بالطبع عبارة عن تابع سهم جديد يقبل وسيطًا واحدًا أيضًا أسميته <code>data</code> يحتوي على البيانات الفعلية التي حصلنا عليها من قاعدة البيانات على الـ Firebase.
</p>

<p>
	ما تبقى ضمن تابع السهم الموجود ضمن تابع <code>then</code> الأخير عبارة عن شيفرة برمجيّة وظيفتها استخلاص البيانات الخام الواردة من المكتبة vue-resource التي تتواصل مع قاعدة البيانات، وتخزينها بشكل مناسب ضمن المصفوفة المؤقتة <code>tmpArray</code>. وبعد انتهاء عملية الاستخلاص، تُسنَد هذه المصفوفة إلى الحقل <code>users</code> وهو مصفوفة بالطبع، لتُعرض البيانات بالشكل المرغوب على المستخدم. انظر هذه الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_19" style="">
<span class="kwd">const</span><span class="pln"> tmpArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    tmpArray</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users </span><span class="pun">=</span><span class="pln"> tmpArray</span><span class="pun">;</span></pre>

<p>
	إنّ سبب وجود حلقة <code>for</code> بالشكل السابق، يعود إلى شكل البيانات الواردة من المكتبة vue-resource والتي هي عبارة عن قاموس (Dictionary)، يكون المفتاح (Key) فيه عبارة عن المفتاح الرئيسي (تلك الرموز الغريبة) لأحد المستخدمين، أمّا القيمة (Value) لهذا المفتاح فهي عبارة عن كائن يتضمن بيانات المستخدم (في حالتنا هذه تكون هذه البيانات عبارة عن اسم المستخدم والاسم والكنية كما نعلم). انظر معي إلى البيانات الخام الواردة من المكتبة vue-resource، والتي حصلت عليها بإضافة تعليمة الكتابة إلى الطرفية (Console) عند ورود البيانات من المكتبة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52263" href="https://academy.hsoub.com/uploads/monthly_2020_10/9.png.7c424c7ad8dce6d113b6beed11607f24.png" rel=""><img alt="9.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52263" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/9.png.7c424c7ad8dce6d113b6beed11607f24.png"></a>
</p>

<p>
	في الحقيقة تعمدت إخفاء بعض التوابع الأخرى الموجودة ضمن الكائن للتركيز على ما يهمنا هنا. الشكل السابق هو نتيجة إضافة مستخدمين افتراضيين آخرين إلى قاعدة البيانات، وبعد نقر زر Retrieve بالطبع. انظر إلى الشكل التالي لترى كيف ستبدو نفس البيانات ولكن على صفحة الويب:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52264" href="https://academy.hsoub.com/uploads/monthly_2020_10/10.png.1e525106673f08bff739d9ce9d4d467b.png" rel=""><img alt="10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52264" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/10.thumb.png.bdf24cb6ae37d9086f8c2d125bab7e9a.png"></a>
</p>

<h2>
	إضافة ميزة تعديل البيانات للتطبيق السابق
</h2>

<p>
	من الواضح أنّ تطبيقنا السابق يسمح بإضافة مستخدمين افتراضيين جدد، كما يسمح بقراءة بيانات هؤلاء المستخدمين وعرضهم على الصفحة. ولكن من المفيد أن يسمح التطبيق أيضًا بتعديل بيانات مستخدم افتراضي موجود مسبقًا. يمكن ذلك ببساطة من خلال استخدام التابع <code>put</code> من الكائن <code>‎ $http</code> حيث يسمح هذا التابع بتعديل بيانات مستخدم موجود مسبقًا ضمن قاعدة البيانات بمجرّد أن نعرف المفتاح الرئيسي (تلك الرموز الغريبة) للمستخدم ضمن قاعدة البيانات.
</p>

<p>
	سأجري في الحقيقة تعديلًا كبيرًا من الناحية الشكلية على التطبيق السابق لكي يسمح بإنجاز هذه الميزة، ورغم التعديلات الكثيرة التي ستجري على الملف App.vue، إلّا أنّها تُعتبر في حقيقة الأمر بسيطة وواضحة خصوصًا بعد أن وصلنا إلى هذه المرحلة في العمل مع Vue.js.
</p>

<p>
	إليك الشيفرة البرمجية الجديدة للملف App.vue:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3142_21" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h2&gt;</span><span class="pln">Vue.js Remote Server</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;label&gt;</span><span class="pln">Username</span><span class="tag">&lt;/label&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.username"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;label&gt;</span><span class="pln">First name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.firstname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
          </span><span class="tag">&lt;label&gt;</span><span class="pln">Last name</span><span class="tag">&lt;/label&gt;</span><span class="pln">
          </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"user.lastname"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"postOrPutData()"</span><span class="tag">&gt;</span><span class="pln">{{actionButtonTitle}}</span><span class="tag">&lt;/button&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary float-right"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"reset()"</span><span class="tag">&gt;</span><span class="pln">Reset</span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;hr&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-2"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary btn-dark"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"getData()"</span><span class="tag">&gt;</span><span class="pln">Retrieve</span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"usr in users"</span><span class="pln"> </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"usr.username"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-2"</span><span class="tag">&gt;</span><span class="pln">{{usr.username}}</span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-4"</span><span class="tag">&gt;</span><span class="pln">{{usr.firstname}} {{usr.lastname}}</span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-1"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-link"</span><span class="pln"> @</span><span class="atn">click</span><span class="pun">=</span><span class="atv">"prepareToSave(usr.id)"</span><span class="tag">&gt;</span><span class="pln">Edit</span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"App"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      user</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        username</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      users</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
      currentUserIdToSave</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
      actionButtonTitle</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Add"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    postOrPutData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">actionButtonTitle </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Add"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
          </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user
          </span><span class="pun">)</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">

              </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
              </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
              </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">},</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
          </span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
          </span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">
            </span><span class="str">"https://vue-remote-servers.firebaseio.com/users/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
              </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentUserIdToSave </span><span class="pun">+</span><span class="pln">
              </span><span class="str">".json"</span><span class="pun">,</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user
          </span><span class="pun">)</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">},</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
          </span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    getData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
        </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">json</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">((</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">const</span><span class="pln"> tmpArray </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[];</span><span class="pln">

          </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            let withId </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">];</span><span class="pln">
            withId</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> key</span><span class="pun">;</span><span class="pln">
            tmpArray</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">

          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users </span><span class="pun">=</span><span class="pln"> tmpArray</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    prepareToSave</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">username</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">firstname</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">lastname</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentUserIdToSave </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">users</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">id</span><span class="pun">;</span><span class="pln">

          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">actionButtonTitle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Save"</span><span class="pun">;</span><span class="pln">

          </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    reset</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">actionButtonTitle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Add"</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentUserIdToSave </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">

      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">row </span><span class="pun">{</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	سأوضّح التعديلات الرئيسية التي طرأت على الشيفرة البرمجية. في البداية أجريت تعديلات تنسيقية على القسم <code>&lt;template&gt;</code> للسماح بإضافة زر جديد اسمه Reset، بالإضافة إلى أنّني غيرت العنصر المسؤول عن عرض بيانات المستخدمين من قاعدة البيانات (كان عبارة عن قائمة غير مرتبة <code>ul</code>)، وذلك لكي أستطيع إضافة زر تعديل Edit بجوار كل مستخدم للسماح بتعديل بياناته في حال الرغبة بذلك.
</p>

<p>
	أضفت أيضًا حقلين جديدين للقسم <code>data</code>، الأول هو <code>currentUserIdToSave</code> ووظيفته الاحتفاظ بالمفتاح الرئيسي للمستخدم الحالي الذي نرغب بتعديل بياناته، أمّا الحقل الثاني فهو <code>actionButtonTitle</code> والذي جعلت قيمته الحالية تظهر مباشرة على الزر Add الذي سيتغير النص الظاهر عليه بحسب السياق. أي عندما نرغب بإضافة مستخدم جديد سيظهر النص Add، أمّا عندما نرغب بتعديل بيانات مستخدم موجود مسبقًا سيظهر النص Save. بمعنى آخر، سيعمل التطبيق على تنفيذ مجموعة مختلفة من التعليمات البرمجية بحسب النص الذي يظهر حاليًا على هذا الزر. لذلك فمن المنطقي تغيير اسم التابع الذي سيُنفّذ عند النقر على هذا الزر، فقد غيرت اسم التابع من <code>postData</code> إلى <code>postOrPutData</code> للإشارة إلى وظيفته الجديدة المتمثلة في الإضافة الجديدة أو التعديل على بيانات موجودة مسبقًا. انظر إلى الشيفرة البرمجية الموجودة ضمن هذا التابع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_23" style="">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">actionButtonTitle </span><span class="pun">===</span><span class="pln"> </span><span class="str">"Add"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
      </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">
        </span><span class="str">"https://vue-remote-servers.firebaseio.com/users.json"</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user
      </span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
        </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">

          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">username </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">firstname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user</span><span class="pun">.</span><span class="pln">lastname </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
      </span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">
        </span><span class="str">"https://vue-remote-servers.firebaseio.com/users/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
          </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentUserIdToSave </span><span class="pun">+</span><span class="pln">
          </span><span class="str">".json"</span><span class="pun">,</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user
      </span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">
        </span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">(</span><span class="pln">error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ عبارة <code>if</code> الموجودة في بداية التابع، وانتبه إلى الشرط الموجود ضمنها. يختبر هذا الشرط فيما إذا كانت القيمة الحالية للحقل <code>actionButtonTitle</code> تساوي القيمة <code>Add</code>. فإذا تحقق هذا الشرط، فهذا يعني أننا نريد إضافة مستخدم جديد، فتُنفّذ الكتلة البرمجية المتعلقة بتحقق ذلك الشرط، وهي نفس الكتلة البرمجية التي كانت موجودة ضمن التابع <code>postData</code> قبل التعديل. أمّا إذا لم يتحقق الشرط، فهذا يعني بالتأكيد أنّنا في السياق الذي يسمح بتعديل بيانات موجودة مسبقًا، لذلك تُنفّذ الكتلة البرمجية الموافقة التي تستخدم في هذه المرة التابع <code>put</code> كما هو واضح. يتم التحكّم في قيمة الحقل <code>actionButtonTitle</code> ضمن التابعين الجديدين <code>prepareToSave</code> و <code>reset</code> كما سنرى ذلك بعد قليل. لنركّز الآن قليلًا على التابع <code>put</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_25" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$http
</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">
    </span><span class="str">"https://vue-remote-servers.firebaseio.com/users/"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">currentUserIdToSave </span><span class="pun">+</span><span class="pln">
        </span><span class="str">".json"</span><span class="pun">,</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">user
    </span><span class="pun">)</span></pre>

<p>
	يقبل هذا التابع وسيطين. الوسيط الأوّل هو عنوان المصدر الذي سنعمل على تعديل بياناته. لاحظ معي كيف وضعت اسم الجدول (المجموعة) <code>users</code> يليه قيمة المفتاح الرئيسي الذي حصلت عليه من قيمة الحقل <code>currentUserIdToSave</code> ثم وضعت الإمتداد الإلزامي <code>‎ .json</code>. أمّا الوسيط الثاني فهو بكل بساطة الكائن <code>user</code> الذي من المفترض الآن أن يحمل البيانات المعدّلة لهذا المستخدم. من الممكن أن نجري تعديل على جزء من البيانات أو على جميع البيانات أو أن لا نجري أية تعديلات. في كل حالة من الحالات السابقة سيتم استبدال بالقيم الحالية لبيانات الكائن <code>user</code> البيانات القديمة الموجودة ضمن قاعدة البيانات والتي لها نفس قيمة المفتاح الرئيسي.
</p>

<p>
	كما أوضحت قبل قليل، فقد أضفت تابعين جديدين هما: <code>prepareToSave</code> و <code>reset</code>، كما أجريت تعديلًا بسيطًا للتابع <code>getData</code>. سأبدأ من التعديل البسيط الذي أجريته على التابع <code>getData</code>. أضفت في الحقيقة حقلًا جديدًا إلى كل كائن يمثّل مستخدم مفترض تم جلبه من قاعدة بيانات. انظر معي إلى حلقة <code>for</code> التي حدث فيها التعديل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3142_27" style="">
<span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">let key in data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    let withId </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">];</span><span class="pln">
    withId</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> key</span><span class="pun">;</span><span class="pln">
    tmpArray</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">data</span><span class="pun">[</span><span class="pln">key</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أنشأت متغير جديد اسمه <code>withId</code> تنحصر وظيفته في إضافة الحقل <code>id</code> إلى البيانات التي تأتي أصلًا من قاعدة البيانات وذلك بهدف الاحتفاظ بالمفتاح الرئيسي لكل مستخدم مع بياناته الأساسية. سنرى سبب هذا التعديل بعد لحظات.
</p>

<p>
	بالنسبة للشيفرة البرمجية لكل من التابعين <code>prepareToSave</code> و <code>reset</code> فهي بسيطة للغاية. بالنسبة للتابع <code>prepareToSave</code> فيُستدعى عند نقر الزر Edit بجوار مستخدم ما. يقبل هذا التابع وسيطًا واحدًا هو قيمة المفتاح الرئيسي لذلك المستخدم الذي نرغب بتعديل بياناته. بعد ذلك ندخل حلقة <code>for</code>، هدفها الوصول إلى الكائن الذي يمثّل المستخدم المراد تعديل بياناته. استطعت تحديد هذا الكائن، وذلك بمقارنة قيمة الوسيط <code>id</code> (الذي يحمل قيمة المفتاح الرئيسي للمستخدم المراد تعديله) مع قيمة الحقل <code>id</code> لكل مستخدم موجود ضمن المصفوفة <code>users</code>. لاحظ هنا أنّ الحقل <code>id</code> الموجود ضمن المصفوفة <code>users</code> قد أضفناه ضمن التابع <code>getData</code>. بعد الوصول إلى الكائن المطلوب ضمن المصفوفة، تعمل الشيفرة على تحديث بيانات الحقل <code>user</code> وبالتالي تتم تعبئة عناصر الإدخال على الصفحة ببيانات المستخدم المراد تعديله، ثم تُعدَّل قيمة الحقل <code>currentUserIdToSave</code> ليحمل قيمة المفتاح الرئيسي لهذا المستخدم المراد تعديله (لاحظ أنّنا استخدمنا قيمة هذا الحقل ضمن التابع <code>postOrPutData</code> بتمريره للتابع <code>put</code>)، وأيضًا تُعدَّل قيمة الحقل <code>actionButtonTitle</code> لتحمل القيمة <code>Save</code>، وهكذا نكون قد دخلنا في سياق حفظ البيانات، أي نكون جاهزين لتعديل بيانات المستخدم.
</p>

<p>
	وأخيرًا بالنسبة للتابع <code>reset</code> فهو يُعيد الأمور إلى أصلها الأول. أي يعمل على تفريغ حقول الإدخال، ويعمل على إعادة السياق إلى حالة إدخال مستخدم جديد بإسناد القيمة <code>Add</code> ضمن الحقل <code>actionButtonTitle</code>، كما يعمل على تفريغ الحقل <code>currentUserIdToSave</code> لأنّه لا يوجد حاليًا أي مستخدم نرغب بتعديل بياناته كما هو واضح.
</p>

<p>
	إذا شغلت التطبيق بعد هذه التعديلات يُفترض أن تحصل على شكل شبيه بما يلي (لاحظ أنّني قد نقرت أيضًا الزر Retrieve):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52265" href="https://academy.hsoub.com/uploads/monthly_2020_10/11.png.ad7aa3c8938c4b2e1a89b6bc5d6594cc.png" rel=""><img alt="11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52265" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/11.thumb.png.c1e8715a0e1a90bf54476aa2923d4f85.png"></a>
</p>

<p>
	جرب نقر زر Edit بجوار أحد المستخدمين، ثم عدّل بياناته، ثم انقر زر Save، وبعدها انقر زر Retrieve من جديد. يجب أن ترى الآن التعديلات التي أجريتها على ذلك المستخدم. انقر زر Reset للعودة إلى سياق إضافة مستخدم جديد.
</p>

<p>
	<strong>ملاحظة:</strong> لا يُعتبر الأسلوب الذي اتبعته في تعديل البيانات أسلوبًا عمليًا في التطبيقات الحقيقة. إذ كان من الواجب الانتقال إلى صفحة منفصلة عند النقر على زر Edit لتعديل بيانات المستخدم بشكل مستقل. لكنني آثرت اتباع هذا الأسلوب غير العملي الآن، لأنّ اتباع الأسلوب العملي يقتضي الدخول في بحث جديد تمامًا وهذا ما سأفعله لاحقًا في درس منفصل إن شاء الله.
</p>

<p>
	<strong>ملاحظة:</strong> من الممكن أيضًا إضافة ميزة حذف مستخدم موجود مسبقًا باستخدام التابع <code>delete</code> مع الكائن <code>‎ $http</code> مع تمرير وسيط واحد فقط له. هو نفسه الوسيط الأوّل للتابع <code>put</code>.
</p>

<h2>
	ختامًا
</h2>

<p>
	لقد تعلّمنا الكثير في هذا الدرس! لقد تعلّمنا كيفية إنشاء قاعدة بيانات بسيطة على Google Firebase، كما وتعلّمنا كيفية استخدام المكتبة vue-resource لإكساب تطبيقات Vue.js القدرة على الاتصال بالانترنت، وبنينا أيضًا تطبيق عملي مبسّط يوضّح كيفية التواصل مع قاعدة البيانات على Google Firebase، وبالتالي كيفية إضافة وقراءة وتعديل البيانات الموجودة ضمنها. يُعتبر هذا الدرس مهمًّا بالفعل، فمن خلاله استطعت للمرة الأولى الخروج من "القمقم" والتواصل مع العالم الخارجي. ستحمل ما تبقى من دروس مفاهيم مهمّة أيضًا حول كيفية التعامل مع Vue.js تلك المكتبة القوية والمرنة.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B0%D8%A7%D8%AA-%D8%B5%D9%81%D8%AD%D8%A9-%D9%88%D8%A7%D8%AD%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%8A%D9%87-routing-%D9%81%D9%8A-vuejs-r1037/" rel="">بناء تطبيقات ذات صفحة واحدة باستخدام التوجيه Routing في Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-filters-%D9%88%D8%A7%D9%84%D9%80%D9%85%D8%AE%D8%A7%D9%84%D9%8A%D8%B7-mixins-%D9%81%D9%8A-vuejs-r1035/" rel="">المرشحات Filters والـمخاليط Mixins في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1036</guid><pubDate>Mon, 02 Nov 2020 13:09:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x631;&#x634;&#x62D;&#x627;&#x62A; Filters &#x648;&#x627;&#x644;&#x640;&#x645;&#x62E;&#x627;&#x644;&#x64A;&#x637; Mixins &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-filters-%D9%88%D8%A7%D9%84%D9%80%D9%85%D8%AE%D8%A7%D9%84%D9%8A%D8%B7-mixins-%D9%81%D9%8A-vuejs-r1035/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/9.png.f9bf6ecf037f75db8051eebf1cbf43fb.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		المرشّح (Filter).
	</li>
	<li>
		المخلوط (Mixin).
	</li>
</ul>
<p>
	سنتابع عملنا في هذه السلسلة مع ميزتين مفيدتين في Vue.js وهما: المرشّحات (Filters) والمخاليط (Mixins). تُعتبر هاتين الميزتين على بساطتهما من المزايا المتقدّمة نسبيًا في Vue.js. سنوضّح المقصود بكل منهما في هذا الدرس، وذلك بكتابة مثالين تطبيقيين بسيطين، لتوضيح الغاية من استخدام هاتين التقنيتين بشكل جيّد.
</p>

<h2>
	المرشّح (Filter)
</h2>

<p>
	المرشّح (Filter) هو ميزة مفيدة في Vue.js يمكن من خلالها تطبيق إجراء معيّن على قيمة حقل ما، بحيث يطرأ تعديل على شكله النهائي عند عرضه للمستخدم.
</p>

<p>
	يمكن تعريف المرشّحات التي نرغب بكتابتها ضمن قسم خاص ضمن كائن Vue.js اسمه <code>filters</code>. فالمرشح في الحقيقة عبارة عن مجرّد تابع يقبل وسيطًا واحدًا، ويرجع قيمة بعد التعديل.
</p>

<p>
	كمثال على ذلك، يمكن استخدام مرشح يعمل على تحويل حالة الأحرف إلى كبيرة (بالنسبة للأحرف الانجليزية)، رغم أنّها قد تكون ضمن الحقل عبارة عن مزيج بين أحرف صغيرة وكبيرة. ربما تكتشف بعد قليل عددا كبيرًا من الأمثلة حول الإمكانات التي قد توفرها المرشّحات. ولكن تذكّر، أنّه من الأفضل دومًا أن تكون المعالجة البرمجية ضمن المرشحات بسيطة وسريعة. فلم تصمّم المرشّحات لإجراء عمليات معقدة على البيانات تكلّف الكثير من إمكانيات المعالجة. فإذا شعرت مثلًا أنّ الأمر يتجه إلى مزيد من التعقيد، فأنصحك بالتفكير باستخدام الخصائص المحسوبة بدلًا من المرشّحات.
</p>

<p>
	لنتناول الآن مثالًا برمجيًا يوضّح كيفية كتابة المرشحات. أنشئ مشروعًا جديدًا باستخدام الأمر <code>vue</code> من موجّه الأوامر وسمّه <code>vue-filters</code> كما يلي:
</p>

<pre class="ipsCode">
vue create vue-filters
</pre>

<p>
	ثم افتح المشروع باستخدام Visual Studio Code. احذف الملف HelloWorld.vue ثم استبدال بما يلي محتويات الملف App.vue:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2107_7" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Filters</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    {{text | toUpper}}
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  data</span><span class="pun">(){</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        text</span><span class="pun">:</span><span class="str">"We will apply a filter on this field."</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  filters</span><span class="pun">:{</span><span class="pln">
    toUpper</span><span class="pun">(</span><span class="pln">value</span><span class="pun">){</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> value</span><span class="pun">.</span><span class="pln">toUpperCase</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="com">#app {</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Avenir</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Helvetica</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#2c3e50;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	انظر إلى القسم الجديد <code>filters</code> كيف عرفت المرشّح <code>toUpper</code> ضمنه على شكل تابع يقبل قيمة وحيدة <code>value</code>. لاحظ كيف يُرجع هذا المرشّح حالة الأحرف الكبيرة لهذه القيمة عن طريق تابع جافاسكريبت وهو <code>toUpperCase</code>.
</p>

<p>
	لاحظ معي الآن طريقة تطبيق المرشّح كما هو ظاهر من الشيفرة السابقة. نضع المحرف | بعد اسم الحقل المراد تطبيق المرشّح عليه، ثم نكتب اسم المرشّح. أي كما في التالي:
</p>

<pre class="ipsCode">
text | toUpper
</pre>

<p>
	وهذا كل شيء. ينبغي الانتباه هنا إلى أنّ المرشّح لن يؤثّر على القيمة الأصلية للحقل <code>text</code> إنما سيجري التعديل على الخرج الذي سيظهر للمستخدم فحسب. جرب الآن معاينة التطبيق البسيط السابق لترى كيف أصبح النص يظهر بأحرف طباعية كبيرة.
</p>

<p>
	الأسلوب السابق في تعريف المرشّحات كقسم ضمن كائن Vue.js يُعتبر تعريفًا محليًا (Local). يمكن تعريف المرشّحات بشكل عام (Global) وذلك عن طريق استخدام التابع <code>Vue.filter</code> ضمن الملف main.js على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2107_9" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln"> from </span><span class="str">'vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App.vue'</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">config</span><span class="pun">.</span><span class="pln">productionTip </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="str">'toLower'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">value</span><span class="pun">){</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> value</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  render</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=&gt;</span><span class="pln"> h</span><span class="pun">(</span><span class="typ">App</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}).</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">)</span></pre>

<p>
	كما هو واضح، يٌمرّر وسيطان إلى التابع <code>filter</code> الأوّل هو اسم المرشّح العام، أمّا الثاني فهو التابع الذي يحتوي على الشيفرة البرمجيّة الخاصة بالمرشّح. المرشّح هنا هو <code>toLower</code> وسنجعله مسؤول عن تحويل الأحرف إلى الحالة الطباعية الصغيرة.
</p>

<p>
	سنعمل الآن على تطبيق المرشّح العام الجديد ضمن الملف <code>App.vue</code> وذلك على المرشّح المحلي القديم على النحو التالي:
</p>

<pre class="ipsCode">
{{text | toUpper | toLower}}
</pre>

<p>
	لاحظ كيف طبقنا المرشّح الجديد بشكل متسلسل على المرشّح القديم. الذي سيحدث الآن، أنّ محتويات الحقل <code>text</code> سيطبّق عليها المرشّح <code>toUpper</code> أولًا، مما سيعطينا حالة أحرف طباعية كبيرة، ثم سيتم تطبيق المرشّح <code>toLower</code> على النتيجة الأخيرة، مما سيؤدي إلى تحويل حالة الأحرف إلى الحالة الطباعية الصغيرة.
</p>

<p>
	كان يمكن بالطبع تطبيق المرشح <code>toLower</code> فقط دون المرشّح <code>toUpper</code> ولكنني فضلت استخدامها بالشكل المتسلسل السابق لتوضيح إمكانية تطبيق أكثر من مرشّح بنفس الوقت بشكل متسلسل كما فعلنا قبل قليل.
</p>

<h2>
	المخلوط (Mixin)
</h2>

<p>
	قد تُضطر في بعض الأحيان إلى كتابة مكوّنات تشترك بنفس الجزء من الشيفرة البرمجية تقريبًا. رغم أنّ ذلك لا يعد مشكلة برمجية أساسًا إلّا أنّه يشكل عادة برمجية غير جيدة. دائمًا ما نسعى في البرمجة إلى تجنّب تكرار الشيفرة البرمجية كما تعلم.
</p>

<p>
	جاء المخلوط (Mixin) ليوجد حلًا لهذه المسألة، حيث من الممكن جعل ذلك الجزء المشترك من المكوّنات ضمنه بحيث تتشارك تلك المكونات بالمخلوط مما يلغي الحاجة إلى تكرار الشيفرة البرمجية.
</p>

<p>
	سنحتاج بالتأكيد إلى مثال عملي يوضّح هذه الفكرة. أنشئ مشروعًا جديدًا وسمّه <code>vue-mixins</code>، ثم افتح المشروع باستخدام Visual Studio Code. احذف الملف HelloWorld.vue، ثم أضف ملفين ضمن المجلّد components، سمّهما على النحو التالي: BMI.vue و ImperialConverter.vue. وأضف أيضًا ملف اسمه ConverterMixin.js إلى المجلّد src.
</p>

<p>
	فكرة هذا التطبيق هي إنشاء مكوّنين الأول هو <code>ImperialConverter</code> يوفر إمكانية التحويل من الكيلوغرام والسنتيمتر إلى الباوند والبوصة على الترتيب. أمّا المكوّن الثاني فهو <code>BMI</code> ووظيفته إعطاء تقرير عن حالة مؤشّر كتلة الجسم (Body Mass Index). يشترك كل من المكونين السابقين بجزء من الشيفرة البرمجية موضوع ضمن المخلوط <code>ConverterMixin</code>. مع العلم أنّ كل من المكونين السابقين مستقلين تمامًا فيما يتعلّق بالبيانات.
</p>

<p>
	يحتوي المخلوط <code>ConverterMixin</code> على الشيفرة البرمجية المسؤولة عن التحويل من الكيلوغرام إلى الباوند، ومن السنتيمتر إلى البوصة. انظر محتويات الملف ConverterMixin.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2107_11" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">ConverterMixin</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            kg_value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
            cm_value</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        to_pounds</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">kg_value </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2.20462</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        to_inches</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">cm_value </span><span class="pun">*</span><span class="pln"> </span><span class="lit">0.393701</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الشيفرة البرمجية الموجودة في المخلوط بسيطة جدًا، حيث تحتوي على حقلي بيانات <code>kg_value</code> و <code>cm_value</code> بالإضافة إلى خاصيتين محسوبتين: <code>to_pounds</code> و <code>to_inches</code>.
</p>

<p>
	بالنسبة للمكون <code>ImperialConverter</code> فهو بسيط أيضًا، انظر للشيفرة البرمجية الموجودة ضمنه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2107_13" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;h2&gt;</span><span class="pln">Kilograms to Pounds Converter</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
      </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="lit">50px</span><span class="pun">;</span><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln">center</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"kg_value"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="lit">8px</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">Kg = {{to_pounds}} pounds.</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
      </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="lit">50px</span><span class="pun">;</span><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln">center</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"cm_value"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="lit">8px</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">CM = {{to_inches}} Inches.</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">ConverterMixin</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../ConverterMixin"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ImperialConverter"</span><span class="pun">,</span><span class="pln">
  mixins</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">ConverterMixin</span><span class="pun">],</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="com">&lt;!-- Add "scoped" attribute to limit CSS to this component only --&gt;</span><span class="pln">
</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	يوفر هذا المكوّن عناصر HTML مناسبة لإدخال البيانات المراد تحويلها وذلك ضمن القسم <code>&lt;template&gt;</code>، أمّا بالنسبة للقسم <code>&lt;script&gt;</code> فنعمل على استيراد المخلوط باستخدام التعليمة <code>import</code> ثم نُخبر Vue.js أنّنا نريد استخدام هذا المخلوط عن طريق القسم <code>mixins</code>. لاحظ أنّه لا توجد شيفرة برمجية فعلية ضمن المكون لأنّه أغلب المنطق الحسابي يحدث ضمن المخلوط في مثالنا البسيط هذا.
</p>

<p>
	أمّا بالنسبة للمكوّن <code>BMI</code> فهو المكوّن المسؤول (كما أشرنا) على حساب مؤشّر كتلة الجسم بالإضافة إلى عرض تقرير بسيط للمستخدم حول القيمة المحسوبة. انظر إلى الشيفرة البرمجية لهذا المكون:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2107_15" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;h2&gt;</span><span class="pln">Body Mass Index (BMI)</span><span class="tag">&lt;/h2&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
      </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;span&gt;</span><span class="pln">Weight (Kg):</span><span class="tag">&lt;/span&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="lit">50px</span><span class="pun">;</span><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln">center</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"kg_value"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;span&gt;</span><span class="pln">Height (Cm):</span><span class="tag">&lt;/span&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">width</span><span class="pun">:</span><span class="lit">50px</span><span class="pun">;</span><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln">center</span><span class="pun">;</span><span class="atv">"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"cm_value"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
      </span><span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;span&gt;</span><span class="pln">BMI value: {{bmi_value}}</span><span class="tag">&lt;/span&gt;</span><span class="pln"> -
        </span><span class="tag">&lt;span&gt;</span><span class="pln">{{result}}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">ConverterMixin</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../ConverterMixin"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"BMI"</span><span class="pun">,</span><span class="pln">
  mixins</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="typ">ConverterMixin</span><span class="pun">],</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    bmi_value</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="lit">703</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">to_pounds</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">to_inches </span><span class="pun">*</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">to_inches</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    result</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">16</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Severe Thinness"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">17</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Moderate Thinness"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">18.5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Mild Thinness"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">25</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Normal"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">30</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Overweight"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">35</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Obese Class I"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">40</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Obese Class II"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">bmi_value </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">40</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Obese Class III"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Not defined!"</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="com">&lt;!-- Add "scoped" attribute to limit CSS to this component only --&gt;</span><span class="pln">
</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	مرة أخرى، يوفّر القسم <code>&lt;template&gt;</code> واجهة المستخدم، أمّا القسم <code>&lt;script&gt;</code> فنستورد عن طريقه المخلوط <code>ConverterMixin</code> ونصرح عن استخدامه كما فعلنا تمامًا مع المكون <code>ImperialConverter</code> قبل قليل. بقي أخيرًا الملف App.vue الذي سنستخدم من خلاله المكونين السابقين. انظر إلى الشيفرة البرمجية لهذا الملف:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2107_17" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">"Vue logo"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"./assets/logo.png"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;imperial-converter/&gt;</span><span class="pln">
    </span><span class="tag">&lt;BMI/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ImperialConverter</span><span class="pln"> from </span><span class="str">'./components/ImperialConverter.vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> BMI from </span><span class="str">'./components/BMI.vue'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'App'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">ImperialConverter</span><span class="pun">,</span><span class="pln">
    BMI
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="com">#app {</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Avenir</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Helvetica</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Arial</span><span class="pun">,</span><span class="pln"> sans</span><span class="pun">-</span><span class="pln">serif</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
  text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#2c3e50;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	بعد تشغيل التطبيق ستحصل على واجهة شبيهة بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52253" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.5cffe06755056257a3770fa275a0ccdb.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52253" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.a3dd012199e4b44400290d56fe1787ac.png"></a>
</p>

<h2>
	ختامًا
</h2>

<p>
	تحدثنا في هذا الدرس عن ميزتين جديدتين من مزايا Vue.js، وهما: المرشّحات (Filters) والمخاليط (Mixins)، حيث قد وجدنا أنّ المرشحات هي عبارة عن شيفرات برمجية بسيطة تعمل على إجراء منطق برمجي بسيط وسريع دون الحاجة لاستخدام التوابع أو الخاصيات المحسوبة. أمّا المخاليط فوجدنا أنّها تقنية مفيدة للتخلص من تكرار الشيفرة البرمجية بين المكوّنات المختلفة، حيث يُوضع القسم البرمجي المشترك بين مكوّنين أو أكثر ضمن ملف منفصل دعوناه بالمخلوط، وتعمل المكوّنات المختلفة بعد ذلك على استخدام هذا المخلوط وتتجنّب تكرار الشيفرة البرمجية.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A8%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r1036/" rel="">استخدام Vue.js للاتصال بالإنترنت</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AF%D8%AE%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%B9%D9%86-%D8%B7%D8%B1%D9%8A%D9%82-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%A5%D8%AF%D8%AE%D8%A7%D9%84-%D9%81%D9%8A-vuejs-r1034/" rel="">التعامل مع دخل المستخدم عن طريق نماذج الإدخال في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1035</guid><pubDate>Fri, 30 Oct 2020 13:06:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x62F;&#x62E;&#x644; &#x627;&#x644;&#x645;&#x633;&#x62A;&#x62E;&#x62F;&#x645; &#x639;&#x646; &#x637;&#x631;&#x64A;&#x642; &#x646;&#x645;&#x627;&#x630;&#x62C; &#x627;&#x644;&#x625;&#x62F;&#x62E;&#x627;&#x644; &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AF%D8%AE%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%B9%D9%86-%D8%B7%D8%B1%D9%8A%D9%82-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%A5%D8%AF%D8%AE%D8%A7%D9%84-%D9%81%D9%8A-vuejs-r1034/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/8.png.b406556ee8913fa8b743d1872651ec16.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		بناء هيكل تطبيق بسيط لشرح أفكار الدرس
	</li>
	<li>
		استخدام إطار العمل Bootstrap
	</li>
	<li>
		استخدام بنى معطيات متقدمة مع عناصر الإدخال النصية
	</li>
	<li>
		المعدِّلات (Modifiers) في Vue.js
	</li>
	<li>
		التعامل مع مربعات الاختيار (Checkboxes) وأزرار الانتقاء (Radiobuttons)
	</li>
	<li>
		التعامل مع القائمة المنسدلة <code>&lt;select&gt;</code>
	</li>
	<li>
		إرسال البيانات ‎
	</li>
</ul>
<p>
	لقد تعاملنا في بداية <a href="https://academy.hsoub.com/tags/%D9%85%D9%82%D8%AF%D9%85%D8%A9%20%D8%A5%D9%84%D9%89%20vuejs/" rel="">هذه السلسلة</a> مع عناصر الإدخال العادية التي يستخدمها المستخدم لإدخال البيانات ضمن صفحات الويب. سنعمل في هذا الدرس على التوسّع في التعامل مع هذه العناصر بالإضافة إلى الاطلاع على طريقة التعامل مع عناصر إدخال HTML جديدة. كما سنتعلّم كيفية التعامل مع أُطر عمل CSS جاهزة، حيث لم يسبق لنا التعامل معها مسبقًا.
</p>

<h2>
	بناء هيكل تطبيق بسيط لشرح أفكار الدرس
</h2>

<p>
	كما جرت العادة، سنبني تطبيق بسيط من أجل هذا الدرس بهدف تطبيق الأفكار الواردة فيه. سيتكوّن تطبيقنا من صفحة واحدة فقط تحوي عدد من عناصر HTML التي ننوي التعامل معها. أنشئ مشروع جديد وسمّه input-forms-cli كما فعلنا مسبقًا في الدرس السابق (راجع الفقرة "بناء هيكل تطبيق بسيط لشرح أفكار الدرس"). بعد الانتهاء من عملية الإنشاء، استخدم Visual Studio Code في فتح المشروع (المجلّد) الذي أنشأته توًّا.
</p>

<p>
	لن نحتاج سوى ملف مكوّن واحد وهو App.vue لذلك احذف الملف HelloWorld.vue كما فعلنا في الدرس السابق. ثم افتح الملف App.vue واستبدل المحتوى الحالي بالشيفرة البرمجية التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7784_6" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;form&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"text-right"</span><span class="tag">&gt;</span><span class="pln">الملف الشخصي للمستخدم</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
                    </span><span class="tag">&lt;hr&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"firstname"</span><span class="tag">&gt;</span><span class="pln">الاسم</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"firstname"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.firstname"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"lastname"</span><span class="tag">&gt;</span><span class="pln">الكنية</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"lastname"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.lastname"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"age"</span><span class="tag">&gt;</span><span class="pln">العمر</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"number"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"age"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.age"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"password"</span><span class="tag">&gt;</span><span class="pln">كلمة المرور</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.password"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 form-group"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"description"</span><span class="tag">&gt;</span><span class="pln">نبذة</span><span class="tag">&lt;/label&gt;&lt;br&gt;</span><span class="pln">
                    </span><span class="tag">&lt;textarea</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"description"</span><span class="pln"> </span><span class="atn">rows</span><span class="pun">=</span><span class="atv">"5"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"description"</span><span class="tag">&gt;&lt;/textarea&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"graduate"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"graduate"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"متخرج"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"status"</span><span class="tag">&gt;</span><span class="pln"> متخرج
                        </span><span class="tag">&lt;/label&gt;</span><span class="pln">
                        </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"smoker"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"working"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"أعمل حاليًا"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"status"</span><span class="tag">&gt;</span><span class="pln"> أعمل حاليًا
                        </span><span class="tag">&lt;/label&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 form-group"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"male"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"male"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"ذكر"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"gender"</span><span class="tag">&gt;</span><span class="pln"> </span><span class="tag">&lt;span&gt;</span><span class="pln">ذكر</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/label&gt;</span><span class="pln">
                    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"female"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"female"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"أنثى"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"gender"</span><span class="tag">&gt;</span><span class="pln"> </span><span class="tag">&lt;span&gt;</span><span class="pln">أنثى</span><span class="tag">&lt;/span&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/label&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 from-group"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"subscriptionKind"</span><span class="tag">&gt;</span><span class="pln">نوع الاشتراك</span><span class="tag">&lt;/label&gt;</span><span class="pln">
                    </span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"subscriptionKind"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"selectedSubscription"</span><span class="tag">&gt;</span><span class="pln">

                        </span><span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"kind in subscriptionKinds"</span><span class="pln"> </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"kind"</span><span class="tag">&gt;</span><span class="pln">
                            {{ kind }}
                        </span><span class="tag">&lt;/option&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/select&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;hr&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-1"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="tag">&gt;</span><span class="pln">إرسال
                    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/form&gt;</span><span class="pln">
        </span><span class="tag">&lt;hr&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"row"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card card-info"</span><span class="tag">&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-header text-right"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;h4&gt;</span><span class="pln">البيانات المُدخلة</span><span class="tag">&lt;/h4&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-body"</span><span class="tag">&gt;</span><span class="pln">
                        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"card-text text-right"</span><span class="tag">&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">الاسم:{{ userMainData.firstname }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">الكنية:{{ userMainData.lastname }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">العمر:{{ userMainData.age }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">كلمة المرور:{{ userMainData.password }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">نبذة: {{ description }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;&lt;strong&gt;</span><span class="pln">الوضع الحالي</span><span class="tag">&lt;/strong&gt;&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;ul&gt;</span><span class="pln">
                                </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"item in status"</span><span class="pln"> </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"item"</span><span class="tag">&gt;</span><span class="pln">{{ item }}</span><span class="tag">&lt;/li&gt;</span><span class="pln">
                            </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">النوع:{{ gender }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                            </span><span class="tag">&lt;p&gt;</span><span class="pln">نوع الاشتراك: {{ selectedSubscription }}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
                        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
                </span><span class="tag">&lt;/div&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
    </span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                userMainData</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln">
                    lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln">
                    age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
                    password</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln">
                </span><span class="pun">},</span><span class="pln">
                description</span><span class="pun">:</span><span class="pln"> </span><span class="str">'اكتب نبذة قصيرة عنك!'</span><span class="pun">,</span><span class="pln">
                status</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
                gender</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ذكر'</span><span class="pun">,</span><span class="pln">
                selectedSubscription</span><span class="pun">:</span><span class="pln"> </span><span class="str">'فضي'</span><span class="pun">,</span><span class="pln">
                subscriptionKinds</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'ذهبي'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'فضي'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'عادي'</span><span class="pun">]</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
    </span><span class="lit">@import</span><span class="pln"> </span><span class="str">"./assets/styles/app.css"</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	أضف مجلّدًا جديدًا ضمن المجلّد assets وسمّه styles ثم أضف ملفًا جديدًا ضمن المجلّد الأخير وسمّه app.css كما فعلنا في الدرس السابق.
</p>

<p>
	احرص أن تكون محتويات الملف app.css على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_8874_9" style="">
<span class="lit">@import</span><span class="pln"> url</span><span class="pun">(</span><span class="com">//fonts.googleapis.com/earlyaccess/notonaskharabic.css);</span><span class="pln">

body</span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Noto Naskh Arabic'</span><span class="pun">,</span><span class="pln"> serif</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ جميع التعديلات، ثم افتح موجّه الأوامر في ويندوز، وبعدها انتقل إلى مجلد التطبيق input-forms-cli الذي أنشأته قبل قليل، ونفّذ الأمر:
</p>

<pre class="ipsCode">
npm run serve
</pre>

<p>
	يعمل هذا الأمر كما نعلم على تشغيل خادوم الويب الخاص بالتطوير، اذهب الآن إلى متصفح الويب لديك، وانتقل إلى العنوان <a href="http://localhost:8080/" ipsnoembed="true" rel="external nofollow">http://localhost:8080/</a> ليظهر لك شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52241" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.4d3b1909aad7221da295123a02c1af9c.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52241" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.179d009c1ef54099993bd3fed32538c7.png"></a>
</p>

<h2>
	استخدام إطار العمل Bootstrap
</h2>

<p>
	ربما تكون قد استغربت قليلًا من عدم استخدامنا لأي مكتبة أو إطار عمل CSS في عمليات التنسيق التي كنا نجريها في تطبيقاتنا السابقة. بدلًا عن ذلك، كنا نستخدم شيفرة CSS عادية فحسب في تنسيق التطبيقات.
</p>

<p>
	يعود سبب ذلك إلى أنّه لا يُنصح أبدًا إضافة إطار عمل CSS بالطريقة التقليدية التي تتمثل في استخدام الوسم <code>&lt;link&gt;</code> كما يفعل أغلبنا عند تطوير تطبيقات أمامية (Frontend Applications). يعود السبب في ذلك لأنّ أغلب أُطر عمل CSS تحتوي على شيفرة JavaScript قد لا تكون متوافقة مع Vue.js.
</p>

<p>
	علينا إذًا استخدام إطار عمل CSS نضمن أن يكون متوافقًا مع Vue.js لكي لا تحصل مفاجآت غير مرغوبة! سأتحدث هنا عن استخدام إطار العمل الشهير Bootstrap لكي نُكسب تطبيقاتنا تنسيقات جميلة وقوية وبشكل متوافق مع Vue.js.
</p>

<p>
	افتح نافذة موجه الأوامر في ويندوز، ثم نفّذ الأمر التالي:
</p>

<pre class="ipsCode">
npm install bootstrap@4.0.0
</pre>

<p>
	بعد الانتهاء وعودة موجه الأوامر إلى حالته الطبيعية، أضف السطر التالي إلى الملف main.js:
</p>

<pre class="ipsCode">
import "bootstrap/dist/css/bootstrap.min.css";
</pre>

<p>
	ستصبح محتويات الملف main.js مشابهة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8874_11" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Vue</span><span class="pln"> from </span><span class="str">'vue'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App.vue'</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">config</span><span class="pun">.</span><span class="pln">productionTip </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"bootstrap/dist/css/bootstrap.min.css"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  render</span><span class="pun">:</span><span class="pln"> h </span><span class="pun">=&gt;</span><span class="pln"> h</span><span class="pun">(</span><span class="typ">App</span><span class="pun">),</span><span class="pln">
</span><span class="pun">}).</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">)</span></pre>

<p>
	نكون بهذا الشكل قد نصبنا إطار العمل Bootstrap ومن ثمّ أضفناه إلى التطبيق الخاص بنا ليصبح جاهزًا للاستخدام. وهكذا نكون قد استغنينا عن كتابة تنسيقات مخصّصة إلى حد كبير.
</p>

<h2>
	استخدام بنى معطيات متقدمة مع عناصر الإدخال النصية
</h2>

<p>
	في الحقيقة رغم أنّ عنوان هذه الفقرة مغرٍ بعض الشيء، إلّا أنّنا في الواقع سنستخدم كائن JavaScript عادي لتمثيل بيانات المستخدم الأساسية ضمن تطبيقنا الحالي. إذا راجعت شيفرة التطبيق الأساسية التي أوردتها في الفقرة الأولى، وتحديدًا ضمن القسم <code>&lt;script&gt;</code> ستجد البنية البسيطة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8874_13" style="">
<span class="pln">userMainData</span><span class="pun">:{</span><span class="pln">
            firstname</span><span class="pun">:</span><span class="str">''</span><span class="pun">,</span><span class="pln">
            lastname</span><span class="pun">:</span><span class="str">''</span><span class="pun">,</span><span class="pln">
            age</span><span class="pun">:</span><span class="lit">0</span><span class="pun">,</span><span class="pln">
            password</span><span class="pun">:</span><span class="str">''</span><span class="pun">,</span><span class="pln">
          </span><span class="pun">}</span></pre>

<p>
	كما أوضحت، سيحمل الحقل <code>userMainData</code> بيانات المستخدم الرئيسية التالية على الترتيب: الاسم، الكنية، العمر، كلمة المرور.
</p>

<p>
	السؤال هنا، كيف سنربط عناصر HTML الموافقة؟ الجواب بسيط، سنستخدم <code>v-model</code> للربط ثنائي الاتجاه. انظر إلى الشيفرة المقتطعة من الشيفرة الموجودة ضمن القسم <code>&lt;template&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7784_10" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"firstname"</span><span class="tag">&gt;</span><span class="pln">الاسم</span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"firstname"</span><span class="pln">
            </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.firstname"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"lastname"</span><span class="tag">&gt;</span><span class="pln">الكنية</span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"lastname"</span><span class="pln">
            </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.lastname"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"age"</span><span class="tag">&gt;</span><span class="pln">العمر</span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"number"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"age"</span><span class="pln">
            </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.age"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-group"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"password"</span><span class="tag">&gt;</span><span class="pln">كلمة المرور</span><span class="tag">&lt;/label&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"password"</span><span class="pln">
            </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"form-control"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"userMainData.password"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	لاحظ معي كيف استخدمت الحقل <code>userMainData</code> لربط كل خاصية من خصائصه بعنصر HTML الموافق. انظر مثلًا ماذا استخدمت لربط حقل الاسم <code>firstname</code>:
</p>

<pre class="ipsCode">
userMainData.firstname
</pre>

<p>
	لقد استخدمت النقطة للفصل بين <code>userMainData</code> وبين <code>firstname</code> وهذا جائز تمامًا! يمكنك مراجعة باقي عناصر HTML لترى كيف استخدمت نفس الترميز السابق. الفائدة في استخدام هذا الأسلوب هي في تنظيم وتمثيل البيانات بشكل منطقي في التطبيق.
</p>

<p>
	حاول كتابة أي شيء ضمن الحقول الأربعة السابقة، ستجد أنّ ذلك سينعكس مباشرة على القسم السفلي (البيانات المُدخلة) من الصفحة، والذي جعلته خصيصًا لمشاهدة النتائج التي سنجريها على البيانات في القسم العلوي.
</p>

<p>
	في الحقيقة لقد تعاملنا مسبقًا مع عناصر الإدخال العادية فيما سبق من دروس، وسنتعامل مع أنواع أخرى من عناصر الإدخال في هذا الدرس. أحد العناصر الجديدة التي سنتعامل معها هو العنصر <code>&lt;textarea&gt;</code> والذي نتعامل معه كما نتعامل مع عناصر الإدخال العادية تمامًا. إذ وضعت الموجّه <code>v-model</code> ضمن هذا العنصر ليرتبط مع الحقل <code>description</code> كما هو واضح من الشيفرة الواردة في الفقرة الأولى من هذا الدرس.
</p>

<h2>
	المُعدِّلات (Modifiers) في Vue.js
</h2>

<p>
	يحتاج المبرمج في بعض الأحيان إلى تعديل سلوك الاستجابة لـ Vue.js. فمثلًا إذا لاحظت في تطبيقنا هذا، أنّ أي شيء تكتبه ضمن أي عنصر من عناصر الإدخال النصية، سينعكس مباشرة ضمن القسم السفلي. قد يكون هذا السلوك غير مرغوب أحيانًا، فقد ترغب ربما بأن لا يستجيب Vue.js مباشرةً لما يكتبه المستخدم، بل بأن تؤجّل هذه الاستجابة حتى ينتهي المستخدم مما يكتبه وينتقل إلى حقل نصي آخر مثلًا.
</p>

<p>
	السيناريو السابق ممكن تمامًا باستخدام تقنية المعدِّلات (modifiers) حيث يمكن أن نستخدم المعدِّل <code>lazy</code> لكي نخبر Vue.js بأن يؤجّل الاستجابة لأي عنصر إدخال مرتبط معه ريثما يعمل المستخدم على مغادرة هذا العنصر (يُفقده التركيز Focus). انتقل إلى الشيفرة البرمجية الخاصة بعنصر الإدخال <code>firstname</code> ضمن <code>&lt;template&gt;</code> ثم أضف المعدّل <code>lazy</code> إلى الموجّه <code>v-model</code> على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8874_17" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">.</span><span class="pln">lazy</span><span class="pun">=</span><span class="str">"userMainData.firstname"</span></pre>

<p>
	احفظ التغييرات، ثم حاول كتابة شيء ما ضمن الحقل <code>firstname</code> ولا تحاول مغادرة الحقل، ستجد هذه المرة أنّ ذلك لن ينعكس مباشرة ضمن القسم السفلي. غادر الآن ذلك الحقل إلى حقل آخر، ستجد أنّ بيانات الاسم قد ظهرت دفعة واحدة في القسم السفلي.
</p>

<p>
	توجد معدّلات أخرى مثل <code>number</code> الذي يُستخدم لكي يُفسَّر دخل المستخدم على أنّه رقم بدلًا من النص. وهناك أيضًا المعدّل <code>trim</code> الذي يُستخدم للتخلص من المحارف الفارغة على يمين ويسار النص المُدخَل. يمكن استخدام أي معدّل كما استخدمنا المعدّل <code>lazy</code> قبل قليل، كما ويمكن استخدامها بشكل مركّب. انظر مثلًا كيف يمكن استخدام المعدلين <code>lazy</code> و <code>trim</code> بشكل مركّب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8874_19" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">.</span><span class="pln">lazy</span><span class="pun">.</span><span class="pln">trim </span><span class="pun">=</span><span class="pln"> </span><span class="str">"userMainData.firstname"</span><span class="pln"> </span></pre>

<h2>
	التعامل مع مربعات الاختيار (Checkboxes) وأزرار الانتقاء (Radiobuttons)
</h2>

<p>
	سنتعلّم في هذه الفقرة كيفية التعامل مع مربع الاختيار (Checkbox) وزر الانتقاء (Radiobutton). سنبدأ أولًا مع مربع الاختيار.
</p>

<p>
	في تطبيقنا هذا، سنستخدم مربّعي اختيار للتعبير عن كون المستخدم متخرّج أم غير متخرّج. بهدف التعامل مع هذين المربعين، عرّفت حقلًا جديدًا اسمه <code>status</code> على أنّه مصفوفة (انظر القسم <code>&lt;script&gt;</code>). ربطت هذه المصفوفة مع مربعي الاختيار بإسنادها إلى الموجّه <code>v-model</code> لكل من المربعين. انظر الشيفرة المقتطعة من القسم <code>&lt;template&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7784_12" style="">
<span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"graduate"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"graduate"</span><span class="pln">
            </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"متخرج"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"status"</span><span class="tag">&gt;</span><span class="pln"> متخرج
</span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"smoker"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"working"</span><span class="pln">
            </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"أعمل حاليًا"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"status"</span><span class="tag">&gt;</span><span class="pln"> أعمل حاليًا
</span><span class="tag">&lt;/label&gt;</span></pre>

<p>
	لاحظ كيف أنّنا ربطنا مربعي الاختيار بنفس الشكل. الذي سيحدث وراء الكواليس، هو أنّه عندما يختار المستخدم أحد المربّعين سيعمل Vue.js على إدراج قيمة الحقل الذي تمّ اختياره كعنصر في المصفوفة <code>status</code>، فإذا اختار المستخدم كلا المربعين، فسيدرج Vue.js عنصرين ضمن المصفوفة، يعبّر كل منهما عن قيمة مربّع الاختيار. أي أنّ عدد عناصر المصفوفة سيكون مساويًا لعدد المربعات التي اختارها المستخدم، طالما أنّ هذه المربعات قد تمّ ربطها بنفس الشكل.
</p>

<p>
	يمكن تطبيق نفس المبدأ تقريبًا على أزرار الانتقاء، في تطبيقنا هذا لدينا زري انتقاء يُعبّران عن نوع المستخدم (ذكر أم أنثى). عرّفت حقلًا جديدًا أسميته <code>gender</code> يحمل القيمة الافتراضية <code>ذكر</code>. انظر معي إلى الشيفرة المقتطعة من القسم <code>&lt;template&gt;</code> لزري الانتقاء:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7784_14" style="">
<span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"male"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"male"</span><span class="pln">
            </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"ذكر"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"gender"</span><span class="tag">&gt;</span><span class="pln"> </span><span class="tag">&lt;span&gt;</span><span class="pln">ذكر</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/label&gt;</span><span class="pln">
</span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"float-right"</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"female"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln">
            </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"radio"</span><span class="pln">
            </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"female"</span><span class="pln">
            </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"أنثى"</span><span class="pln">
            </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"gender"</span><span class="tag">&gt;</span><span class="pln"> </span><span class="tag">&lt;span&gt;</span><span class="pln">أنثى</span><span class="tag">&lt;/span&gt;</span><span class="pln">
</span><span class="tag">&lt;/label&gt;</span></pre>

<p>
	لاحظ معي بدايةً أنّني قد وضعت القيمة <code>value</code> لكل من الزرين السابقين لتكونا <code>ذكر</code> و <code>أنثى</code> على الترتيب. لاحظ أيضًا كيف استخدمت نفس أسلوب الربط باستخدام الموجّه <code>v-model</code> لكل من هذين الزرين.
</p>

<p>
	الذي سيحدث عند بدء تشغيل التطبيق أنّ الحقل <code>gender</code> سيحمل القيمة <code>ذكر</code> بشكل افتراضي كما ذكرت قبل قليل، وبالتالي سيختار Vue.js الزر المعبّر عن الـ "ذكر" لأنّ قيمته ستكون مماثلة لقيمة الحقل <code>gender</code> في هذه الحالة. وهذا ما يبرّر الاختيار الافتراضي لهذا الزر عند البدء بتشغيل التطبيق.
</p>

<p>
	جرب أن تجري الآن بعض التجارب على مربعي الاختيار وزري الانتقاء، ولاحظ النتائج التي ستحدث ضمن القسم السفلي المخصّص لعرض البيانات.
</p>

<h2>
	التعامل مع القائمة المنسدلة <code>&lt;select&gt;</code>
</h2>

<p>
	بقي لنا أن نتعلّم كيفية الربط مع القائمة المنسدلة <code>&lt;select&gt;</code>. سينقسم عملنا هنا إلى قسمين. الأوّل هو تعبئة هذه القائمة، والثاني هو الربط مع Vue.js باستخدام الموجّه <code>v-model</code>.
</p>

<p>
	بالنسبة لتعبئة هذه القائمة بالبيانات الأولية التي سيختار منها المستخدم، فقد عرّفت الحقل <code>subscriptionKinds</code> وهو على شكل مصفوفة تحوي العناصر التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8874_25" style="">
<span class="pln">subscriptionKinds</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'ذهبي'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'فضي'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'عادي'</span><span class="pun">]</span></pre>

<p>
	تعبّر هذه المصفوفة عن نوع الاشتراك الذي يرغب المستخدم باعتماده. سيكون لدينا كما هو واضح ثلاثة اشتراكات. الشيفرة البرمجية المسؤولة عن تعبئة عنصر القائمة هي التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8874_27" style="">
<span class="tag">&lt;option</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"kind in subscriptionKinds"</span><span class="pln"> </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"kind"</span><span class="tag">&gt;</span><span class="pln">
                          {{ kind }}
                        </span><span class="tag">&lt;/option&gt;</span></pre>

<p>
	هذه الشيفرة مأخوذة من القسم <code>&lt;template&gt;</code> بالطبع. وهي عبارة عن حلقة بسيطة تعمل على تعبئة القائمة من خلال توليد عناصر <code>&lt;option&gt;</code> العمود الفقري لعنصر القائمة <code>&lt;select&gt;</code>.
</p>

<p>
	بالنسبة لعملية الربط فقد عرّفت حقلًا آخرًا أسميته <code>selectedSubscription</code> وأسندت له القيمة الافتراضية <code>فضي</code>. لاحظ معي أنّ هذه القيمة مماثلة للعنصر الثاني من عناصر المصفوفة <code>subscriptionKinds</code>. بعد ذلك، ربطت عنصر القائمة باستخدام <code>v-model</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8874_29" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">=</span><span class="str">"selectedSubscription"</span></pre>

<p>
	وهكذا وعند تشغيل التطبيق للمرة الأولى، سيظهر العنصر الثاني <code>فضي</code> وقد اختير بشكل افتراضي. جرب الآن أن تغير خياراتك ضمن القائمة وانظر كيف سينعكس ذلك ضمن القسم السفلي المخصّص لعرض البيانات.
</p>

<h2>
	إرسال البيانات
</h2>

<p>
	كما هو معلوم، عند وضع عنصر الزر <code>button</code> ضمن عنصر النموذج <code>form</code>، فسيؤدي نقر هذا الزر إلى إرسال بيانات النموذج (form) إلى الخادوم. في تطبيقنا البسيط هذا، وضعنا زرًا لإرسال البيانات كما تعلم، ولكن بما أنّه ليس لدينا حاليًا أي تطبيق يعمل على الخادوم لمعالجة لبيانات المرسلة، لذلك سنعمل على معالجة البيانات محليًّا بشكل وهمي، لذلك سنغيّر من سلوك هذا الزر لكي نمنعه من التصرف بالشكل الافتراضي.
</p>

<p>
	سنستخدم لهذه الغاية المعدِّل <code>prevent</code> مع الموجّه <code>v-on:click</code>. اعمل على تعديل شيفرة HTML الخاصة بزر الإرسال لتصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8874_31" style="">
<span class="pln"> </span><span class="tag">&lt;button</span><span class="pln">
    </span><span class="atn">v-on:click</span><span class="pln">.</span><span class="atn">prevent</span><span class="pun">=</span><span class="atv">"submitInfo"</span><span class="pln">
    </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"btn btn-primary"</span><span class="tag">&gt;</span><span class="pln">إرسال
</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	سنضيف القسم <code>method</code> لكي نتمكّن من تعريف التابع <code>submitInfo</code>. سأضع هنا كامل قسم <code>&lt;script&gt;</code> بعد التعديل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5286_6" style="">
<span class="pln">methods</span><span class="pun">:{</span><span class="pln">
    submitInfo</span><span class="pun">(){</span><span class="pln">
        alert</span><span class="pun">(</span><span class="str">"تمت معالجة البيانات"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وضعت رسالة بسيطة تشير إلى أنّ البيانات قد تمت معالجتها بشكل افتراضي محليًّا. يمكن أن تضع بدلًا من هذه الرسالة أن شيفرة قد تجدها مناسبة للبيانات التي أدخلها المستخدم. الهدف هنا هو أن تفهم المبدأ بحيث يمكنك تكييفه فيما بعد بحسب احتياجاتك.
</p>

<h2>
	ختامًا
</h2>

<p>
	تعلّمنا في هذا الدرس كيفية استخدام أُطر عمل جاهزة لتنسيق المحتوى، حيث استخدمنا في هذا الدرس إطار العمل الشهير Bootstrap. كما تعلّمنا كيف نتعامل مع عدد من عناصر HTML المخصّصة لاستقبال الدخل من المستخدم، حيث تعاملنا مع عناصر الإدخال النصية البسيطة بالإضافة إلى عنصر الإدخال ذو الأسطر المتعدّدة <code>&lt;textarea&gt;</code> وأيضًا مربعات الاختيار وأزرار الانتقاء وعنصر القائمة المنسدلة. في الحقيقة، يمكن أن تبني عناصر إدخال مخصّصة بك وفق احتياجاتك الخاصة وذلك باستخدام المكوّنات كما مرّ معنا في دروس سابقة. أرجو لك الفائدة من هذا الدرس، أراك في الدروس القادمة إن شاء الله.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-filters-%D9%88%D8%A7%D9%84%D9%80%D9%85%D8%AE%D8%A7%D9%84%D9%8A%D8%B7-mixins-%D9%81%D9%8A-vuejs-r1035/" rel="">المرشحات Filters والـمخاليط Mixins في Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-vuejs-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vue-cli-r1033/" rel="">إنشاء مشاريع Vue.js باستخدام Vue CLI</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1034</guid><pubDate>Mon, 26 Oct 2020 13:07:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x645;&#x634;&#x627;&#x631;&#x64A;&#x639; Vue.js &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Vue CLI</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-vuejs-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vue-cli-r1033/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.6bf322c7336131f217c83737c41cac55.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		لماذا Vue CLI؟
	</li>
	<li>
		إعداد Vue CLI
	</li>
	<li>
		إنشاء مشروع جديد باستخدام Vue CLI
	</li>
	<li>
		نظرة عامة على هيكل المشروع
	</li>
	<li>
		تعديل تطبيق مشاريب حسوب حسب الأسلوب الجديد
	</li>
</ul>
<p>
	سنتعرّف في هذا الدرس على Vue CLI ولماذا نحتاجه. وسنتعرّف أيضًا على كيفية إعداد Vue CLI بالتفصيل، ثم سنعمل على موائمة تطبيق "مشاريب حسوب" الذي بنيناه في الدرس السابق لكي يتوافق مع Vue CLI.
</p>

<h2>
	لماذا Vue CLI؟
</h2>

<p>
	بدأنا <a href="https://academy.hsoub.com/tags/%D9%85%D9%82%D8%AF%D9%85%D8%A9%20%D8%A5%D9%84%D9%89%20vuejs/" rel="">سلسلة Vue.js</a> بكتابة التطبيقات التي نحتاج لها ضمن <a href="https://jsfiddle.net/" rel="external nofollow">موقع JSFiddle</a>، ثم طورنا عملنا بأن استخدمنا محرّر الشيفرة البرمجية Visual Studio Code بحيث أصبحنا نكتب تطبيقاتنا محليًّا باستخدمه، ثم نجرب هذه التطبيقات عن طريق الإضافة Live Server.
</p>

<p>
	السيناريو الأخير جيّد في الواقع ولكن قد يكون في بعض الأحيان غير كاف. وخاصةً إذا بدأت بكتابة تطبيقات أكبر وأكثر تعقيدًا باستخدام المكوّنات التي تكتبها أنت والتي تحتاجها في تطبيقاتك.
</p>

<p>
	المشكلة التي ستواجهها هي التداخل بين الشيفرة الخاصة بالمكوّنات مع الشيفرة الخاصة بالتطبيق، وهذا يحدث على مستوى شيفرة JavaScript و شيفرة HTML وحتى تنسيقات CSS. في حال التطبيقات الكبيرة سيكون هذا التداخل مزعج وأكثر عرضة للأخطاء. لذلك فمن الحكمة أحيانًا الانتقال إلى مستوى أعلى في بناء تطبيقات عملية وواقعية باستخدام أدوات تطوير فعًالة ومناسبة.
</p>

<p>
	بغية تحقيق هذا الهدف، سنستخدم في هذا الدرس Vue CLI وهي واجهة موجّه الأوامر الخاص بـ Vue.js. باختصار، هي عبارة عن حزمة برمجيّة تسمح لنا ببناء الهيكل الأساسي لتطبيق Vue.js تمهيدًا لكتابة الشيفرة، بالإضافة إلى تزويدنا بخادوم تطوير بسيط (مختلف عن الخادوم Live Server) يسمح لنا بمحاكاة الظروف الفعلية التي سيعمل ضمنها هذا التطبيق. توجد عدة قوالب مُتاحة يستطيع Vue.js توليدها لك، سنستخدم أبسطها في هذا الدرس.
</p>

<h2>
	إعداد Vue CLI
</h2>

<p>
	نستطيع تثبيت Vue CLI على مختلف أنواع أنظمة التشغيل الأساسية (Windows, Linux, Mac OS) بنفس الأسلوب تقريبًا. سأركّز هنا على نظام التشغيل Windows.
</p>

<h3>
	تثبيت Node.js
</h3>

<p>
	رغم أنّنا سنحتاج إلى Node.js إلّا أنّنا لن نكتب أي شيفرة باستخدامه حاليا، إنما سنستخدم مدير الحزم <code>npm</code> وهو ضروري لتثبيت Vue CLI، بالإضافة إلى احتواءه على خادوم التطوير الذي تحدثنا عنه قبل قليل، والذي سيستضيف تطبيقاتنا أثناء تطويرها.
</p>

<p>
	في البداية يتوجب علينا زيارة <a href="https://nodejs.org/en/" rel="external nofollow">الموقع الخاص بـ Node.js</a> وتنزيل الإصدار الأخير منه.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52232" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.e343ffd0d94b196913dff9b53259bba2.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52232" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.ddb2dda6cd94e5c4249ed00db2230b65.png"></a>
</p>

<p>
	انقر على الإصدار الحالي (الزر الأخضر الأيمن). بعد تنزيل برنامج التثبيت، شغّل هذا البرنامج (ستحتاج إلى صلاحيات مدير النظام)، واتبع خطوات التثبيت مع ترك الخيارات الافتراضية كما هي. ستأخذ عملية التثبيت زمنًا قصيرًا نسبيًا. بعد الانتهاء يمكنك الانتقال إلى الخطوة التالية.
</p>

<h3>
	تثبيت Vue CLI
</h3>

<p>
	شغّل موجّه الأوامر في Windows (يمكنك ذلك من خلال ضغط مفتاح الويندوز مع المفتاح R، ثم كتابة الأمر cmd مباشرةً، ونقر زر موافق OK). بعد ذلك اكتب الأمر التالي:
</p>

<pre class="ipsCode">
npm install -g @vue/cli
</pre>

<p>
	ستبدأ عندها عملية تثبيت Vue CLI والتي ستأخذ أيضًا وقتًا قصيرًا نسبيًا. بعد الانتهاء، سيعود موجّه الأوامر إلى حالته الطبيعية.
</p>

<p>
	عند هذه النقطة أصبح Vue CLI جاهزًا للاستخدام، حيث يمكنك البدء بتنفيذ الأمر <code>vue</code> مباشرةً ضمن موجّه الأوامر لأنه أصبح متاحًا بعد تثبيته باستخدام <code>npm</code>.
</p>

<p>
	<strong>ملاحظة</strong> قد تحتاج إلى إغلاق نافذة موجه الأوامر الحالية، وفتح نافذة موجّه أوامر جديدة حتى تستطيع استخدام الأمر vue.
</p>

<h3>
	تثبيت Git
</h3>

<p>
	سنحتاج أيضًا إلى تطبيق إدارة الإصدار Git. يمكنك تحميله <a href="https://git-scm.com/downloads" rel="external nofollow">من هذا الرابط</a> مع اختيار نسخة الويندوز. بعد تنزيل الملف، نصّب التطبيق (ستحتاج إلى صلاحيات مدير النظام). اترك الخيارات الافتراضية كما هي باستثناء الشاشة التي تطلب منك فيها تحديد الطرفية الافتراضية للـ Git. اختر الخيار الثاني <code>Use Windows' default console window</code>. ثم تابع بنقر الزر <code>Next</code> حتى تصل للنهاية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52233" href="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.e260338c74843226b1757ea82aa7489e.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52233" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.e260338c74843226b1757ea82aa7489e.png"></a>
</p>

<p>
	بعد الانتهاء من تثبيت Git. افتح نافذة موجّه الأوامر (نافذة جديدة) واكتب الأمر التالي لكي نتأكّد من أنّ عملية التثبيت قد تمّت بشكل صحيح:
</p>

<pre class="ipsCode">
git --version
</pre>

<p>
	ستحصل على إصدار النسخة الحالي إذا جرت الأمور بشكل سليم.
</p>

<h2>
	إنشاء مشروع جديد باستخدام Vue CLI
</h2>

<p>
	الآن وبعد أن انتهينا من إعداد Vue CLI أصبح بإمكاننا الشروع باستخدامه. سنبدأ بإنشاء مشروع جديد. وبما أنّنا سنعمل على نقل تطبيق "مشاريب حسوب" إلى Vue CLI بعد قليل، لذلك فسنسمي المشروع الجديد الذي سنعمل على إنشائه الآن بالاسم hsoub-drinks-cli.
</p>

<p>
	لنبدأ الآن! اكتب الأمر التالي ضمن موجّه الأوامر:
</p>

<pre class="ipsCode">
vue create hsoub-drinks-cli
</pre>

<p>
	من السطر السابق: vue هو الأمر الخاص بتنفيذ Vue CLI كما أشرنا، الوسيط <code>create</code> يشير كما هو واضح إلى إنشاء مشروع جديد، أمّا <code>hsoub-drinks-cli</code> فهو اسم المشروع، عند تنفيذ الأمر السابق سيعمل Vue CLI على إنشاء المشروع ضمن مجلّد يحمل نفس اسم المشروع، وذلك في نفس الدليل الحالي الذي ننفّذ فيه الأمر السابق. اضغط المفتاح Enter لتنفيذ الأمر ، سيطلب منك Vue CLI المزيد من المعلومات قبل أن يُنشأ المشروع.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52234" href="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.22aebe477f46b86d5a979126f5ca7246.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52234" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.22aebe477f46b86d5a979126f5ca7246.png"></a>
</p>

<p>
	من الشكل السابق، يسأل Vue CLI عن نوع القالب الذي نريد استخدمه، توجد العديد من القوالب، حيث يمكنك ضغط مفتاح السهم السفلي من لوحة المفاتيح لاختيار <code>Manually select features</code> والاطلاع على القوالب الجاهزة مسبقًا. لمشروعنا البسيط، سأختار القالب الافتراضي <code>default (babel, eslint)‎</code>، أي اضغط على المفتاح Enter فحسب.
</p>

<p>
	سيستغرق ذلك بعض الوقت لكي تُحمّل الملفات المطلوبة ويُحضّر المشروع الجديد للاستخدام. لا تقلق من عدد الملفات الكبير التي ستنزّل من الانترنت (رغم أنّ المشروع بسيط).
</p>

<p>
	<strong>ملاحظة</strong> في بعض الأحيان القليلة، يمكن أن يحدث جمود في عملية إنشاء المشروع لسبب أو لآخر. إذا شعرت أنّ هذه العملية قد استغرقت وقتًا طويلًا غير منطقي، أو أنّ عملية التحميل تقف عند حزمة محدّدة ولا تنتقل إلى حزمة تالية، عندها يمكنك ضغط <code>Ctrl + C</code> لإيقاف Vue CLI، ثم أغلق نافذة موجّه الأوامر، ثم احذف المجلّد <code>hsoub-drinks-cli</code> الذي أُنشأ توًّا، وأعد تشغيل الحاسوب.وكرّر العملية من جديد.
</p>

<p>
	بعد الانتهاء من إنشاء المشروع. ادخل إلى المجلّد <code>hsoub-drinks-cli</code> باستخدام الأمر التالي:
</p>

<pre class="ipsCode">
cd hsoub-drinks-cli
</pre>

<p>
	ثم نفّذ الأمر التالي لتشغيل خادوم التطوير البسيط الذي يأتي مع <code>npm</code>:
</p>

<pre class="ipsCode">
npm run serve
</pre>

<p>
	سيؤدي ذلك إلى تشغيل هذا الخادوم على المنفذ الافتراضي 8080 ليعمل على تخديم ملفات المشروع <code>hsoub-drinks-cli</code> الذي أنشأناه توًّا. من الممكن أن تُفتَح نافذة جديدة من المتصفح الافتراضي لديك بشكل تلقائي بحيث تعرض مباشرة الصفحة الرئيسية الافتراضية. أو يمكنك أن تفعل أنت ذلك بأن تفتح نافذة (أو لسان تبويب) جديدة من المتصفح لديك وتنتقل إلى العنوان التالي: <a href="http://localhost:8080" rel="external nofollow">http://localhost:8080</a>. ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52235" href="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.50a98ed6d3fb4e12023d16988e32aace.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52235" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/4.thumb.png.4b1382f1e9836591f3b30249313d72d0.png"></a>
</p>

<p>
	<strong>ملاحظة</strong> من الممكن في بعض الأحيان أن يظهر لك تنبيه أمني من نظام التشغيل، يطلب منك السماح لخادوم التطوير بالعمل. كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52236" href="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.c588c19b1e1404614c4daddf669901d2.png" rel=""><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52236" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.c588c19b1e1404614c4daddf669901d2.png"></a>
</p>

<p>
	انقر الزر <code>Allow access</code> للسماح بذلك.
</p>

<h2>
	نظرة عامة على هيكل المشروع
</h2>

<p>
	انتقل الآن إلى Visual Studio Code ثم افتح مجلّد المشروع الذي أنشأناه توًّا. يمكنك ذلك باختيار الأمر <code>File -&gt;‏ Open Folder</code> ثم انتقل إلى المجلّد الذي أنشأت فيه المشروع. انقر نقرًا مزدوجًا على هذا المجلّد لكي تدخل ضمنه، ثم اختر <code>Select Folder</code>.
</p>

<p>
	سيظهر المشروع ضمن نافذة المستكشف في القسم الأيسر من الشاشة بشكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52237" href="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.f7131cbb132a4d9fa4f556fc3718688d.png" rel=""><img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52237" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.f7131cbb132a4d9fa4f556fc3718688d.png"></a>
</p>

<table>
<thead><tr>
<th>
				الملف أو المجلد
			</th>
			<th>
				الوصف
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				public/index.html
			</td>
			<td>
				عبارة عن ملف HTML عادي يرسله الخادوم إلى متصفح الويب عند زيارة الموقع: <a href="http://localhost:8080/" rel="external nofollow">http://localhost:8080/</a> من المتصفح.
			</td>
		</tr>
<tr>
<td>
				src
			</td>
			<td>
				يحتوي هذا المجلد على ملفات الشيفرة البرمجية، بالإضافة إلى أصول التطبيق من صور وتنسيقات وغيرها.
			</td>
		</tr>
<tr>
<td>
				src/main.js
			</td>
			<td>
				هذا ملف JavaScript وهو مسؤول عن إعدادات تطبيق Vue JS. كما يحتوي هذا الملف على أيّة حزم من طرف ثالث يمكن أن يستخدمها التطبيق
			</td>
		</tr>
<tr>
<td>
				src/App.vue
			</td>
			<td>
				الملفات ذات الامتداد <code>vue</code> عمومًا، هي الملفات التي تُوضع ضمنها المكوّنات (Components)، حيث سنطبّق مبدأ فصل المكوّنات بشكل كامل عن ملفات HTML العادية.
			</td>
		</tr>
<tr>
<td>
				src/assets
			</td>
			<td>
				يحتوي على أصول (assets) الموقع مثل الصور وشعار الموقع وملفات التنسيق وغيرها.
			</td>
		</tr>
<tr>
<td>
				components
			</td>
			<td>
				المجلّد الخاص بالمكوّنات التي سنكتبها للتطبيق.
			</td>
		</tr>
<tr>
<td>
				components/HelloWorld.vue
			</td>
			<td>
				ملف vue يحتوي على مكوّن تجريبي بسيط، لن نحتاج إلى هذا الملف بالطبع. حيث سنستبدل به المكوّنات الخاصة بتطبيق "مشاريب حسوب"
			</td>
		</tr>
</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
}

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<p>
	احذف الملف HelloWorld.vue باختياره من نافذة المستكشف ثم ضغط الزر Delete، ثم أنشئ ملفًا جديدًا ضمن المجلد Components بالنقر بزر الفأرة الأيمن ثم اختيار الأمر New File. سمّ الملف الجديد بالاسم drink.vue. سيحوي هذا الملف المكوّن الممثّل لمشروب محدّد (راجع الدرس السابق).
</p>

<p>
	انسخ الشيفرة البرمجية التالية إلى الملف drink.vue الجديد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3231_10" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"select"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"drink"</span><span class="pln"> </span><span class="atn">v-bind:class</span><span class="pun">=</span><span class="atv">"{'active-drink': is_selected}"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"description"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">{{name}}</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"drink"</span><span class="pun">,</span><span class="pln">
  props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    selectedDrink</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    is_selected</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">selectedDrink </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    select</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">"drink_selected_event"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="com">&lt;!-- Add "scoped" attribute to limit CSS to this component only --&gt;</span><span class="pln">
</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">
</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">pack</span><span class="pun">:</span><span class="pln"> justify</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">flex</span><span class="pun">-</span><span class="pln">pack</span><span class="pun">:</span><span class="pln"> justify</span><span class="pun">;</span><span class="pln">
    justify</span><span class="pun">-</span><span class="pln">content</span><span class="pun">:</span><span class="pln"> space</span><span class="pun">-</span><span class="pln">between</span><span class="pun">;</span><span class="pln">
    cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">transition</span><span class="pun">:</span><span class="pln"> all </span><span class="pun">.</span><span class="lit">3s</span><span class="pln"> ease</span><span class="pun">;</span><span class="pln">
    transition</span><span class="pun">:</span><span class="pln"> all </span><span class="pun">.</span><span class="lit">3s</span><span class="pln"> ease
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">weight </span><span class="pun">{</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">flexbox</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> flex
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">description </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">description </span><span class="pun">.</span><span class="pln">title </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3d4852;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">description </span><span class="pun">.</span><span class="pln">description </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">875rem</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#8795a1;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">price </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pun">%;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#09848d;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">flexbox</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Crimson</span><span class="pln"> </span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> serif</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">600</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">price </span><span class="pun">.</span><span class="pln">dollar</span><span class="pun">-</span><span class="pln">sign </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">24px</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">price </span><span class="pun">.</span><span class="pln">number </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">72px</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">5</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">);</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">after</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover</span><span class="pun">:</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#7dacaf;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> lightgray</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">);</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">after</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover</span><span class="pun">:</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#7dacaf;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	لاحظ معي أنّ الملف السابق يتكوّن من الأقسام الثلاثة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3231_12" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
...
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	يمكن أن يحتوي أي ملف يحمل الامتداد vue (وبالتالي أي مكوّن) على ثلاثة أقسام نُعبّر عنها بالوسوم <code>&lt;template&gt;</code> و <code>&lt;script&gt;</code> و <code>&lt;style&gt;</code>. الوسم <code>&lt;template&gt;</code> إلزامي، والوسمين الآخرين اختيارين. قد تظن أنّ الشيفرة السابقة معقدة بعض الشيء إلّا أنّها بسيطة في الواقع. الشيفرة الموجودة هنا مماثلة لتلك الموجودة في الدرس السابق إلى حدّ كبير. حيث عملت على تجميع جميع الشيفرات البرمجية أو التنسيقات الخاصة بالمكوّن <code>drink</code> ضمن الملف drink.vue. أي أننا استطعنا عزل كل ما يتعلق بالمكوّن <code>drink</code> ضمن هذا الملف. وفي ذلك فائدة كبيرة تتمثّل في فصل وتنظيم الشيفرة في أجزاء منطقية يسهل التعامل معها.
</p>

<p>
	يحتوي القسم <code>&lt;template&gt;</code> على شيفرة HTML الخاصة بقالب المكوّن. أما القسم <code>&lt;script&gt;</code> فيحتوي على شيفرة Vue.js اللازمة للمكوّن. أما القسم <code>&lt;style&gt;</code> فكما هو واضح يحتوي على التنسيق اللازم للمكوّن. يمكن في بعض الأحيان (كما في حالتنا هنا) استخدام الكلمة <code>scoped</code> مع الوسم <code>&lt;style&gt;</code> بهدف أن نجعل التنسيق خاصًا بالمكوّن الحالي.
</p>

<p>
	أريد التركيز على الشيفرة الموجودة ضمن القسم <code>&lt;script&gt;</code>. لاحظ أنّني قد استخدمت التعليمة <code>export default</code>. هذه التعليمة هي تعليمة JavaScript ووظيفتها السماح بتصدير كائن Vue.js الذي يأتي بعدها إلى خارج الوحدة البرمجية (الملف) drink.vue وبالتالي يمكن استيراده فيما بعد باستخدام التعليمة <code>import</code> كما سنرى بعد قليل. أمّا كائن Vue.js نفسه فهو مماثل لذلك الموجود في الدرس السابق.
</p>

<p>
	جاء الآن دور المكوّن <code>drinksselector</code> والذي أجريت تعديلًا طفيفًا على اسمه الذي كان في الدرس السابق وذلك لجعل الأمر أكثر سهولة في التعامل معه.
</p>

<p>
	أنشئ ملفًا جديدًا ضمن المجلد Components بالنقر بزر الفأرة الأيمن ثم اختيار الأمر New File. سمّ الملف الجديد بالاسم drinksselector.vue. سيحوي هذا الملف المكوّن الأساسي الذي ينظّم عملية اختيار المشاريب (مكوّنات <code>drink</code>) ضمنه (راجع الدرس السابق).
</p>

<p>
	انسخ الشيفرة البرمجية التالية إلى الملف drinksselector.vue الجديد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3231_14" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"drinks"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;drink</span><span class="pln">
      </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"drink in drinks"</span><span class="pln">
      </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"drink.name"</span><span class="pln">
      </span><span class="atn">v-bind:name</span><span class="pun">=</span><span class="atv">"drink"</span><span class="pln">
      </span><span class="atn">v-on:drink_selected_event</span><span class="pun">=</span><span class="atv">"drink_selected_handler"</span><span class="pln">
      </span><span class="atn">v-bind:selectedDrink</span><span class="pun">=</span><span class="atv">"current_drink"</span><span class="pln">
    </span><span class="tag">&gt;&lt;/drink&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> drink from </span><span class="str">"./drink.vue"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"drinksselector"</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    drink
  </span><span class="pun">},</span><span class="pln">
  data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">],</span><span class="pln">
      current_drink</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    drink_selected_handler</span><span class="pun">(</span><span class="pln">drink_name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">current_drink </span><span class="pun">=</span><span class="pln"> drink_name</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="com">&lt;!-- Add "scoped" attribute to limit CSS to this component only --&gt;</span><span class="pln">
</span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">scoped</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	لاحظ معي أنّ القسم <code>&lt;style&gt;</code> هنا فارغ. قد تتسائل كيف سنطبّق التنسيق الخاص بهذا المكوّن كما فعلنا في الدرس السابق. في الحقيقة سيطبّق التنسيق اللازم لهذا المكوّن من خلال المكوّن الابن <code>drink</code>. رغم أنّنا وضعنا الكلمة <code>scoped</code> ضمن القسم <code>&lt;style&gt;</code> من المكوّن <code>drink</code> كما مرّ معنا قبل قليل، إلّا أنّ التنسيقات الخاصة بالمكوّن <code>drinksselector</code> ستطبّق عليه. السبب في ذلك هو أنّ المكوّن <code>drink</code> هو مكوّن متداخل (مكوّن ابن) مع المكوّن <code>drinksselector</code> فتطبق التنسيقات على المكوّن الأعلى (الأب) في هذه الحالة بشكل تلقائي.
</p>

<p>
	لاحظ أيضًا السطر الذي يلي وسم الفتح <code>&lt;script&gt;</code>:
</p>

<pre class="ipsCode">
import drink from "./drink.vue";
</pre>

<p>
	تعمل هذه التعليمة البرمجية على استيراد كائن الكائن <code>drink</code> من الملف <code>drink.vue</code>. استطعنا استخدام التعليمة <code>import</code> هنا بسبب وجود التعليمة <code>export default</code> ضمن الملف <code>drink.vue</code> كما مرّ معنا قبل لحظات.
</p>

<p>
	جاء الآن دور ملف التطبيق الرئيسي App.vue والذي يعد بحد ذاته مكوّنًا، ولكنّه المكوّن الرئيسي في تطبيق ما. افتح هذا الملف وانسخ إليه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3231_16" style="">
<span class="tag">&lt;template&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"header"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"logo"</span><span class="tag">&gt;</span><span class="pln">مشاريب حسوب</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">المشروبات المتوفرة</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
        </span><span class="tag">&lt;drinksselector&gt;&lt;/drinksselector&gt;</span><span class="pln">
      </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/template&gt;</span><span class="pln">

</span><span class="tag">&lt;script&gt;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> drinksselector from </span><span class="str">"./components/drinksselector.vue"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"App"</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    drinksselector
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">

</span><span class="tag">&lt;style&gt;</span><span class="pln">
</span><span class="lit">@import</span><span class="pln"> </span><span class="str">"./assets/styles/app.css"</span><span class="pun">;</span><span class="pln">
</span><span class="tag">&lt;/style&gt;</span></pre>

<p>
	لاحظ كيف أدرجنا المكوّن <code>drinksselector</code> ضمن القسم <code>components</code> الموجود بدوره ضمن القسم <code>&lt;script&gt;</code>. لاحظ أيضًا كيف استخدمنا التنسيقات ضمن القسم <code>&lt;style&gt;</code>. لقد ربطنا ملف التنسيقات app.css الذي سننشئه بعد قليل بهذا المكوّن عن طريق التعليمة <code>‎ @import</code>.
</p>

<p>
	أضف الآن مجلّدًا جديدًا ضمن المجلّد src وذلك بالنقر بزر الفأرة الأيمن على المجلد src ثم اختيار الأمر <code>New Folder</code>. سمّ المجلّد الجديد بالاسم assets. ثم أنشئ مجلّد آخر ضمن المجلّد assets بنفس الأسلوب السابق وسمّه styles. أنشئ الآن ضمن المجلّد styles ملفًا اسمه app.css وانسخ إليه التنسيقات التالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3231_18" style="">
<span class="lit">@import</span><span class="pln"> url</span><span class="pun">(</span><span class="com">//fonts.googleapis.com/earlyaccess/notonaskharabic.css);</span><span class="pln">
body </span><span class="pun">{</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100vh</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Noto Naskh Arabic'</span><span class="pun">,</span><span class="pln"> serif</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ccdcdc;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">no</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

span</span><span class="com">#logo {</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#eee;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> larger</span><span class="pun">;</span><span class="pln">
    letter</span><span class="pun">-</span><span class="pln">spacing</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">05em</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">5rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">5rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">float</span><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6px</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">header </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> slategray</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">80</span><span class="pun">%;</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50px</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

h1</span><span class="pun">.</span><span class="pln">title </span><span class="pun">{</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.875rem</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#2d3336</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

h2</span><span class="pun">.</span><span class="pln">subtitle </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> x</span><span class="pun">-</span><span class="pln">large</span><span class="pun">;</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5</span><span class="pun">;</span><span class="pln">
    max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500px</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#5c6162</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">content </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">620px</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	انتقل الآن إلى الملف index.html واحرص على أن يكون محتواه مماثلًا للشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3231_20" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"en"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">"X-UA-Compatible"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"IE=edge"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"viewport"</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">"width=device-width,initial-scale=1.0"</span><span class="tag">&gt;</span><span class="pln">
    &lt;link rel="icon" href="</span><span class="pun">&lt;%=</span><span class="pln"> BASE_URL %&gt;favicon.ico"&gt;
    </span><span class="tag">&lt;title&gt;</span><span class="pun">&lt;%=</span><span class="pln"> htmlWebpackPlugin</span><span class="pun">.</span><span class="pln">options</span><span class="pun">.</span><span class="pln">title %&gt;</span><span class="tag">&lt;/title&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;noscript&gt;</span><span class="pln">
      </span><span class="tag">&lt;strong&gt;</span><span class="pln">We're sorry but </span><span class="pun">&lt;%=</span><span class="pln"> htmlWebpackPlugin</span><span class="pun">.</span><span class="pln">options</span><span class="pun">.</span><span class="pln">title %&gt; doesn't work properly without JavaScript enabled. Please enable it to continue.</span><span class="tag">&lt;/strong&gt;</span><span class="pln">
    </span><span class="tag">&lt;/noscript&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln">
    </span><span class="com">&lt;!-- built files will be auto injected --&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	لقد انتهينا الآن من جميع الملفات! اذهب إلى المتصفّح ثم انتقل إلى العنوان <a href="http://localhost:8080" rel="external nofollow">http://localhost:8080</a> لتجد تطبيق "مشاريب حسوب" وقد عمل من جديد. ولكن هذه المرة باستخدام Vue CLI
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52238" href="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.e579d3e38ffcbeac209e009316c594dc.png" rel=""><img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52238" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/7.thumb.png.d40615461d2c801e7a7b09eaf979ffb7.png"></a>
</p>

<p>
	<strong>ملاحظة</strong> بعد الانتهاء من عملية التطوير بشكل كامل، يمكن استخدام الأمر التالي لبناء التطبيق وتجهيزه ضمن بيئة الإنتاج (Production Environment) للاستخدام النهائي باستخدام الأمر:
</p>

<pre class="ipsCode">
npm run build
</pre>

<p>
	يمكنك الاطلاع على المزيد حول هذا الموضوع من خلال <a href="https://cli.vuejs.org/guide/deployment.html" rel="external nofollow">من هذا الرابط</a>.
</p>

<h2>
	ختامًا
</h2>

<p>
	تعلّمنا في هذا الدرس كيفية إنشاء تطبيق Vue.js متكامل باستخدام قالب جاهز منحنا إيّاه Vue CLI. تعلّمنا بدايةً ما هو مفهوم Vue CLI وكيفية إعداده، وكيف ننشئ مشروع جديد باستخدامه.
</p>

<p>
	كما عملنا على تحويل كامل تطبيق "مشاريب حسوب" من الأسلوب القديم والمفيد في حال كنّا نريد تجربة مزايا جديدة، إلى أسلوب Vue CLI بالكامل.
</p>

<p>
	بهذا الدرس نكون قد خطونا خطوةً مهمةً ومتقدمة في العمل مع Vue.js.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AF%D8%AE%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%B9%D9%86-%D8%B7%D8%B1%D9%8A%D9%82-%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%84%D8%A5%D8%AF%D8%AE%D8%A7%D9%84-%D9%81%D9%8A-vuejs-r1034/" rel="">التعامل مع دخل المستخدم عن طريق نماذج الإدخال في Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D8%B2%D9%8A%D8%AF-%D8%AD%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1032/" rel="">المزيد حول المكونات في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1033</guid><pubDate>Fri, 23 Oct 2020 13:03:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x632;&#x64A;&#x62F; &#x62D;&#x648;&#x644; &#x627;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D8%B2%D9%8A%D8%AF-%D8%AD%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1032/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.ee2a66144ca047c5b97134886a795c80.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		بناء تطبيق نموذجي (مشاريب حسوب).
	</li>
	<li>
		إضافة وسائل تنقيح متطوّرة لتطبيقات Vue.js.
	</li>
	<li>
		المكوّنات المتداخلة.
	</li>
	<li>
		تسجيل المكوّنات محليًّا وتسجيلها على المستوى العام.
	</li>
	<li>
		تحديد المكوّن الذي اختاره المستخدم.
	</li>
	<li>
		التخاطب بين المكوّنات باستخدام أحداث مخصّصة.
	</li>
</ul>
<p>
	سنتعلّم في هذا الدرس المزيد عن المكوّنات، حيث سنتعرّف على المزيد من المزايا المتعلّقة بها، والتي ستساعدنا على بناء مكوّنات عملية ومفيدة. سنبدأ هذا الدرس ببناء تطبيق نموذجي سيكون الهيكل الأساسي الذي سنستخدمه لتعلّم المزايا الجديدة حول المكوّنات، ثم سنتعرّف على كيفية استخدام أدوات تنقيح متطوّرة مكتوبة خصيصًا لـ Vue.js، ثم نتعرّف على المكوّنات المتداخلة وكيفية استخدامها، ثم سنتعلّم كيفية تسجيل المكوّنات محليًا وعلى المستوى العام في التطبيق، ونختم بتعلّم كيفية التخاطب بين المكوّنات المتداخلة.
</p>

<h2>
	بناء تطبيق نموذجي (مشاريب حسوب)
</h2>

<p>
	سنبني من أجل هذا الدرس تطبيق نموذجي بسيط لكي نطبق عليه الأفكار التي سنتاولها هنا. سيكون هذا التطبيق عبارة عن واجهة بسيطة لمحل افتراضي بيع مشروبات متنوعة. سيعبّر المكوّن في هذه المرة عن مشروب معيّن من قائمة المشروبات المتاحة.
</p>

<p>
	انظر إلى الشكل النهائي المقترح:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52225" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.531b25a144156778b6c2289651f714bf.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52225" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.3a48b1c380b753346123de7fd88bfeb3.png"></a>
</p>

<p>
	كما ترى فإنّني أستخدم اللغة العربية في التطبيق هذه المرّة! أنشئ مجلّدًا جديدًا سمّه hsoub-drinks سنستخدمه لوضع ملفات المشروع ضمنه.
</p>

<p>
	يحتوي هذا التطبيق على مكوّن وحيد حاليًا أسميته <code>drink</code> أي مشروب ما. لهذا المكوّن خاصيّة وحيدة اسمها <code>name</code> تعبّر عن اسم هذا المشروب. انظر إلى شيفرة Vue.js التي سأضعها ضمن الملف app.js الذي سيكون موجودًا ضمن المجلّد hsoub-drinks الذي أنشأته توًّا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_7" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'drink'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">


  </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">]</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span></pre>

<p>
	لاحظ كم هو بسيط هذا التطبيق: مكوّن عادي معرّف في الأعلى، وكائن Vue.js بسيط في الأسفل يحتوي على البيانات التي نريد عرضها على الشاشة. هذه البيانات موجودة ضمن المصفوفة <code>drinks</code> كما هو واضح.
</p>

<p>
	لننتقل الآن إلى شيفرة HTML التي سأضعها ضمن ملف سأسمّه <code>index.html</code>وسيكون موجودًا أيضًا ضمن المجلّد hsoub-drinks:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_9" style="">
<span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"header"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"logo"</span><span class="tag">&gt;</span><span class="pln">مشاريب حسوب</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">المشروبات المتوفرة</span><span class="tag">&lt;/h1&gt;</span><span class="pln">

            </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"drinks"</span><span class="tag">&gt;</span><span class="pln">
                </span><span class="tag">&lt;drink</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"drink in drinks"</span><span class="pln"> </span><span class="atn">v-bind:name</span><span class="pun">=</span><span class="atv">"drink"</span><span class="tag">&gt;&lt;/drink&gt;</span><span class="pln">
            </span><span class="tag">&lt;/div&gt;</span><span class="pln">
        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drink"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"description"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"title"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">{{</span><span class="pln">name</span><span class="pun">}}</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/vue@2.6.11/dist/vue.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"app.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"app.css"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	كما مرّ معنا فيما سبق نستخدم حلقة <code>v-for</code> في المرور على عناصر المصفوفة <code>drinks</code> وبالتالي توليد عنصر المكوّن <code>drink</code> كما هو واضح من الشيفرة السابقة. لاحظ أيضًا أنّ العناصر المولَّدة والتي تمثّل المشروبات المتوفرة ستكون موجودة ضمن عنصر <code>div</code> يحمل الصنف <code>drinks</code>. أرجو أن لا يختلط عليك الأمر بين اسم المكوّن <code>drink</code> وبين صنف التنسيق <code>drink</code> لأنّ كليهما يحملان نفس الاسم، وهذا أمر جائز تمامًا.
</p>

<p>
	بقيت أخيرًا تنسيقات CSS الذي سأضعها ضمن الملف <code>app.css</code> ضعه أيضًا ضمن المجلد hsoub-drinks:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6613_11" style="">
<span class="lit">@import</span><span class="pln"> url</span><span class="pun">(</span><span class="com">//fonts.googleapis.com/earlyaccess/notonaskharabic.css);</span><span class="pln">
body </span><span class="pun">{</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100vh</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> antialiased</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">moz</span><span class="pun">-</span><span class="pln">osx</span><span class="pun">-</span><span class="pln">font</span><span class="pun">-</span><span class="pln">smoothing</span><span class="pun">:</span><span class="pln"> grayscale</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Noto Naskh Arabic'</span><span class="pun">,</span><span class="pln"> serif</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ccdcdc;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">:</span><span class="pln"> no</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

span</span><span class="com">#logo {</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#eee;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> larger</span><span class="pun">;</span><span class="pln">
    letter</span><span class="pun">-</span><span class="pln">spacing</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">05em</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">5rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">5rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">float</span><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6px</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">header</span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln">slategray</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">80</span><span class="pun">%</span><span class="pln"> </span><span class="pun">;</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50px</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

h1</span><span class="pun">.</span><span class="pln">title </span><span class="pun">{</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.875rem</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#2d3336</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

h2</span><span class="pun">.</span><span class="pln">subtitle </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> x</span><span class="pun">-</span><span class="pln">large</span><span class="pun">;</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5</span><span class="pun">;</span><span class="pln">
    max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500px</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#5c6162</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">content </span><span class="pun">{</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">620px</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">40px</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40px</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">pack</span><span class="pun">:</span><span class="pln"> justify</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">flex</span><span class="pun">-</span><span class="pln">pack</span><span class="pun">:</span><span class="pln"> justify</span><span class="pun">;</span><span class="pln">
    justify</span><span class="pun">-</span><span class="pln">content</span><span class="pun">:</span><span class="pln"> space</span><span class="pun">-</span><span class="pln">between</span><span class="pun">;</span><span class="pln">
    cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">transition</span><span class="pun">:</span><span class="pln"> all </span><span class="pun">.</span><span class="lit">3s</span><span class="pln"> ease</span><span class="pun">;</span><span class="pln">
    transition</span><span class="pun">:</span><span class="pln"> all </span><span class="pun">.</span><span class="lit">3s</span><span class="pln"> ease
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">weight </span><span class="pun">{</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">flexbox</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> flex
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">description </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">description </span><span class="pun">.</span><span class="pln">title </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#3d4852;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">float</span><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">description </span><span class="pun">.</span><span class="pln">description </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">875rem</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">500</span><span class="pun">;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#8795a1;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">price </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pun">%;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#09848d;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">flexbox</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.5rem</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">family</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Crimson</span><span class="pln"> </span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> serif</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">600</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">price </span><span class="pun">.</span><span class="pln">dollar</span><span class="pun">-</span><span class="pln">sign </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">24px</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">700</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">&gt;.</span><span class="pln">price </span><span class="pun">.</span><span class="pln">number </span><span class="pun">{</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">72px</span><span class="pun">;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">5</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">);</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">after</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover</span><span class="pun">:</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#7dacaf;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أصبح التطبيق النموذجي جاهزًا. نستطيع الآن المتابعة مع موضوعات هذا الدرس.
</p>

<h2>
	إضافة وسائل تنقيح متطوّرة لتطبيقات Vue.js
</h2>

<p>
	يوفّر مطوروا Vue.js أدوات تنقيح متطوّره مخصصة لتطبيقات Vue.js بحيث تسهّل حياة المبرمج إلى حدّ كبير. تظهر هذه الأدوات ضمن أدوات المطوّر التي يمكن الوصول إليها بضغط المفتاح <code>F12</code>. يمكنك زيارة <a href="https://github.com/vuejs/vue-devtools" rel="external nofollow">هذه الصفحة</a> للاطلاع على كيفية تثبيت هذه الأدوات. بعد أن تثبت الأدوات السابقة، يمكنك الوصول إليها بضغط المفتاح F12 كما أشرنا، ثم تبحث عن لسان التبويب Vue.js (قد تحتاج إلى نقر زر عرض المزيد في حال لم تجد لسان التبويب هذا). انظر الشكل التالي لترى كيف تبدو.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52226" href="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.453447d0925ca22050f9b083748bf2c9.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52226" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/2.thumb.png.0616c22a3df0e9abce66feadc927d429.png"></a>
</p>

<h2>
	المكونات المتداخلة
</h2>

<p>
	نحتاج في بعض الأحيان إلى جعل المكونات متداخلة فيما بينها، كأن يكون هناك مكوّن أساسي (مكوّن أب) يستخدم مكوّنات أصغر (مكوّنات أبناء) ضمنه. سنوظف هذا المفهوم ضمن التطبيق النموذجي السابق.
</p>

<p>
	سأضيف مكوّنًا جديدًا ضمن الملف app.js وسأسمّه <code>drink-selector</code>. سيلعب هذا المكوّن دور المكوّن الأساسي الذي يحوي المكوّن <code>drink</code> الذي سيكون ضمنه بشكل متداخل. انظر إلى محتويات الملف app.js بعد إضافة المكوّن الجديد إليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_13" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'drink'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'drink-selector'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-selector-template'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ معي كيف نقلت البيانات الخاصة بالتطبيق من كائن Vue.js إلى المكوّن <code>drink-selector</code>. لهذا الأمر فائدة سنراها لاحقًا إن شاء الله.
</p>

<p>
	بالنسبة لشيفرة HTML فالأمر بسيط أيضًا. سننشئ القالب <code>drink-selector-template</code> المعبّر عن مكوّننا الجديد. وسننقل إليه الشيفرة الخاصة بتوليد قائمة المشاريب. انظر محتوى القالب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_15" style="">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-selector-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drinks"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">drink v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"drink in drinks"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">name</span><span class="pun">=</span><span class="str">"drink"</span><span class="pun">&gt;&lt;/</span><span class="pln">drink</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	بدلًا من الشيفرة التي نقلناها توًا يمكنك استخدام العنصر <code>&lt;drink-selector&gt;&lt;/drink-selector&gt;</code>. انظر كيف ستصبح الشيفرة بعد التعديل الأخيرة على الملف index.html:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_17" style="">
<span class="tag">&lt;html</span><span class="pln"> </span><span class="atn">lang</span><span class="pun">=</span><span class="atv">"ar"</span><span class="tag">&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"header"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"logo"</span><span class="tag">&gt;</span><span class="pln">مشاريب حسوب</span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"container"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"content"</span><span class="tag">&gt;</span><span class="pln">
            </span><span class="tag">&lt;h1</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"title"</span><span class="tag">&gt;</span><span class="pln">المشروبات المتوفرة</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
            </span><span class="tag">&lt;drink-selector&gt;&lt;/drink-selector&gt;</span><span class="pln">

        </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-selector-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drinks"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">drink v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"drink in drinks"</span><span class="pln"> </span><span class="pun">:</span><span class="pln">name</span><span class="pun">=</span><span class="str">"drink"</span><span class="pun">&gt;&lt;/</span><span class="pln">drink</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drink"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"description"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"title"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">{{</span><span class="pln">name</span><span class="pun">}}</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/vue@2.6.11/dist/vue.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"app.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"app.css"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	إذًا استطعنا استخدام مكوّن ضمن مكوّن آخر بشكل متداخل. يمكنك الآن أن تنشأ عناصر <code>drink-selector</code> جديدة بنسخ ولصق السطر التالي بشكل متكرر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_19" style="">
<span class="tag">&lt;drink-selector&gt;&lt;/drink-selector&gt;</span></pre>

<h2>
	تسجيل المكونات محليًّا وتسجيلها على المستوى العام
</h2>

<p>
	يمكن تسجيل المكوّنات ضمن تطبيق Vue.js بأسلوبين مختلفين. الأسلوب الأوّل هو الأسلوب العام، وهو الأسلوب الذي استخدمناه حتى هذه اللحظة باستخدام التابع <code>Vue.component</code>. والأسلوب الآخر هو الأسلوب المحلي والذي سنتعرّف عليه في هذه الفقرة.
</p>

<p>
	في الحقيقة لا يُعتبر تسجيل المكوّنات على المستوى العام أمرًا جيّدًا، لأنّه عندما ستكبر تطبيقاتك وتبدأ باستخدام أساليب متقدمة في بناء التطبيقات (كما سيمر معنا في الدروس اللاحقة)، سيتم بناء المكوّنات التي سجلتها على المستوى العام وذلك في التطبيق النهائي، حتى ولو لم تستخدمها في ذلك التطبيق. وهذا يعني زيادة في حجم شيفرة JavaScript التي على المستخدمين تحميلها من الانترنت دون فائدة. هذا فضلًا عن مشاكل من الناحية التصميمية للتطبيق. ففي تطبيقنا الأخير مثلًا، لن نستخدم المكوّن <code>drink</code> خارج المكوّن <code>drink-selector</code>، وبالتالي لا حاجة لتسجيل المكوّن <code>drink</code> على المستوى العام.
</p>

<p>
	لحل هذه المشكلة، وبالتالي تسجيل المكوّنات بشكل محلي إذا اقتضى الأمر ذلك، فيمكننا بكل بساطة تعريف المكوّن على شكل كائن JavaScript وإسناده إلى متغيّر عادي بدون استخدام التابع Vue.Component. ثم تسجيله في المكان الذي سنستخدمه فيه فقط. دعنا نطبّق هذه الطريقة على المكوّن <code>drink</code> الذي سيصبح تعريفه على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_21" style="">
<span class="pln">let drink_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بما أنّ هذا المكوّن سيُستخدم ضمن المكون <code>drink-selector</code> لذلك سننشئ قسمًا جديدًا ضمن المكون <code>drink-selector</code> اسمه <code>components</code> والذي يسمح بتسجيل أي مكوّنات داخلية سيستخدمها هذا المكون. انظر إلى تعريف المكون <code>drink-selector</code> بعد التعديل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_23" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'drink-selector'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-selector-template'</span><span class="pun">,</span><span class="pln">
    components</span><span class="pun">:{</span><span class="pln">
        drink</span><span class="pun">:</span><span class="pln"> drink_component
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وبذلك نكون قد سجّلنا المكوّن <code>drink</code> محليّا ضمن المكوّن <code>drink-selector</code> ولا يمكن بعد ذلك استخدام المكون <code>drink</code> في أي مكان آخر غير المكون <code>drink-selector</code>.
</p>

<p>
	كما يمكن بطبيعة الحال فعل الأمر ذاته مع المكوّن <code>drink-selector</code> أي تسجيله محليا بدون استخدم التابع <code>Vue.component</code> في حال أردنا استخدام هذا المكوّن فقط ضمن صفحة محدّدة ضمن تطبيق الويب. سنجر الآن تعديلًا مماثلًا على المكوّن <code>drink-selector</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_25" style="">
<span class="pln">let drink_selector_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-selector-template'</span><span class="pun">,</span><span class="pln">
    components</span><span class="pun">:{</span><span class="pln">
        drink</span><span class="pun">:</span><span class="pln"> drink_component
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الآن، أين تعتقد أنّه يجب تسجيل المكوّن <code>drink-selector</code>؟
</p>

<p>
	الجواب بكل بساطة، وبما أنّه لا يوجد مكوّن رئيسي يمكن أن يُعرَّف المكوّن <code>drink-selector</code> ضمنه، فسنسجله ضمن كائن Vue.js الخاص بالتطبيق باستخدام القسم <code>components</code> أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_27" style="">
<span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
    components</span><span class="pun">:{</span><span class="pln">
        </span><span class="str">'drink-selector'</span><span class="pun">:</span><span class="pln"> drink_selector_component
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ معي أنّني قد عرفت اسم المكوّن هذه المرة على شكل نص: <code>drink-selector</code> بشكل مختلف عن تعريف المكوّن <code>drink</code>. السبب في ذلك أنّني أرغب بالاستمرار باستخدام الرمز <code>-</code> ضمن اسم المكون <code>drink-selector</code> وهذا جائز تمامًا بالطبع. إذا أردت الاطلاع على الشكل النهائي للملف app.js بعد التعديلات الأخيرة، انظر إلى الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_29" style="">
<span class="pln">let drink_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let drink_selector_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-selector-template'</span><span class="pun">,</span><span class="pln">
    components</span><span class="pun">:{</span><span class="pln">
        drink</span><span class="pun">:</span><span class="pln"> drink_component
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
    components</span><span class="pun">:{</span><span class="pln">
        </span><span class="str">'drink-selector'</span><span class="pun">:</span><span class="pln"> drink_selector_component
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<h2>
	تحديد المكون الذي اختاره المستخدم
</h2>

<p>
	لنمضي قدمًا في تطبيق المشاريب، حيث سنعمل الآن على إضافة ميزة تحديد المشروب الذي اختاره المستخدم عن طريق النقر عليه بالفأرة. تحتاج هذه الميزة إلى بعض المتطلّبات البسيطة، حيث سنُكسِب المكوّن <code>drink</code> حقلًا جديدًا اسمه <code>is_selected</code> سيُعرّف ضمن القسم <code>data</code> كما نعلم، لتحديد فيما إذا كان المستخدم قد اختار هذا المشروب أم لا، بالإضافة إلى تزويده بتابع جديد يسمح باختيار المشروب ولنسمّه <code>select</code> والذي سيحتوي على تعليمة برمجية واحدة تجعل قيمة الحقل <code>is_selected</code> مساوية للقيمة <code>true</code>، أي تعبّر عن عملية الاختيار. انظر كيف سيبدو شكل المكون <code>drink</code> بعد إضافة التعديلين السابقين عليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_31" style="">
<span class="pln">let drink_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            is_selected</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        select</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">is_selected </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنجر الآن التعديلات اللازمة ضمن الملف index.html حيث سنضيف الموجّه <code>v-on:click</code> ضمن قالب المكوّن <code>drink</code> للاستجابة لحدث النقر. انظر التعديلات التالية على القالب <code>drink-template</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_33" style="">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">=</span><span class="str">"select"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drink"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"description"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"title"</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">{{</span><span class="pln">name</span><span class="pun">}}</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	عد إلى المتصفّح لمعاينة التغييرات (تذكّر أنّنا نستعرض الملف index.html ضمن الخادوم Live Server). جرب أن تنقر على المشروبين: "شاي" و "شاي أخضر"، ثم انتقل إلى نافذة أدوات المطوّر بضغط F12، ومن هناك انتقل إلى لسان التبويب Vue. انشر العقد في حال احتجت ذلك، ستحصل على شكل شبيه بما يلي بالنسبة للمشروب الأول "شاي":
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52227" href="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.2aa06824039256088a2f5ffb6247d6dc.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52227" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/3.thumb.png.a5b70cc72ee44d02f73fd3f2470cefe4.png"></a>
</p>

<p>
	جرب أن تعاين حالة المشروب التالي "قهوة" ستجد أن قيمة الحقل <code>is_selected</code> له تساوي <code>false</code> لأنّنا لم ننقر على القهوة. جرب الآن أن تعاين حالة المشروب التالي "شاي أخضر"، ستلاحظ أنّ قيمة <code>is_selected</code> في هذه الحالة هي <code>true</code>. أي أنّ التطبيق حاليًا يعمل كما هو متوقّع منه حتى الآن. بقي أن نضيف بعض التأثيرات البصرية البسيطة للإشارة إلى أنّ المشروب قد اختير من قبل المستخدم. سأستخدم الموجّه <code>v-bind:class</code> لإضافة تنسيق CSS وذلك ضمن القالب <code>drink-template</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_35" style="">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">=</span><span class="str">"select"</span><span class="pln"> </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drink"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="kwd">class</span><span class="pun">=</span><span class="str">"{'active-drink': is_selected}"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"description"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"title"</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">{{</span><span class="pln">name</span><span class="pun">}}</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	سيُطبّق تنسيق CSS المسمى <code>'active-drink'</code> فقط عندما تكون قيمة الحقل <code>is_selected</code> تساوي <code>true</code> أي عندما يختار المستخدم المشروب الحالي. ولاحاجة بطبيعة الحال لاستخدام علامة الاقتباس المفردة في حال لم يحتوي اسم الصنف على رمز مثل <code>-</code>. بقي أن نضيف تنسيق CSS نفسه إلى ملف التنسيقات app.css. أضف الصنفين التاليين إلى ذلك الملف:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_6613_37" style="">
<span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> lightgray</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">);</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">30px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">11</span><span class="pun">),</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> </span><span class="lit">15px</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="lit">08</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">active</span><span class="pun">-</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">after</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">drinks </span><span class="pun">.</span><span class="pln">drink</span><span class="pun">:</span><span class="pln">hover</span><span class="pun">:</span><span class="pln">after </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#7dacaf;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">25rem</span><span class="pun">;</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> block</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عد إلى المتصفح واختر المشروب الأول والثالث مرة أخرى لتحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52228" href="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.df90c72277a68d7b1633464d87b4b6d9.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52228" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.df90c72277a68d7b1633464d87b4b6d9.png"></a>
</p>

<p>
	لقد تمّت المهمة بنجاح! ولكن، ماذا لو أردنا اختيار مشروب واحد فقط من القائمة؟ سنحل هذه المشكلة في الفقرة التالية حيث سنتعلّم كيفية التخاطب بين المكوّنات المختلفة باستخدام أحداث مخصّصة.
</p>

<h2>
	التخاطب بين المكونات باستخدام أحداث مخصصة
</h2>

<p>
	برزت الحاجة في الفقرة السابقة إلى اختيار مشروب واحد فقط من قائمة المشروبات المتاحة. أي أنّنا بحاجة إلى آلية معيّنة تسمح باختيار مشروب واحد فقط، بحيث تعمل هذه الآلية على إلغاء أي اختيار سابق لمشروب ما (في حال وجوده) ضمن القائمة، والإبقاء على المشروب الذي اختاره المستخدم أخيرًا.
</p>

<p>
	يمكن تحقيق هذا الأمر بالتخاطب بين المكوّن الابن <code>drink</code> والمكوّن الأب <code>drink-selector</code> حيث سنستخدم المكوّن الأب للمساعدة في هذا الأمر.
</p>

<p>
	يمكن التخاطب بين المكونات باستخدام الأحداث المخصّصة التي سنتحدث عنها بعد قليل، حيث سنبلغ المكوّن الأب <code>drink-selector</code> بأن مشروبًا ما قد اختاره المستخدم، فيعمل عندئذ المكون الأب على إلغاء اختيار أي مشروب سابق يمكن أن يكون قد اختير من قبل، باستثناء المشروب الحالي.
</p>

<p>
	قبل المتابعة، توقف عن القراءة قليلًا، حضر كوبًا من الشاي (أو القهوة)، ثم عد إلى هنا من جديد، لأنّ الشرح التالي يحتاج إلى المزيد من التركيز.
</p>

<p>
	سنبدأ من الملف app.js حيث سنجري بعض التعديلات على المكونين <code>drink</code> و <code>drink-selector</code>. بالنسبة للمكون <code>drink</code> سأجري التعديلات التالية:
</p>

<p>
	استخدمنا في المثال في الفقرة السابقة الحقل <code>is_selected</code> للإشارة إلى كون المشروب الحالي قد اختير أم لا. سأحول هذا الحقل إلى خاصية محسوبة (Computed Property) بالإضافة إلى أنّني سأحذف قسم <code>data</code> بشكل كامل، وسنرى سبب ذلك بالإضافة بعد قليل. كما سأستخدم لأوّل مرة التابع المضمّن <code>‎ $emit</code> ضمن التابع <code>select</code> (بدلًا من التعليمة <code>this.is_selected = true</code>) لكي نُصدر الحدث <code>drink_selected_event</code> وذلك لكي نبلّغ المكون الأب بأن المشروب الحالي قد اختير، وذلك بأن أمرّر اسم هذا المشروب كوسيط ثانٍ للتابع <code>$emit</code>. سأضيف أيضًا خاصية جديدة اسمها <code>selectedDrink</code> إلى المكون <code>drink</code> ضمن القسم <code>props</code> وذلك لكي أسمح للمكون الأب فيما بعد، بتمرير اسم المشروب (مكون <code>drink</code>) الذي اختاره المستخدم حاليًا إلى هذا المكون.
</p>

<p>
	تأمّل الشيفرة البرمجية الجديدة الخاصة بالمكون <code>drink</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_39" style="">
<span class="pln">let drink_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        selectedDrink</span><span class="pun">:{</span><span class="pln">
            type</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    computed</span><span class="pun">:{</span><span class="pln">
        is_selected</span><span class="pun">(){</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">selectedDrink </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        select</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'drink_selected_event'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أمّا بالنسبة للمكوّن <code>drink-selector</code> فسأجري عليه أيضًا التعديلات التالية:
</p>

<ul>
<li>
		وضعت ضمنه القسم <code>methods</code> لكي أستطيع وضع التابع <code>drink_selected_handler</code> والذي سيكون معالجًا للحدث <code>drink_selected_event</code> الذي سأصدره (باستخدام التابع المضمّن <code>‎ $emit</code>) ضمن التابع <code>select</code> في المكوّن <code>drink</code> كما رأينا قبل قليل.
	</li>
	<li>
		أضفت حقلًا جديدًا أسميته <code>current_drink</code> ضمن القسم <code>data</code> وهو الذي سيحتفظ باسم المكوّن (المشروب) الذي اختاره المستخدم توًّا.
	</li>
</ul>
<p>
	إليك الشيفرة البرمجية الجديدة الخاصة بالمكون <code>drink-selector</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_41" style="">
<span class="pln">let drink_selector_component </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#drink-selector-template'</span><span class="pun">,</span><span class="pln">
    components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        drink</span><span class="pun">:</span><span class="pln"> drink_component
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            drinks</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"شاي"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"قهوة"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"شاي أخضر"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"زهورات"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"بابونج"</span><span class="pun">],</span><span class="pln">
            current_drink</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    methods</span><span class="pun">:{</span><span class="pln">
        drink_selected_handler</span><span class="pun">(</span><span class="pln">drink_name</span><span class="pun">){</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">current_drink </span><span class="pun">=</span><span class="pln"> drink_name</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إليك الآن التعديلات التي حدثت ضمن قالب المكوّن <code>drink-selector</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6613_43" style="">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/x-template"</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"drink-selector-template"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"drinks"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">drink v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"drink in drinks"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">name</span><span class="pun">=</span><span class="str">"drink"</span><span class="pln"> 
                v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">drink_selected_event</span><span class="pun">=</span><span class="str">"drink_selected_handler"</span><span class="pln"> 
                v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">selectedDrink</span><span class="pun">=</span><span class="str">"current_drink"</span><span class="pun">&gt;&lt;/</span><span class="pln">drink</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	أريد هنا التركيز على أمرين هما في صلب الموضوع:
</p>

<ul>
<li>
		الأمر الأوّل هو استخدامي للموجّه <code>v-on:drink_selected_event</code>. هذا الموجّه ليس مبيّتًا بالأصل. إنّما هو موجّه جديد مُحدَث بسبب استخدامي للتابع <code>‎$emit</code> وتمريري للقيمة 'drink_selected_event' له. إذًا يمكن إنشاء موجّهات مخصّصة باستخدام التابع المبيّت <code>‎ $emit</code>.
	</li>
	<li>
		الأمر الثاني الذي أريد التركيز عليه هو الموجّه <code>v-bind:selectedDrink="current_drink"‎</code> الذي يربط قيمة الحقل <code>current_drink</code> من الموجّه الأب، مع الخاصية <code>selectedDrink</code> من الموجّه الابن.
	</li>
</ul>
<p>
	فالذي يحدث بكل بساطة، هو أنّه عندما يختار المستخدم مشروبًا ما من القائمة، فسيُستدعى في البداية التابع <code>select</code> من المكون الابن. ضمن هذا التابع لتنفّذ التعليمة البرمجية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_45" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$emit</span><span class="pun">(</span><span class="str">'drink_selected_event'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span></pre>

<p>
	التي تعمل على استدعاء حدث مخصص للتخاطب مع المكوّن الأب، حيث يقول المكوّن الابن للمكوّن الأب: "انظر لقد تمّ اختياري!"، علمًا أنّ اسم المكوّن الابن (اسم المشروب) سيمرّّر ضمن الوسيط الثاني من التابع <code>‎ $emit</code>كما أوضحنا قبل قليل.
</p>

<p>
	بسبب وجود الموجّه <code>v-on:drink_selected_event="drink_selected_handler"</code> ضمن قالب المكوّن الأب، سيُلتَقط هذا الحدث، وسيُستدعى التابع <code>drink_selected_handler</code> من المكوّن الأب، حيث تعمل تعليمة بسيطة ضمنه على إسناد اسم المشروب (المكون الابن) الذي اختاره المستخدم ضمن الحقل <code>current_drink</code> وبهذه الطريقة يعرف المكوّن الأب من هو المشروب الحالي الذي اختاره المستخدم.
</p>

<p>
	ستؤدي هذه المعرفة، وبسبب طبيعة Vue.js إلى تحديث قالب المكوّن بكامله، وبالتالي ستنفّذ حلقة <code>v-for</code> مرة أخرى، ولكن في هذه الحالة سيمرّر اسم المكوّن (المشروب) الذي اختاره المستخدم إلى جميع المشروبات الموجودة ضمن المكوّن الأب عن طريق الخاصية <code>selectedDrink</code> وبالتالي سيعرف كل مكوّن ابن من المكوّن الابن "المحظوظ" الذي اختاره المستخدم حاليًا. وبسبب وجود الخاصية المحسوبة <code>is_selected</code> في المكون الابن، ستنفّذ التعليمة البرمجية الموجودة ضمنها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_47" style="">
<span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">selectedDrink </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span></pre>

<p>
	هذه التعليمة بسيطة للغاية، وهي تُرجع قيمة من النوع المنطقي <code>ture</code> إذا كان اسم المكوّن الحالي يطابق اسم المكوّن "المحظوظ" الذي اختاره المستخدم. أو تُرجع القيمة <code>false</code> إذا لم تتحقق هذه المطابقة.
</p>

<p>
	زبدة القول، فإنّ القيمة التي سترجعها الخاصية المحسوبة <code>is_selected</code> هي التي ستُسند إلى الموجّه <code>v-bind:class="{'active-drink': is_selected}‎"</code>‎ وبالتالي يظهر هذا المشروب كما لو أنّه تم اختياره بتطبيق تنسيق CSS المناسب أو يظهر بشكل عادي.
</p>

<p>
	<strong>ملاحظة</strong> نستنتج مما سبق، أنّه يمكن للمكوّن الأب أن يرسل رسائل إلى المكوّن الابن الموجود ضمنه، عن طريق الخصائص التي نعرفها ضمن القسم <code>props</code> في المكون الابن، التي تُعتبر مستقبلات للمكون الابن تسمح له بالتقاط الرسائل من خارجه بشكل عام. أمّا عندما يريد المكون الابن مخاطبة المكون الأب، فيمكن ذلك عن طريق أحداث مخصّصة باستخدام التابع <code>‎ $emit</code> كما أوضحنا في المثال الأخير.
</p>

<p>
	جرب التطبيق بعد التعديلات الأخيرة. لاحظ كيف أصبح يسمح باختيار مشروب واحد فقط.
</p>

<h2>
	ختامًا
</h2>

<p>
	لقد تناولنا في هذا الدرس الكثير من الموضوعات المهمة حول المكوّنات، وأعتقد أنّه أصبح من الضروري الانتقال إلى مستوى أعلى، عن طريق بناء تطبيقات بأساليب احترافية توفرها Vue.js لنا. سنعمل في الدرس القادم إن شاء الله على الاطلاع على كيفية فصل المكوّنات ضمن ملفات مستقلة تحتوي الواحدة منها على جميع التفاصيل المتعلّقة بالمكوّن مما يساهم بتنظيم الشيفرة البرمجية إلى حدّ كبير. بالإضافة إلى الاطلاع على تقنية بناء تطبيقات Vue.js بشكل مختلف عن طريق Vue.js CLI. حتى الدرس القادم أرجو أن تكونوا بأفضل حال!
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D9%85%D8%B4%D8%A7%D8%B1%D9%8A%D8%B9-vuejs-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vue-cli-r1033/" rel="">إنشاء مشاريع Vue.js باستخدام Vue CLI</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/" rel="">مدخل إلى التعامل مع المكونات في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1032</guid><pubDate>Mon, 19 Oct 2020 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.45d9c0cbc8a65d9a913fdbc783318fab.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		تجهيز هيكل التطبيق على حاسوب محلّي.
	</li>
	<li>
		بناء مكوّن جديد: مكوّن المهام.
	</li>
	<li>
		تحسين تجربة الاستخدام للمكوّن.
	</li>
	<li>
		تمرير وسائط إلى المكوّنات.
	</li>
	<li>
		إنشاء أكثر من نسخة من المكون ضمن نفس الصفحة.
	</li>
	<li>
		إضافة ميزة التصفية لمكوّن المهام.
	</li>
	<li>
		إضافة ميزة مهمة جديدة لمكوّن المهام.
	</li>
</ul>
<p>
	سنتابع في هذا الدرس التعامل مع المكوّنات، حيث سنتعلّم كيف نبني المكوّنات بصورة عمليّة. سنبني في هذا الدرس مكوّنًا بسيطًا لكنّه عملي، وهو مكوّن إدارة مهام مبسّط. الهدف من هذا التطبيق هو التعرّف على أسس بناء المكوّنات بشكل جيّد. سيعمل هذا التطبيق البسيط على السماح للمستخدم بعرض بعض المهام التي ينوي تنفيذها فيما بعد، مع إمكانية تحديد فيما إذا كان قد أنجز المهام أم لا باستخدام زر اختيار بسيط. بالإضافة إلى امتلاكه ميزة تصفية بسيطة لإخفاء أو إظهار المهام المنجزة، بالإضافة إلى إمكانية إضافة مهام جديدة.
</p>

<h2>
	تجهيز هيكل التطبيق على حاسوب محلّي
</h2>

<p>
	سنسلك هذه المرّة منحًى مغايرًا عمّا اعتدناه في الدروس السابقة. كان تركيزنا في الدروس السابقة منصبًّا على كتابة تطبيقات vue.js ضمن <a href="https://jsfiddle.net/" rel="external nofollow">موقع JSFiddle</a>، وهذا الأمر جيّد في الواقع عندما نريد التعلّم أو تجريب بعض المزايا الخفيفة. ولكن عند الانتقال إلى مستوى أعلى ببناء تطبيقات عملية وواقعية، ينبغي علينا بالتأكيد الانتقال إلى أدوات تطوير فعًالة ومناسبة.
</p>

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

<p>
	سنستخدم في هذا الدرس وغيره من الدروس اللاحقة، محرّر الشيفرة البرمجيّة Visual Studio Code من Microsoft. يمكنك في الواقع اختيار المحرّر الذي ترغب به، أو حتى يمكنك استخدام بيئة تطوير متكاملة إن أحببت. يوجد العديد من محرّرات النصوص البرمجية الأخرى مثل Atom و Sublime Text و Brackets.
</p>

<p>
	لتنصيب Visual Studio Code يمكنك زيارة الصفحة التالية code.visualstudio.com/download. يمكنك اختيار نظام التشغيل المناسب لك من الأسفل. بالنسبة لنا سنختار النسخة الخاصة بويندوز. بعد التنزيل، نصّب التطبيق مع ترك الخيارات الافتراضية كما هي (قد تحتاج إلى صلاحيات مدير النظام).
</p>

<p>
	بعد تثبيت Visual Studio Code انتقل إلى الإضافات Extensions الخاصّة به، واعمل على تثبيت الإضافة Live Server التي سنستخدمها كخادوم بسيط. انظر الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52215" href="https://academy.hsoub.com/uploads/monthly_2020_10/1.png.e9df78d7838f0dfeda09e307bafa4e51.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52215" data-unique="k85gnim9k" src="https://academy.hsoub.com/uploads/monthly_2020_10/1.thumb.png.2fde874e66d613124ce71f6f3bfa6f0f.png"></a>
</p>

<p>
	يمكنك الوصول مباشرةً إلى مدير الإضافات من الناحية اليسرى من الشاشة، كما هو ظاهر من الشكل السابق. بعد ذلك أدخل اسم الإضافة: Live Server في خانة البحث. بعد أن يجده، اختره، لتظهر النافذة الخاصة به كما في الشكل السابق، ثم انقر الزر الأخضر Install لتثبيته.
</p>

<p>
	من المفيد أيضًا تثبيت الإضافتين التاليتين:
</p>

<ul>
<li>
		الإضافة Vetur لتنسيق الشيفرة الخاصة بـ vue.js.
	</li>
	<li>
		الإضافة HTML5 Boilerplate لتنسيق شيفرة HTML.
	</li>
</ul>
<p>
	اكتب اسم كل من هاتين الإضافتين في خانة البحث، واعمل على تثبيتهما كما فعلنا قبل قليل مع الإضافة Live Server.
</p>

<p>
	<strong>ملاحظة</strong>: أنصح بإعادة تشغيل Visual Studio Code عند هذه المرحلة حتى ولو لم يطلب منك ذلك.
</p>

<p>
	لنبدأ ببناء مشروعنا! انتقل إلى المكان الذي ترغب فيه بإنشاء المشروع على القرص الصلب، وأنشئ مجلّدًا سمّه veujs-mytasks. انتقل مرّة أخرة إلى Visual Studio Code ثم اختر الأمر File -&gt; ‏Open Folder واختر المجلّد الذي أنشأته توًّا.
</p>

<p>
	من نافذة المستكشف Explorer الموجودة في الطرف الأيسر، لاحظ الأيقونتين الصغيرتين، ضع مؤشّر الفأرة للحظات فوق كل منهما لتكتشف وظيفة كل منهما. الأيقونة الأولى من اليسار وظيفتها إنشاء ملف جديد ضمن المجلّد الحالي، والأيقونة الأخرى وظيفتها إنشاء مجلّد جديد ضمن المجلّد الحالي.
</p>

<p style="text-align: center;">
	<img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52217" data-unique="w42p9aadc" src="https://academy.hsoub.com/uploads/monthly_2020_10/2.png.ec3337e6857e6740a4999bb05ffcf5e6.png"></p>

<p>
	استخدم زر ملف جديد لتُنشئ ملفين، واختر الاسمين index.html و app.js لهما على الترتيب. ستحصل في النهاية على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52218" data-unique="pbntuc5oo" src="https://academy.hsoub.com/uploads/monthly_2020_10/3.png.870819c5728706e5eebccbdc0d6ac691.png"></p>

<p>
	اختر الملف index.html لكي تفتحه، ثم انسخ شيفرة HTML التالية إليه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_8" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">'utf-8'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">'X-UA-Compatible'</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">'IE=edge'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">My Tasks</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'viewport'</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">'width=device-width, initial-scale=1'</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Welcome to MyTasks Application</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">This application is built to explain how to deal with components</span><span class="tag">&lt;/p&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'app'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;tasks&gt;&lt;/tasks&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">




    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/vue@2.6.11/dist/vue.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"app.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	شيفرة HTML السابقة عبارة عن شيفرة بسيطة، الأمر الجديد الوحيد فيها هو إضافة العنصر <code>tasks</code> وهو المكوّن الذي سنبنيه بعد قليل وسيمثّل قائمة المهام التي نرغب ببنائها. لاحظ أيضًا أنّنا وضعنا هذا العنصر الجديد ضمن عنصر <code>div</code> له الوسم <code>id = 'app'‎</code> وهو العنصر المستهدَف في كائن vue.js كما اعتدنا سابقًا. وأخيرًا، لاحظ كيف أضفت مرجعين لملف إطار العمل vue.js بالإضافة إلى مرجع للملف app.js الذي سيحتوي على الشيفرة البرمجية لكل من المكوّن والتطبيق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_10" style="">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/vue@2.6.11/dist/vue.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"app.js"</span><span class="tag">&gt;&lt;/script&gt;</span></pre>

<p>
	لننتقل الآن إلى الملف app.js، انسخ الشيفرة البرمجية التالية إليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_12" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'tasks'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'&lt;strong&gt;&lt;p&gt;{{name}} - Tasks&lt;/p&gt;&lt;/strong&gt;'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Husam'</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	الشيفرة البرمجيّة هنا مماثلة لتلك التي تعاملها معها في الدرس السابق، حيث نسجّل مكوّن جديد باسم <code>tasks</code> بحيث نُسند له قالب بسيط، يعرض اسم الشخص الذي سنُسند إليه هذه المهام عن طريق الخاصية <code>{{name}}</code> كما هو واضح. ثم ننشئ كائن vue.js بسيط ونعيّن العنصر المستهدف.
</p>

<p>
	انتقل الآن إلى نافذة المستكشف Explorer، وانقر بزر الفأرة الأيمن على الملف index.html ثم اختر الأمر Open with Live Server (تذكّر أننا ثبتنا الإضافة Live Server قبل قليل)، سيؤدي ذلك إلى فتح نافذة أو تبويب جديد ضمن متصفّح الانترنت الافتراضي لديك بحيث يتجه إلى العنوان <a href="http://127.0.0.1:5500/index.html" rel="external nofollow">http://127.0.0.1:5500/index.html</a> وهو العنوان مع المنفذ الافتراضي الذي ينصت عنده الخادوم Live Server. ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52219" data-unique="84g1o974b" src="https://academy.hsoub.com/uploads/monthly_2020_10/4.png.5d2fcfddc11d5a87ef8b97071c1a2840.png"></p>

<p>
	هذا دليل على أنّ الأمور تسير على ما يرام. وأنّ نجحنا ببناء الهيكل العام للتطبيق. لننتقل الآن للمرحلة التالية.
</p>

<h2>
	بناء مكوّن جديد: مكوّن المهام
</h2>

<p>
	لنبدأ الآن بالعمل الفعلي في بناء المكوّن الخاص بالمهام، والذي أسميناه <code>tasks</code>. سأنقل أولًا شيفرة HTML المسندة للحقل <code>template</code> ضمن المكوّن، وأضعها ضمن مكان منفصل لأنّها ستصبح بعد قليل كبيرة ومعقدة بعض الشيء لتُوضع في مكان كهذا. أجرِ التعديل التالي في الملف app.js ضمن الحقل <code>template</code> للمكوّن ليصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_15" style="">
<span class="pln">template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#tasks-template'</span></pre>

<p>
	لاحظ أنني قد عرضت مكان التعديل فقط طلبًا للاختصار. الجديد هنا أنّني وضعت معرّف القالب الجديد الذي سيحتوي على الشيفرة. انتقل الآن إلى الملف index.html وأضف الشيفرة التالية مباشرةً بعد عنصر <code>div</code> المُستهدَف الخاص بتطبيق vue.js:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_17" style="">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text/x-template'</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'tasks-template'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">h3</span><span class="pun">&gt;{{</span><span class="pln"> name </span><span class="pun">}}</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Tasks</span><span class="pun">&lt;/</span><span class="pln">h3</span><span class="pun">&gt;</span><span class="pln">       
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
 </span><span class="tag">&lt;/script&gt;</span></pre>

<p>
	كما ترى أجريت بعض التعديل على شيفرة HTML التي كانت موجودة سابقًا. انتقل الآن إلى الصفحة index.html في المتصّح ثم حدثها (إن لم تُحدّث بشكل تلقائي)، يجب أن تحصل على شكل قريب من الشكل الذي حصلنا عليه في الفقرة السابقة.
</p>

<p>
	الجديد هنا هو فصل القالب ووضعه ضمن مكان مخصّص له. في هذه الحالة سيكون ضمن العنصر <code>script</code> والذي تحمل السمة <code>type</code> له القيمة <code>text/x-template</code> كما هو واضح. بالإضافة لذلك لاحظ كيف جعلت قيمة المعرف <code>id</code> له نفس القيمة التي أسندتها للحقل <code>template</code> ضمن المكوّن قبل قليل.
</p>

<p>
	من المهم جدًّا تحقيق مبدأ الفصل في بناء المكوّنات. لأنّه كلما أصبح المكوّن أكثر تعقيدًا كما سترى بعد قليل، كلما برزت الحاجة إلى تحقيق مبدأ الفصل بشكل أفضل.
</p>

<p>
	لنُكسِب الآن مكوّننا الوليد بعض المزايا الإضافية لكي يصبح قادرًا على عرض بعض المهام للمستخدم. أجر التعديلات التالية ضمن الملف <code>app.js</code> ليصبح مشابهًا لما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_19" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'tasks'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#tasks-template'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Husam'</span><span class="pun">,</span><span class="pln">
            tasks_list</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Write an introduction about vue.js components."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Drink a cup of team."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Call Jamil."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Buy new book."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	في الواقع، لقد أضفت حقلًا جديدًا أسميته <code>tasks_list</code> يحتوي على بيانات المهام التي أرغب بعرضها. لاحظ كيف أنّ كل مهمّة ضمن القائمة عبارة عن كائن بسيط، يحتوي على خاصيتين: تضم الأولى النص الخاص بالمهمة، أمّا الثانية فتضم قيمة منطقية تشير إلى أنّ المهمة قد نُفّذت <code>true</code> أم ليس بعد <code>false</code>.
</p>

<p>
	انتقل الآن إلى الملف index.html وأجر بعض التعديلات التي ستكون أكبر هذه المرة، ليصبح مماثلًا لما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_21" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">'utf-8'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">'X-UA-Compatible'</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">'IE=edge'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">My Tasks</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'viewport'</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">'width=device-width, initial-scale=1'</span><span class="tag">&gt;</span><span class="pln">

    </span><span class="tag">&lt;style&gt;</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">tasks</span><span class="pun">-</span><span class="pln">container </span><span class="pun">{</span><span class="pln">
            border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
            border</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> solid</span><span class="pun">;</span><span class="pln">
            display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
            padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all </span><span class="pun">{</span><span class="pln">
            border</span><span class="pun">-</span><span class="pln">collapse</span><span class="pun">:</span><span class="pln"> collapse</span><span class="pun">;</span><span class="pln">
            border</span><span class="pun">-</span><span class="pln">spacing</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
            width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
            display</span><span class="pun">:</span><span class="pln"> table</span><span class="pun">;</span><span class="pln">
            border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#ccc</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all tr </span><span class="pun">{</span><span class="pln">
            border</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#ddd</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all tr</span><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">child</span><span class="pun">(</span><span class="pln">odd</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all tr</span><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">child</span><span class="pun">(</span><span class="pln">even</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#f1f1f1</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all td</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all th </span><span class="pun">{</span><span class="pln">
            padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
            display</span><span class="pun">:</span><span class="pln"> table</span><span class="pun">-</span><span class="pln">cell</span><span class="pun">;</span><span class="pln">
            text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;</span><span class="pln">
            vertical</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> top
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all th</span><span class="pun">:</span><span class="pln">first</span><span class="pun">-</span><span class="pln">child</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all td</span><span class="pun">:</span><span class="pln">first</span><span class="pun">-</span><span class="pln">child </span><span class="pun">{</span><span class="pln">
            padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16px</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all th</span><span class="pun">{</span><span class="pln">
            background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#d0d0d0;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="tag">&lt;/style&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Welcome to MyTasks Application</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">This application is built to explain how to deal with components</span><span class="tag">&lt;/p&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'app'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;tasks&gt;&lt;/tasks&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">



    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text/x-template'</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'tasks-template'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">'tasks-container'</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">table </span><span class="kwd">class</span><span class="pun">=</span><span class="str">'w3-table-all'</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">colgroup</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">col style</span><span class="pun">=</span><span class="str">"width:15%"</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">col style</span><span class="pun">=</span><span class="str">"width:85%"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">colgroup</span><span class="pun">&gt;</span><span class="pln">  
                </span><span class="pun">&lt;</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">th colspan</span><span class="pun">=</span><span class="str">"2"</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">center</span><span class="pun">&gt;{{</span><span class="pln"> name </span><span class="pun">}}</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Tasks</span><span class="pun">&lt;/</span><span class="pln">center</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Done</span><span class="pun">&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Title</span><span class="pun">&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">

                    </span><span class="pun">&lt;</span><span class="pln">tr v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"task in tasks_list"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">key</span><span class="pun">=</span><span class="str">"task.title"</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">{{</span><span class="pln"> task</span><span class="pun">.</span><span class="pln">done </span><span class="pun">}}</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">{{</span><span class="pln"> task</span><span class="pun">.</span><span class="pln">title </span><span class="pun">}}</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">table</span><span class="pun">&gt;</span><span class="pln">      
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/vue@2.6.11/dist/vue.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"app.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	حدّث الصفحة index.html ضمن متصفّح الانترنت لديك لتحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52220" data-unique="uw2wo5byw" src="https://academy.hsoub.com/uploads/monthly_2020_10/5.png.4a193d168330c36f781b3f96761ade6f.png"></p>

<p>
	ربما تشعر أنّ الشيفرة قد أصبحت كبيرة ومعقّدة نسبيًا، إلّا أنّ الأمر في الحقيقة ليس كذلك. حدثت نسبة كبيرة من التعديلات عندما أضفت عنصر التنسيق <code>style</code> مع تنسيقاته إلى الملف index.html. كان من الأفضل وضع تنسيقات CSS ضمن ملف مستقل، وهذا ما سأعمل عليه بعد قليل. التنسيقات المستخدمة هنا استعرتها من موقع <a href="http://w3schools.com" rel="external nofollow">W3Schools</a> الشهير. بالإضافة إلى ذلك، لاحظ أنّني قد استخدمت عنصر الجدول <code>table</code> لعرض قائمة المهام. عدا عن ذلك، أعتقد أنّ معظم الشيفرة البرمجيّة واضحة، باستثناء الموجّه الجديد: <code>v-bind:key</code>:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1624_23" style="">
<span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">"task in tasks_list"</span><span class="pln"> </span><span class="atn">v-bind:key</span><span class="pun">=</span><span class="atv">"task.title"</span><span class="tag">&gt;</span></pre>

<p>
	في الواقع لقد استخدمنا موجّه آخر مسبقًا، وهو <code>v-bind:href</code> وذلك في الدرس الثاني (استخدام vue.js للتعامل مع DOM). لكننا سنستخدم اليوم الكلمة <code>key</code> بدلًا من <code>href</code>. لاستخدام <code>v-bind:key</code> مزيّة مهمّة تتمثّل في الأداء (Performance)، وخصوصًا عندما يكون حجم البيانات كبيرًا. نستخدم هذا الموجّه لتعيين مفتاح ربط <code>key</code> للموجّه التكراري <code>for</code>.
</p>

<p>
	من الواضح أنّه في الوضع الحالي، من غير الممكن لنا أن نعدّل على أي مهمة بحيث تصبح منفّذة أو غير منفّذة. سنعمل في الفقرة التالية على تحسين تجربة الاستخدام، من خلال توفير إمكانية إجراء هذه التعديلات.
</p>

<h2>
	تحسين تجربة الاستخدام للمكوّن
</h2>

<p>
	سنعمل الآن على السماح للمستخدم بتعديل حالة المهمة وذلك بإضافة <a href="https://wiki.hsoub.com/HTML/input/checkbox" rel="external">عنصر اختيار Checkbox</a>. قبل ذلك دعنا ننقل تنسيقات CSS إلى ملف منفصل. أنشئ ملف جديد ضمن نافذة المستكشف في Visual Studio Code لهذا الغرض ولنسمه tasks.css.
</p>

<p>
	انقل محتويات العنصر <code>style</code> في الملف index.html إلى ملفنا الجديد، ثم احذف العنصر <code>style</code>. لاستخدام التنسيقات ضمن الملف الجديد، أضف مرجعًا إليه في الملف index.html ضمن القسم <code>head</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_25" style="">
<span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"tasks.css"</span><span class="tag">&gt;</span></pre>

<p>
	سنجري الآن تغييرًا ضمن الشيفرة البرمجية للقالب فقط، وتحديدًا بالقسم الخاص بإنهاء أو عدم إنهاء المهمة أي في القسم <code>Done</code> فقط. استبدل بالشيفرة التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_27" style="">
<span class="pln">...
</span><span class="tag">&lt;td&gt;</span><span class="pln">
       {{ task.done }}
</span><span class="tag">&lt;/td&gt;</span><span class="pln">
...</span></pre>

<p>
	الشيفرة الجديدة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_29" style="">
<span class="pln">...
</span><span class="tag">&lt;td&gt;</span><span class="pln">
       </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"task.done"</span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;/td&gt;</span><span class="pln">
...</span></pre>

<p>
	أعد تحديث الصفحة لتحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52221" data-unique="so4h3lixo" src="https://academy.hsoub.com/uploads/monthly_2020_10/6.png.4fbff329d26aa79cbae8f519a3a9d661.png"></p>

<p>
	لاحظ أنّني قد استخدمت الربط ثنائي الاتجاه <code>v-model="task.done"‎</code> للربط الثنائي للبيانات.
</p>

<p>
	<strong>ملاحظة</strong>: الاختصارات في vue.js يمكن دومًا استبدال الرمز <code>@</code> بالموجّه <code>v-on</code>. أي أنّ <code>v-on:click</code> مثلًا سيصبح: <code>‎@:click</code>. وبنفس الأسلوب، يمكننا حذف الموجّه <code>v-bind</code> بالكامل، وسيفهم vue.js أنّ هذا الموجّه موجود. فمثلًا يمكن كتابة <code>‎:href</code> فقط بدلًا من <code>v-bind:href</code>، وكتابة <code>‎:key</code> بدلًا من <code>v-bind:key</code>.
</p>

<h2>
	تمرير وسائط إلى المكوّنات
</h2>

<p>
	لعلك قد لاحظت أنّنا استخدمنا بيانات ثابتة في التعامل مع مكوّن المهام. ولكن في الواقع العملي سنحتاج إلى أن تكون هذه البيانات قابلة للتغيير كما هو واضح, لهذا الهدف توفّر المكوّنات في vue.js ميزة الخصائص <code>props</code>، حيث يمكن وضع قسم جديد اسمه <code>props</code> ضمن الوسيط الممرّر إلى المكوّن عند إنشاءه لهذه الغاية. في الحقيقة للخصائص الموجودة ضمن القسم <code>props</code> فوائد مهمة عندما سنتحدث عن المكونات المتداخلة لاحقًا في الدرس التالي، حيث سنستخدمها لتمرير البيانات من المكون الأساسي إلى المكون الفرعي.
</p>

<p>
	لنبدأ بإجراء التعديلات اللازمة. أجر التعديلات التالية في الملف app.js ليصبح على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_31" style="">
<span class="pln"> </span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'tasks'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#tasks-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
        tasks_list</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لقد أزلت قسم <code>data</code> وأضفت بدلًا منه القسم <code>props</code> (يمكن بالطبع أن يكونا معًا بنفس الوقت). عرفت الوسائط التي يمكن أن أمرّرها للمكوّن ضمن القسم <code>props</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_33" style="">
<span class="pln">props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
        tasks_list</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	الوسيط الأول هو <code>name</code> وهو من النوع <code>String</code> أي نص، والوسيط الثاني هو <code>tasks_list</code> وهو من نوع <code>Array</code> أي مصفوفة كما هو واضح. بالنسبة لطريقة الاستخدام فهي سهلة جدا. أجر التعديل التالي على الوسم <code>tasks</code> ضمن الملف index.html:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_1624_35" style="">
<span class="pun">&lt;</span><span class="pln">tasks name</span><span class="pun">=</span><span class="str">'Husam'</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">tasks_list</span><span class="pun">=</span><span class="str">'[{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Write an introduction about vue.js components."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Drink a cup of team."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Call Jamil."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Buy new book."</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">}]</span><span class="str">'&gt;&lt;/tasks&gt;</span></pre>

<p>
	مرّرت البيانات إلى المكوّن كما لو أنّها وسوم عادية. الشيء الوحيد الملفت للنظر هو أنّني قد استخدمت الموجه <code>v-bind:‎</code> عند تمرير المصفوفة <code>tasks_list</code> وهذا الأمر إلزامي عند تمرير وسائط ديناميكية إلى المكوّنات، في حين أنّه لا يجب استخدام هذا الموجه عند تمرير وسائط نصية ساكنة كما فعلنا عند تمرير الوسيط <code>name</code>.
</p>

<p>
	<strong>ملاحظة</strong>: يوجد العديد من أنواع الوسائط التي يمكن تمريرها إلى المكونات وهي:
</p>

<pre class="ipsCode">
String, Number, Boolean, Array, Object, Function, Promise
</pre>

<h2>
	إنشاء أكثر من نسخة من المكون ضمن نفس الصفحة
</h2>

<p>
	لنعمل الآن على استخدام أكثر من مكون واحد ضمن الصفحة لنكتشف قوة المكونات. انسخ شيفرة HTML الأخيرة والصقها مرة آخرى مع إجراء بعض التعديلات البسيطة عليها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_38" style="">
<span class="tag">&lt;tasks</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'My house'</span><span class="pln"> </span><span class="atn">v-bind:tasks_list</span><span class="pun">=</span><span class="atv">'[{ title: "Do a cleaning for windows.", done: false},
        { title: "Bring some vegetables and fruits.", done: true},
        { title: "Wash clothes", done: false}]'</span><span class="tag">&gt;&lt;/tasks&gt;</span></pre>

<p>
	حدث الصفحة index.html من جديد لتحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="52222" href="https://academy.hsoub.com/uploads/monthly_2020_10/7.png.d0c4ca31f194a47026d213aa170dbf07.png" rel=""><img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52222" data-unique="a16wnkoua" src="https://academy.hsoub.com/uploads/monthly_2020_10/7.thumb.png.0795774b158c8014d19588347acd930e.png"></a>
</p>

<p>
	يمكننا بسهولة أن نستخدم هذا المكون في المكان الذي نحتاج إليه في الصفحة، كما يمكن مشاركته مع الآخرين. مازال هناك الكثير للتحدث عنه حول المكوّنات، سنتناول في الدروس اللاحقة العديد من المزايا الخاصة بها، والطرق المثالية للتعامل معها. يمكنك الحصول على الشيفرات الكاملة بالملفات الثلاثة التي عملنا عليها في هذا الدرس في المقاطع الثلاثة التالية:
</p>

<p>
	الملف index.html:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_40" style="">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">

</span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">'utf-8'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">http-equiv</span><span class="pun">=</span><span class="atv">'X-UA-Compatible'</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">'IE=edge'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">My Tasks</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'viewport'</span><span class="pln"> </span><span class="atn">content</span><span class="pun">=</span><span class="atv">'width=device-width, initial-scale=1'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"tasks.css"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Welcome to MyTasks Application</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">This application is built to explain how to deal with components</span><span class="tag">&lt;/p&gt;</span><span class="pln">

    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'app'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;tasks</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'Husam'</span><span class="pln"> </span><span class="atn">v-bind:tasks_list</span><span class="pun">=</span><span class="atv">'[{ 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 }]'</span><span class="tag">&gt;&lt;/tasks&gt;</span><span class="pln">

        </span><span class="tag">&lt;tasks</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">'My house'</span><span class="pln"> </span><span class="atn">v-bind:tasks_list</span><span class="pun">=</span><span class="atv">'[{ title: "Clean windows.", done: false},
        { title: "Bring some vegetables and fruits.", done: true},
        { title: "Wash clothes", done: false}]'</span><span class="tag">&gt;&lt;/tasks&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">



    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text/x-template'</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'tasks-template'</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">'tasks-container'</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">table </span><span class="kwd">class</span><span class="pun">=</span><span class="str">'w3-table-all'</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="pln">colgroup</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">col style</span><span class="pun">=</span><span class="str">"width:15%"</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">col style</span><span class="pun">=</span><span class="str">"width:85%"</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">colgroup</span><span class="pun">&gt;</span><span class="pln">  
                </span><span class="pun">&lt;</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">th colspan</span><span class="pun">=</span><span class="str">"2"</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">center</span><span class="pun">&gt;{{</span><span class="pln"> name </span><span class="pun">}}</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Tasks</span><span class="pun">&lt;/</span><span class="pln">center</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">th</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Done</span><span class="pun">&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="typ">Title</span><span class="pun">&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">

                    </span><span class="pun">&lt;</span><span class="pln">tr v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">"task in tasks_list"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">key</span><span class="pun">=</span><span class="str">"task.title"</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"checkbox"</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">=</span><span class="str">"task.done"</span><span class="pun">/&gt;</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                        </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                            </span><span class="pun">{{</span><span class="pln"> task</span><span class="pun">.</span><span class="pln">title </span><span class="pun">}}</span><span class="pln">
                        </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
                    </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">table</span><span class="pun">&gt;</span><span class="pln">      
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/script&gt;</span><span class="pln">

    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://unpkg.com/vue@2.6.11/dist/vue.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"app.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/body&gt;</span><span class="pln">

</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	الملف tasks.css:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1624_42" style="">
<span class="pun">.</span><span class="pln">tasks</span><span class="pun">-</span><span class="pln">container </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> solid</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">collapse</span><span class="pun">:</span><span class="pln"> collapse</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">spacing</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> table</span><span class="pun">;</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#ccc</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all tr </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid </span><span class="com">#ddd</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all tr</span><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">child</span><span class="pun">(</span><span class="pln">odd</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all tr</span><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">child</span><span class="pun">(</span><span class="pln">even</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#f1f1f1</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all td</span><span class="pun">,</span><span class="pln">
</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all th </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="lit">8px</span><span class="pun">;</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> table</span><span class="pun">-</span><span class="pln">cell</span><span class="pun">;</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> left</span><span class="pun">;</span><span class="pln">
    vertical</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> top
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all th</span><span class="pun">:</span><span class="pln">first</span><span class="pun">-</span><span class="pln">child</span><span class="pun">,</span><span class="pln">
</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all td</span><span class="pun">:</span><span class="pln">first</span><span class="pun">-</span><span class="pln">child </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16px</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">w3</span><span class="pun">-</span><span class="pln">table</span><span class="pun">-</span><span class="pln">all th</span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#d0d0d0;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الملف app.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_44" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'tasks'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#tasks-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
        tasks_list</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pln">
</span><span class="pun">})</span></pre>

<h2>
	إضافة ميزة الترشيح لمكوّن المهام
</h2>

<p>
	كثيرًا ما ستحتاج في التطبيقات التي ستكتبها إلى ميزة الترشيح بصرف النظر عن نوع التطبيق الذي تبنيه. سنتناول في هذه الفقرة كيفية إضافة هذه الميزة إلى مكوّن المهام.
</p>

<p>
	رغم أنّ هذه الميزة بسيطة، وتنحصر وظيفتها في إخفاء (أو إظهار) المهام المنجزة، إلّا أنّها ستعطيك فكرة جيدة عن كيفية عمل مثل هذه المزايا.
</p>

<p>
	سنكمل على الشيفرة الأخيرة لتطبيق المهام. ستكون ميزة التصفية على شكل صندوق اختيار Checkbox موجود أعلى قائمة المهام. عندما يختاره المستخدم فإنّ المهام المنجزة ستختفي، والعكس صحيح.
</p>

<p>
	سنبدأ بإضافة عنصر الاختيار هذا إلى الملف index.html ضمن القسم الخاص بقالب المكوّن. أضف الشيفرة التالية بعد الوسم <code>&lt;div class='tasks-container'‎&gt;</code> مباشرة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_46" style="">
<span class="pln"> </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"hide_cmp_tasks"</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"checkbox"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"hide_completed_tasks"</span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;label</span><span class="pln"> </span><span class="atn">for</span><span class="pun">=</span><span class="atv">"hide_cmp_tasks"</span><span class="tag">&gt;</span><span class="pln">Hide completed tasks</span><span class="tag">&lt;/label&gt;</span></pre>

<p>
	لاحظ معي أنّ هذا العنصر مرتبط بحقل اسمه <code>hide_competed_tasks</code> سنعرفه بعد قليل ضمن مكوّن المهام.
</p>

<p>
	افتح الآن الملف app.js وأضف القسمين <code>data</code> و <code>computed</code> للمكوّن <code>tasks</code>. سيحتوي قسم <code>data</code> على تعريف الحقل <code>hide_competed_tasks</code> المرتبط بعنصر صندوق الاختيار الذي أضفناه قبل قليل، وسيكون من النوع المنطقي <code>Boolean</code>، في حين أنّ القسم <code>computed</code> فسيحتوي على الخاصية المحسوبة <code>filtered_tasks</code>. سيصبح المكوّن <code>tasks</code> على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_48" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'tasks'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#tasks-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
        tasks_list</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            hide_completed_tasks</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        filtered_tasks</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">hide_completed_tasks </span><span class="pun">?</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tasks_list</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">done</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tasks_list</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	إذا تأملت معي محتويات الخاصية المحسوبة <code>filtered_tasks</code> فستجدها عبارة عن شيفرة برمجية بسيطة لتصفية المهام المنجزة من خلال اختبار قيمة الخاصية <code>done</code>. أي أنّ عملية التصفية ستحدث في هذا المكان تحديدًا بناءً على كون الحقل <code>hide_completed_tasks</code> يحمل القيمة <code>true</code> أو <code>false</code>.
</p>

<p>
	هذا كلّ شيء! إذا أحببت الآن، انقر بزر الفأرة الأيمن على الملف index.html الموجود ضمن نافذة المستكشف Explorer، واختر الأمر <code>Open with Live Server</code> كما اعتدنا من قبل. ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="8.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52223" data-unique="hhpz37v7l" src="https://academy.hsoub.com/uploads/monthly_2020_10/8.png.4c282874fe876eb761770a9ab45d905e.png"></p>

<p>
	جرب الآن أن تنقر بشكل متكرّر على صندوق الاختيار <code>Hide completed tasks</code> لتجد كيف أنّ المهام المنجزة تختفي وتظهر وفقًا لذلك.
</p>

<h2>
	إضافة ميزة مهمة جديدة لمكوّن المهام
</h2>

<p>
	لنحسن مكوّن المهام بميزة إضافة مهمة جديدة للمهام الموجودة مسبقًا. سأضع أسفل قائمة المهام عنصر إدخال نصي مع زر للإضافة. و سأضيف أيضًا بعض اللمسات باستخدام CSS لكي أحصل على مظهر مقبول لهما.
</p>

<p>
	افتح الملف tasks.css وأضف أصناف CSS التالية له:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1624_50" style="">
<span class="pun">.</span><span class="pln">add</span><span class="pun">-</span><span class="pln">task</span><span class="pun">-</span><span class="pln">container </span><span class="pun">{</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
    margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">add</span><span class="pun">-</span><span class="pln">task</span><span class="pun">-</span><span class="pln">container div</span><span class="pun">{</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">60px</span><span class="pun">;</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">45px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">add</span><span class="pun">-</span><span class="pln">task</span><span class="pun">-</span><span class="pln">container div input</span><span class="pun">{</span><span class="pln">
   width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">add</span><span class="pun">-</span><span class="pln">task</span><span class="pun">-</span><span class="pln">container input</span><span class="pun">{</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="lit">50px</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	انتقل الآن إلى الملف index.html وأضف الشيفرة التالية بعد نهاية وسم الإغلاق للجدول مباشرةً (ضمن القالب الخاص بمكوّن المهام):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1624_52" style="">
<span class="pln"> </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"add-task-container"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;span&gt;</span><span class="pln">Task: </span><span class="tag">&lt;/span&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
        </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">"new_task_text"</span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"button"</span><span class="pln"> </span><span class="atn">value</span><span class="pun">=</span><span class="atv">"Add"</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"add_new_task"</span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	حان الآن دور الشيفرة البرمجية ضمن الملف app.js. افتح هذا الملف، واحرص على أن تكون محتوياته مطابقة لما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1624_54" style="">
<span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'tasks'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    template</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#tasks-template'</span><span class="pun">,</span><span class="pln">
    props</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">String</span><span class="pun">,</span><span class="pln">
        tasks_list</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    data</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            hide_completed_tasks</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
            new_task_text </span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        filtered_tasks</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">hide_completed_tasks </span><span class="pun">?</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tasks_list</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">t </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">t</span><span class="pun">.</span><span class="pln">done</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tasks_list</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        add_new_task</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">tasks_list</span><span class="pun">.</span><span class="pln">push</span><span class="pun">({</span><span class="pln"> title</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">new_task_text</span><span class="pun">,</span><span class="pln"> done</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">});</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">new_task_text </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	الجديد هنا هو أنّني أضفت حقلًا جديدًا إلى القسم <code>data</code> وأسميته <code>new_task_text</code> سيرتبط بمربع النص الذي سندخل من خلاله عنوان المهمة. كما قد أضفت القسم <code>methods</code> وعرفت ضمنه التابع الجديد <code>add_new_task</code>، وهذا التابع الذي سيُستدعى عند نقر زر إضافة المهمة.
</p>

<p>
	الشيفرة البرمجية الموجودة في هذا التابع بسيطة، فهي تعمل على إضافة المهمة الجديدة إلى مصفوفة المهام <code>tasks_list</code> ثم تفرّغ عنوان المهمة من جديد لاستقبال المهمة التالية.
</p>

<p>
	جرب كتابة المهمة التالية: <code>My new task! ‎</code> ضمن مربع النص، ثم انقر الزر <code>Add</code>. ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="9.png" class="ipsImage ipsImage_thumbnailed" data-fileid="52224" data-unique="r8hvfi02s" src="https://academy.hsoub.com/uploads/monthly_2020_10/9.png.c9824f7f85a15e4cec3bd1b664176c7c.png"></p>

<h2>
	ختامًا
</h2>

<p>
	بدأنا في هذا الدرس بالولوج في عالم المكوّنات. يُعتبر ما تناولناه في هذا الدرس مقدّمة بسيطة إلّا أنها مهمة في التعامل مع المكونات. حيث تعلمنا كيف نبني هيكلًا لتطبيق بسيط على حاسوبنا الشخصي، وكيفية إضافة خادوم مبسّط لمحاكاة عمل التطبيق بشكل فعلي، كما بنينا مكوّنًا مفيدًا، وتعلّمنا أساسيات فصل شيفرة vue.js عن باقي التطبيق. هنالك المزيد لتعلّمه حول المكوّنات وحول vue.js بصورة عامة في الدروس القادمة إن شاء الله.
</p>

<h2>
	تمارين داعمة
</h2>

<h3>
	تمرين 1
</h3>

<p>
	أنشئ مكوّنًا سمّه <code>vu-countdowntimer</code> وظيفته العد التنازلي بمقدار ثانية واحدة كل مرّة، ابتداءً من قيمة محددة يمكن تمريرها للمكون، وحتى الصفر.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D8%B2%D9%8A%D8%AF-%D8%AD%D9%88%D9%84-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1032/" rel="">المزيد حول المكونات في Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D8%B5%D9%8A%D9%84-%D8%B9%D9%84%D9%89-%D9%83%D8%A7%D8%A6%D9%86-vuejs-r992/" rel="">التعرف بالتفصيل على كائن Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1031</guid><pubDate>Thu, 15 Oct 2020 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x631;&#x641; &#x628;&#x627;&#x644;&#x62A;&#x641;&#x635;&#x64A;&#x644; &#x639;&#x644;&#x649; &#x643;&#x627;&#x626;&#x646; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D8%B5%D9%8A%D9%84-%D8%B9%D9%84%D9%89-%D9%83%D8%A7%D8%A6%D9%86-vuejs-r992/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/4.png.776e8f58623a6919c25598d71927780d.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		إنشاء أكثر من كائن Vue.js
	</li>
	<li>
		الوصول إلى عناصر HTML مباشرةً باستخدام <code>‎$refs</code>
	</li>
	<li>
		الخصائص المحسوبة ضمن كائن Vue.js
	</li>
	<li>
		الخصائص المراقبة ضمن كائن Vue.js
	</li>
	<li>
		تثبيت قالب جديد باستخدام <code>‎$mount()‎</code>
	</li>
	<li>
		فصل القالب عن عنصر HTML المُستَهدَف
	</li>
	<li>
		ما هو المكوّن (Component)؟
	</li>
</ul>
<p>
	سنتعلّم في هذا الدرس المزيد عن كائن Vue.js، حيث سنتعرّف على كيفية إنشاء أكثر من كائن Vue.js وكيف نصل إلى خصائص كل كائن من خلال شيفرة JavaScript عادية. وكما سنتعرّف على الخصائص المحسوبة والخصائص المراقبة، وسنعود أيضًا إلى القوالب، وكيف نثبّت قالب ما إلى عنصر HTML بشكل برمجي.كما سنتعرّف على المكوّنات والحاجة إليها، وسنبني تطبيق بسيط للغاية يعتمد على مكوّن يعمل على التحويل من واحدة الكيلو غرام إلى واحد الباوند.
</p>

<h2>
	إنشاء أكثر من كائن Vue.js
</h2>

<p>
	من الممكن إنشاء أكثر من كائن Vue.js ضمن نفس التطبيق. حيث يمكن ربط كل كائن بعنصر <code>div</code> كما كنّا نفعل مسبقًا. يمكن لكل كائن أن يعمل بصورة مستقلة عن الكائن الآخر، وفي ذلك فائدة كبيرة، إذ يمكننا تقسيم واجهة المستخدم الرئيسية إلى أجزاء متعدّدة، كل منها ينفّذ وظيفة محدّدة، بدون أن تتداخل مع بعضها.
</p>

<p>
	في الحقيقة تقودنا هذه الميزة المهمة إلى بناء المكوّنات (Components). يلعب المكوّن دورًا مهمًّا في تنظيم الشيفرة البرمجيّة وفي عملية إعادة الاستخدام للشيفرة من قِبَلك، أو من قِبَل أي شخص آخر. سنتحدّث عن المكونات في Vue.js بشكل مبدئي في هذا الدرس.
</p>

<p>
	لنأخذ الآن مثالًا بسيطًا يوضّح كيفية إنشاء أكثر من كائن واحد بنفس الوقت:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8902_7" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app1"</span><span class="tag">&gt;</span><span class="pln">
  {{title}}
</span><span class="tag">&lt;/div&gt;</span><span class="pln">

</span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app2"</span><span class="tag">&gt;</span><span class="pln">
  {{title}}
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_9" style="">
<span class="kwd">var</span><span class="pln"> instance1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="str">'#app1'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'From first instance'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> instance2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="str">'#app2'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'From second instance'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	الشيفرة السابقة سهلة ومباشرة. بدايةً عرّفت عنصري <code>div</code> أسندت للأوّل المعرّف <code>app1</code> وللثاني المعرّف <code>app2</code>. كل من العنصرين السابقين لا يحتوي إلا على الاستبدال النصي <code>{{title}}</code>.
</p>

<p>
	بالنسبة لشيفرة JavaScript فالأمر بسيط أيضًا. فقد عرّفت كائني Vue.js وأسندت كل منهما إلى متغيرين منفصلين <code>instance1</code> و <code>instance2</code>. الكائنين متشابهين من حيث الشكل العام ولكنهما يختلفان بالقيمة النصيّة للخاصيّة <code>title</code> لكل منهما كما هو واضح.
</p>

<p>
	عند تنفيذ التطبيق السابق ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50903" data-unique="4213fmmcl" src="https://academy.hsoub.com/uploads/monthly_2020_09/1.png.ed56b4490df9892fcbb7070cc1bc4370.png"></p>

<p>
	من الواضح ظهور نصين مختلفين من كائنين مختلفين، رغم أنّه لكل منهما نفس اسم الخاصية <code>title</code>. يمكن بالطبع وجود أكثر من كائنين، ويمكن بديهةً أن يكون لكل كائن عتاده الخاص من الخصائص والدوال وغيرها.
</p>

<p>
	توجد أيضًا ميزة مهمّة لكائنات Vue.js، وهي إمكانية الوصول لأي كائن من شيفرة JavaScript عادية. انظر إلى المثال المعدّل عن المثال السابق (التعديل سيكون على شيفرة JavaScript فقط):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_11" style="">
<span class="kwd">var</span><span class="pln"> instance1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="str">'#app1'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'From first instance'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> instance2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="str">'#app2'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'From second instance'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

instance1</span><span class="pun">.</span><span class="pln">$data</span><span class="pun">.</span><span class="pln">title</span><span class="pun">=</span><span class="str">'This text from outside!'</span><span class="pun">;</span></pre>

<p>
	التعديل الوحيد الذي حدث هو في السطر الأخير. انظر كيف كتبت شيفرة JavaScript عادية للوصول إلى الخاصية <code>title</code> للكائن <code>instance1</code>. بعد التنفيذ ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50904" href="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.f82e56501e8dfc30c3e33347a5154e4d.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50904" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.f82e56501e8dfc30c3e33347a5154e4d.png"></a>
</p>

<p>
	لاحظ معي كيف أصبح السطر الأوّل. استطعت تعديل النص من خارج الكائن. وهناك أمر آخر، لعلّك قد انتبهت إلى الخاصيّة <code>‎$data</code>. في الحقيقة هو كائن يولّده Vue.js بشكل تلقائي لكي يسمح للمبرمجين بالوصول إلى الخصائص الداخلية للقسم <code>data</code>.
</p>

<p>
	هذا دليل واضح على أنّ Vue.js مندمجة بشكل ممتاز مع JavaScript وليست بديلًا عنها، إنّما مكمّلة لها. سنشاهد عددًا من هذه الكائنات والدوال المولّدة بهذه الطريقة.
</p>

<h2>
	الوصول إلى عناصر HTML مباشرة باستخدام <code>‎$refs</code>
</h2>

<p>
	توجد أكثر من طريقة للوصول إلى عناصر HTML ضمن DOM. تضيف Vue.js طريقة أخرى لها باستخدام المفتاح <code>ref</code>. يسمح هذا المفتاح للمبرمج بالوصول إلى أي عنصر HTML بسهولة كبيرة. يمكن استخدام هذا الأسلوب بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_13" style="">
<span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"app"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">=</span><span class="str">'changeText'</span><span class="pln"> ref</span><span class="pun">=</span><span class="str">'testButton'</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="typ">Old</span><span class="pln"> </span><span class="typ">Text</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_15" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    changeText</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">testButton</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="str">'New Text!'</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	الجديد هنا هو وضع الكلمة <code>ref</code> كما لو أنّها سمة ضمن العنصر <code>button</code> وإسناد القيمة <code>testButton</code> لها. الكلمة <code>ref</code> ليست سمة قياسية في HTML بالتأكيد، إنما هي كلمة تابعة لـ Vue.js. انظر الآن إلى كود JavaScript وتحديدًا ضمن التابع <code>changeText</code> ستلاحظ السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_17" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">$refs</span><span class="pun">.</span><span class="pln">testButton</span><span class="pun">.</span><span class="pln">innerText </span><span class="pun">=</span><span class="pln"> </span><span class="str">'New Text!'</span><span class="pun">;</span></pre>

<p>
	الخاصية الجديدة هنا هي <code>‎$refs</code> وهي عبارة عن كائن JavaScript مولّد تلقائيًّا. انتبه إلى وجود حرف s الخاص بالجمع آخر كلمة <code>‎$refs</code>، لأنّه من الممكن استخدام أكثر من كلمة <code>ref</code> مع عناصر HTML مختلفة. انظر أيضًا إلى الخاصيّة <code>testButton</code> وهي تحمل نفس الاسم الذي عيّنّاه ضمن الكلمة <code>key</code> في HTML. في الحقيقة إنّ <code>testButton</code> عبارة عن كائن JavaScript أيضًا يمثّل عنصر في HTML، ولذلك استطعنا استخدام الخاصية <code>innerText</code> منه.
</p>

<p>
	عند تنفيذ التطبيق السابق. ستحصل على زر وحيد يحمل النص <code>Old Text</code>. بعد نقر الزر، ستحصل على النص الجديد <code>New Text!‎</code> كما هو متوقع.
</p>

<p>
	في الواقع لا يُنصَح بتعديل خصائص عناصر HTML بهذا الأسلوب، أنصح باستخدام هذا الأسلوب فقط لقراءة خصائص عناصر HTML في حال الحاجة.
</p>

<h2>
	الخصائص المحسوبة في Vue.js
</h2>

<p>
	سنتحدّث في هذه الفقرة عن مفهوم الخاصيات المحسوبة (Computed Properties)، والحاجة إليها عند بناء تطبيقات باستخدام Vue.js. تشبه بنية الخصائص المحسوبة البنية الخاصة بالتوابع، في أنّهما عبارة عن دوال، مع فرق بسيط يتمثّل في أنّ الخاصيّة المحسوبة يجب أن تُرجع قيمة ما. تُعرّف الخصائص المحسوبة ضمن قسم جديد اسمه <code>computed</code> يُوضع على نفس مستوى القسمين <code>data</code> و <code>methods</code> أي على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_19" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#app"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تلعب الخصائص المحسوبة دورًا مهمّا عندما يكون التطبيق كبيرًا نسبيًا، حيث تسمح بتنفيذ الشيفرة البرمجية بشكل محسَّن (Optimized)، فهي تتجنّب المعالجة غير الضرورية لأجزاء من الشيفرة في حال لم يطرأ تغيير ما عليها. لفهم الخصائص المحسوبة بشكل أفضل، سنأخذ تطبيق يقيّم درجات الحرارة برسائل نصيّة بسيطة لنفهم الحاجة إلى الخصائص المحسوبة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8902_21" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;span&gt;</span><span class="pln">Current temperature:</span><span class="tag">&lt;/span&gt;&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text'</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">'temperature'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;span&gt;</span><span class="pln"> - Clouds:</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;select</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">'clouds'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;option&gt;</span><span class="pln">Yes</span><span class="tag">&lt;/option&gt;</span><span class="pln">
    </span><span class="tag">&lt;option&gt;</span><span class="pln">No</span><span class="tag">&lt;/option&gt;</span><span class="pln">
  </span><span class="tag">&lt;/select&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">
    </span><span class="tag">&lt;b&gt;</span><span class="pln">Result:</span><span class="tag">&lt;/b&gt;</span><span class="pln">  (Computed) {{evaluation_computed}} | (Method) {{evaluation_method()}}
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">
    {{clouds == 'Yes'? 'With some clouds.':'And the sky is clear.'}}
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_23" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    temperature</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
    clouds</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Yes'</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    evaluation_computed</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Computed'</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">temperature </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">35</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Hot'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">20</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Cold'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'Moderate'</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    evaluation_method</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Method'</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">temperature </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">35</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Hot'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">20</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Cold'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'Moderate'</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	بعد تنفيذ البرنامج السابق ستحصل على خرج شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50905" data-unique="z1vo657y7" src="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.266d775dc9581bb4877ea62f5ee3d87b.png"></p>

<p>
	بالنسبة لقسم HTML أعتقد أنّ الأمور واضحة، فقد عرّفت مربع نص، بالإضافة إلى عنصر قائمة منسدلة يحمل القيمتين <code>Yes</code> و <code>No</code> للإشارة إلى وجود غيوم في السماء أم لا. كل من العنصرين السابقين مربوطين ربطًا ثنائي الاتجاه باستخدام الموجّه <code>v-model</code> بالحقلين الموافقين من القسم <code>data</code> في كائن Vue.js.
</p>

<p>
	ثمّ عرّفت بعد ذلك عنصري <code>p</code> لعرض النتائج. عنصر <code>p</code> الأوّل مسؤول عن عرض تقييم الوضع الحالي للجو فيما إذا كان حارًا أم معتدلًا أم باردًا بحسب قيمة الحقل <code>temperature</code>، ولاحظ هنا أنّني أعرض التقييم من الخاصية المحسوبة <code>evaluation_computed</code> والتابع <code>evaluation_method()‎</code> على التوالي لغرض سأوضّحه لك بعد قليل. أمّا عنصر <code>p</code> الثاني فيُستخدم لإخبار المستخدم في حال وجود بعض الغيوم أم أنّ السماء صافية بحسب القيمة التي اختارها المستخدم من عنصر القائمة المنسدلة السابق. لا أدري إن كنت قد انتبهت إلى أنّني لا أضع قوسي الاستدعاء بعد اسم الخاصية المحسوبة على عكس التابع العادي المعرّف ضمن القسم <code>methods</code>.
</p>

<p>
	بالنسبة لشيفرة JavaScript، لاحظ بدايةً أنّ الشيفرة البرمجية الموجودة سواءً في الخاصية المحسوبة <code>evaluation_computed</code> أم في التابع <code>evaluation_method()‎</code> متطابقة تمامًا. ولاحظ أيضًا أنّني قد وضعت في كل منهما تعليمة الكتابة إلى الطرفية (console) الخاصة بأدوات المطوّر ضمن المتصفّح لنراقب كيف ستُنفَّذ كل منهما.
</p>

<p>
	اعرض أدوات المطوّر في المتصفّح الآن (اضغط المفتاح F12)، ثم غيّر درجة الحرارة في مربّع النص. ستلاحظ ظهور الكلمتين <code>Computed</code> و <code>Method</code> على التوالي، مما يشير إلى أنّ التنفيذ قد دخل إلى الخاصية المحسوبة <code>evaluation_computed</code> والتابع <code>evaluation_method()‎</code>. ستستمرّ الكلمتان السابقتان بالظهور على هذا النمط، كلّما أجريت أي تغيير في درجة الحرارة.
</p>

<p>
	الأمر المثير الآن، هو أنّه إذا غيّرت الاختيار الحالي ضمن عنصر القائمة المنسدلة، ستجد الكلمة <code>Method</code> قد ظهرت وحدها ضمن الطرفية، ولن تظهر الكلمة <code>Computed</code> مما يشير إلى أنّ الشيفرة البرمجية الموجودة ضمن الخاصية المحسوبة لم تُنفَّذ!
</p>

<p>
	إذًا، فالخاصية المحسوبة ذكية بما يكفي لكي تدرك أنّ درجة الحرارة لم تتغيّر فليس هناك حاجة لتنفيذ الشيفرة البرمجية الخاصّة بها كل مرّة. بعبارة أخرى، تدرك الخاصية المحسوبة أنّ الشيفرة البرمجية الموجودة ضمنها لا تحتوي على خصائص تمّ تغييرها بشكل أو بآخر، فتختصر عملية التنفيذ وتعرض التقييم السابق لدرجة الحرارة طالما أنّها لم تتغيّر!
</p>

<p>
	الشكل التالي نتج معي بعد تغيير حالة الغيوم عدّة مرات دون تغيير قيمة درجة الحرارة سوى المرّة الأولى فقط:
</p>

<p style="text-align: center;">
	<img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50906" data-unique="gdtyvz5da" src="https://academy.hsoub.com/uploads/monthly_2020_09/4.png.6001150e72c24fb9ff775ae6d1938ba5.png"></p>

<h2>
	الخصائص المراقبة ضمن كائن Vue.js
</h2>

<p>
	رغم أنّ الخصائص المحسوبة كافية في معظم الأحيان. إلّا أنّه هناك بعض الحالات التي يكون استخدام الخصائص المراقبة أفضل. والخصائص المراقبة (Watched Properties) تشبه إلى حدّ كبير الخصائص المحسوبة، وتتميّز عنها بميزتين أساسيتين:
</p>

<ol>
<li>
		يمكن تنفيذ شيفرة برمجية غير متزامنة ضمنها، بمعنى أنّه يمكن تنفيذ مهام بشكل متوازي مع التطبيق الأساسي كالاتصال بخادوم بعيد مثلًا.
	</li>
	<li>
		لا نحتاج إلى إرجاع قيمة من الخصائص المراقبة كما كنّا نفعل مع الخصائص المحسوبة.
	</li>
</ol>
<p>
	تُعرّف الخصائص المحسوبة ضمن قسم جديد اسمه <code>watch</code> يُوضع على نفس مستوى باقي الأقسام الأخرى مثل <code>data</code> و <code>methods</code> و <code>computed</code> أي على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_25" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#app"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  watch</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لنأخذ مثالًا بسيطًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8902_27" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text"</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">'content'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">
    The input has changed: {{counter}} times.
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_29" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln">
    counter</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  watch</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      tmp </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
      setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        tmp</span><span class="pun">.</span><span class="pln">counter</span><span class="pun">++;</span><span class="pln">
      </span><span class="pun">},</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	استخدمت في المثال السابق مربع إدخال نصي يسمح للمستخدم بكتابة ما يرغب. عندما يكتب المستخدم أي شيء ضمن مربّع النص، سيعمل التطبيق على إحصاء عدد مرّات التعديل التي أجراها المستخدم، ويُظهر ذلك في الأسفل ضمن رسالة مناسبة.
</p>

<p>
	استخدمت الربط ثنائي الاتجاه باستخدام <code>v-model</code> للربط مع الحقل <code>content</code> (راجع الدرس الثاني). سنراقب الحقل <code>content</code> (المرتبط مع دخل المستخدم) في حال حدث أي تغيير على قيمته. وهكذا فقد وضعت نفس اسم الحقل <code>content</code> ضمن القسم <code>watch</code> كما هو واضح، وأسندت إليه تابع. هذه هي الصيغة المعتمدة لمراقبة أي حقل.
</p>

<p>
	الذي يحدث ضمن الخاصية المراقبة بسيط في هذا المثال. فقد استخدمت التابع المُضمّن <code>setTimeout</code> لزيادة قيمة الحقل <code>counter</code> بعد ثانيتين في حال حدث أي تغيير عليه. اعتمدت هذا الأسلوب، لكي ألفت انتباهك إلى أنّ عملية العد تحدث بشكل غير متزامن، وبشكل منفصل تمامًا عن التعديلات التي يُجريها المستخدم ضمن مربّع النص.
</p>

<p>
	نفّذ التطبيق السابق، وابدأ بالكتابة والتعديل ضمن مربّع النص. ستلاحظ أنّ قيمة العدّاد ستتزايد بينما تجري التعديلات ضمن مربّع النص، ولكن هذا التزايد لا يحدث فورًا، إنّما بتأخير زمني قدره ثانيتين عن التعديلات الفعلية.
</p>

<p>
	<strong>ملاحظة</strong> لاحظ أنّني قد استخدمت المتغيّر المؤقت <code>tmp</code> لتخزين المرجع <code>this</code> قبل استخدام التابع <code>setTimeout</code> ضمن الخاصية المراقبة.
</p>

<p>
	والسبب في ذلك أنّ الشيفرة البرمجيّة ستُنفّذ ضمن مغلّف (Closure) وبالتالي لن تُشير الكلمة <code>this</code> إذا استُخدِمت مباشرةً إلى كائن Vue.js كما اعتدنا سابقًا.
</p>

<h2>
	تثبيت قالب جديد باستخدام <code>‎$mount()‎</code>
</h2>

<p>
	استخدمنا في جميع الأمثلة التي تعاملنا معها حتى الآن القسم <code>el</code> من كائن Vue.js لتحديد العنصر المُستَهدف الذي سيمثّل القالب template الذي سيعمل التطبيق على تعديله والتعامل معه كما وسبق أن أوضحنا من قبل (راجع "فهم قوالب Vue.js" من الدرس الثاني).
</p>

<p>
	إلّا أنّه يمكن الاستغناء عن القسم <code>el</code> بشكل كامل، إذا لم نكن نعرف مسبقًا العنصر الذي سنستهدفه (وبالتالي لا نعرف القالب). في هذه الحالة يمكن استخدام التابع المولّد تلقائيًّا <code>‎$mount()‎</code> الذي ينوب عن القسم <code>el</code> في هذه الحالة، وذلك في اللحظة التي نريد فيها الربط مع عنصر محدّد. انظر إلى المثال البسيط التالي لتوضيح هذه الفكرة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8902_31" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  {{title}}
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_33" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="str">'Hello!'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ أنّني قد حذفت القسم <code>el</code>، وهكذا، وعند تنفيذ المثال السابق ستحصل على الخرج التالي:
</p>

<pre class="ipsCode">
{{title}}
</pre>

<p>
	أي أنّ Vue.js لم يعرف في هذه الحالة القالب الذي سيتعامل معه. لحل هذه المشكلة وإظهار الرسالة المناسبة، سنضيف سطرًا واحدًا فقط إلى شيفرة JavaScript السابقة، لتصبح الشيفرة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_36" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="str">'Hello!'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">);</span></pre>

<p>
	إذًا فقد استخدمنا التابع <code>‎$mount()‎</code> ومرّرنا له معرّف العنصر المُستهدَف (وهو <code>‎#app</code> في مثالنا) ليعمل عندها Vue.js على ربط (mount) القالب المراد التعامل معه، وبالتالي إظهار الرسالة المناسبة للمستخدم.
</p>

<p>
	تُعتبر هذه الميزة، من المزايا المهمّة جدًّا في Vue.js حيث أنّها تسمح ببناء المكوّنات التي سنتحدّث عنها بعد قليل.
</p>

<h2>
	فصل القالب عن عنصر HTML المُستَهدَف
</h2>

<p>
	توجد ميزة مهمّة أخرى سنحتاجها لاحقًا عند العمل الموسّع مع المكوّنات، وهي إمكانية عدم كتابة شيفرة HTML التي (تُعبّر عن القالب) ضمن العنصر المُستَهدَف. بمعنى آخر، يمكن فصل شيفرة HTML التي تُعبّر عن القالب عن العنصر المُستَهدَف، ووضعها ضمن قسم جديد ضمن كائن Vue.js. اسم هذا القسم هو <code>template</code> ويوضع على نفس المستوى مع بقيّة الأقسام الرئيسية. انظر إلى الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_38" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#app"</span><span class="pun">,</span><span class="pln">
  template</span><span class="pun">:</span><span class="pln"> </span><span class="str">"HTML CODE GOES HERE"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  computed</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  watch</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لنأخذ مثالًا بسيطًا يوضّح هذه الفكرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_40" style="">
<span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"app"</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_42" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
    el</span><span class="pun">:</span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
            template</span><span class="pun">:</span><span class="str">'&lt;h2&gt;Hsoub Academy&lt;/h2&gt;'</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	بالنسبة لشيفرة HTML فهي لا تحتوي سوى العنصر المُستَهدف وهو فارغ بالطبع. أما بالنسبة لشيفرة JavaScript فهي تحتوي على كائن Vue.js بسيط، عرّفنا ضمنه العنصر المُستهدَف عن طريق <code>el</code>، وأيضًا وضعنا القالب الذي نريد التعامل معه ضمن القسم <code>template</code>. جعلت كود HTML في هذا القالب بسيطًا للغاية بهدف شرح الفكرة فقط.
</p>

<p>
	نفّذ المثال السابق لتحصل على الجملة:
</p>

<pre class="ipsCode">
Hsoub Academy
</pre>

<p>
	من الممكن أيضًا الاستغناء عن القسم <code>el</code> كليًّا واستبداله بالتابع <code>‎$mount()‎</code>. انظر شيفرة JavaScript الجديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_44" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  template</span><span class="pun">:</span><span class="str">'&lt;h2&gt;Hsoub Academy&lt;/h2&gt;'</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">);</span></pre>

<p>
	بعد التنفيذ، ستحصل على النتيجة السابقة. الآن لنجري تطويرًا بسيطًا على المثال الأخير، بحيث نعرض قيمة حقل اسمه <code>title</code> معرّف ضمن القسم <code>data</code>. سيكون التعديل ضمن شيفرة JavaScript فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_46" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  template</span><span class="pun">:</span><span class="str">'&lt;div&gt;&lt;h2&gt;Hsoub Academy&lt;/h2&gt;&lt;p&gt;{{title}}&lt;/p&gt;&lt;/div&gt;'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:{</span><span class="pln">
      title</span><span class="pun">:</span><span class="str">'Welcome dear user!'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">$mount</span><span class="pun">(</span><span class="str">'#app'</span><span class="pun">);</span></pre>

<p>
	الشيفرة السابقة سهلة ومباشرة. بعد التنفيذ ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50907" data-unique="2wo67c33q" src="https://academy.hsoub.com/uploads/monthly_2020_09/5.png.f3594850a208e5f58d0fee8e130b7dea.png"></p>

<p>
	لاحظ كيف حدث الاستبدال النصّي ضمن شيفرة HTML الموجودة ضمن القالب، وذلك بسبب وجود <code>{{title}}</code>. هناك ملاحظة بسيطة أخرى حول شيفرة HTML المكتوبة ضمن القالب. يجب أن يحتوي القالب المُسنَد إلى القسم <code>template</code> على عنصر جذر واحد، في مثالنا السابق أنشأت عنصر <code>div</code> لهذا الغرض، ووضعت فيه العنصرين <code>h2</code> و <code>p</code> كما هو واضح.
</p>

<p>
	مرّة أخرى يُعد هذا الأسلوب أساسيًّا في بناء المكوّنات واستخدامها في Vue.js. في الحقيقة لا نستخدم هذا الأسلوب كما هو في التطبيقات العملية عادةً. الذي يهمّنا هنا هو المفهوم فقط.
</p>

<h2>
	ما هو المكون (Component)؟
</h2>

<p>
	المكوّن بصورة عامّة عبارة عن وحدة برمجية مستقلة بذاتها، تُنجز عملًا واحدًا على الغالب. نصادف المكوّنات كثيرًا في عالم البرمجيات. وإذا أردت أمثلة عنها في عالم الويب، فجداول البيانات التي تعرض المعلومات المختلفة للمستخدم مع مزايا الترشيح والترتيب، وأيضًا المساحات الصغيرة الموجودة على جانب الصفحة التي تعرض درجة الحرارة الحالية أو أسعار الصرف للعملات، كلها عبارة عن مكوّنات.
</p>

<p>
	وبصورة عامة أي ناحية وظيفية يمكن أن تُستخدَم بشكل متكرر في نفس المشروع البرمجي أو في مشاريع برمجيّة مختلفة يمكن أن تُرشّح لتصبح مكونًا.
</p>

<p>
	سنلامس المكوّنات في هذا الدرس، ولن ندخل في تفاصيلها، حيث سنؤجّل ذلك إلى دروس لاحقًا. سأبني في هذا الدرس مكوّن بسيط للغاية، وظيفته التحويل من واحدة الكيلوغرام إلى واحدة الباوند. انظر إلى التطبيق التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8902_48" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;weightconverter&gt;&lt;/weightconverter&gt;</span><span class="pln">
  </span><span class="tag">&lt;weightconverter&gt;&lt;/weightconverter&gt;</span><span class="pln">
  </span><span class="tag">&lt;weightconverter&gt;&lt;/weightconverter&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_50" style="">
<span class="kwd">var</span><span class="pln"> wcComponent </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'weightconverter'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  template</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`&lt;</span><span class="pln">div style</span><span class="pun">=</span><span class="str">'margin-bottom:10px;'</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">input</span><span class="pun">=</span><span class="str">'inputChanged'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">span</span><span class="pun">&gt;</span><span class="typ">Kg</span><span class="pun">.</span><span class="pln"> is equivalent to</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">b</span><span class="pun">&gt;{{</span><span class="pln">pounds</span><span class="pun">}}&lt;</span><span class="str">/b&gt; pounds.&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;`,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      pounds</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    inputChanged</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">pounds </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2.20462</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span><span class="pln">


</span><span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'weightconverter'</span><span class="pun">:</span><span class="pln"> wcComponent
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	نفّذ التطبيق السابق، ستحصل على شكل شبيه بما يلي:
</p>

<p style="text-align: center;">
	<img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50908" data-unique="7lv5jhwjo" src="https://academy.hsoub.com/uploads/monthly_2020_09/6.png.20bd6549373e4d406ff6083543e74902.png"></p>

<p>
	سأتحدث عن شيفرة HTML بعد قليل. لننظر الآن إلى شيفرة JavaScript. لنبدأ بالقسم الأوّل من هذه الشيفرة حيث سجّلنا مكوّن جديد باستخدام التابع <code>Vue.component</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_52" style="">
<span class="kwd">var</span><span class="pln"> wcComponent </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">.</span><span class="pln">component</span><span class="pun">(</span><span class="str">'weightconverter'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  template</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`&lt;</span><span class="pln">div style</span><span class="pun">=</span><span class="str">'margin-bottom:10px;'</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">input</span><span class="pun">=</span><span class="str">'inputChanged'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">span</span><span class="pun">&gt;</span><span class="typ">Kg</span><span class="pun">.</span><span class="pln"> is equivalent to</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">b</span><span class="pun">&gt;{{</span><span class="pln">pounds</span><span class="pun">}}&lt;</span><span class="str">/b&gt; pounds.&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;`,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      pounds</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    inputChanged</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">pounds </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2.20462</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	كما هو واضح فإنّنا سنسند المكوّن الذي يُرجعه التابع <code>component()‎</code> إلى المتغيّر <code>wcComponent</code>. يقبل التابع <code>component()‎</code> وسيطين. الوسيط الأوّل هو اسم المكوّن المراد إنشاءه، وهو عبارة عن قيمة نصيّة، أمّا الوسيط الثاني فهو كائن آخر يحوي إعدادات المكوّن.
</p>

<p>
	لو تمعنت النظر بهذا الكائن، فستجد أنّه يطابق كائن Vue.js قياسي مع اختلاف واحد بسيط. يكمن الاختلاف في القسم <code>data</code>. في كائنات Vue.js التي أنشأناها حتى الآن كنّا نُسند للقسم <code>data</code> كائن عادي يحتوي على الحقول المراد التعامل معها ضمن التطبيق. أمّا في الشيفرة السابقة فيجب تعريف القسم <code>data</code> على أنّه تابع يُرجع الكائن الذي يحتوي الحقول المراد التعامل معها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_54" style="">
<span class="pln">data</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      pounds</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	ما عدا ذلك تبقى الأمور كما هي!
</p>

<p>
	أمّا القسم الثاني من شيفرة JavaScript فتحتوي على تعريف كائن Vue.js عادي، ولكن مع وجود قسم جديد وهو القسم <code>components</code>. هذا القسم يحتوي على أيّة مكونات سيستخدمها التطبيق، وهي في حالتنا هذه المكوّن <code>weightconverter</code> الذي عرّفناه قبل قليل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8902_56" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  components</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'weightconverter'</span><span class="pun">:</span><span class="pln"> wcComponent
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	لاحظ كيف نسجّل المكونات التي نريد استخدامها: اسم المكوّن يليه المرجع له (موجود ضمن المتغيّر <code>wcComponent</code> بالطبع).
</p>

<p>
	بالنسبة إلى شيفرة HTML فهي بسيطة، حيث نستخدم العنصر الجديد <code>weightconverter</code> ضمن شيفرة HTML كما لو أصبح عنصر HTML نظامي. استخدمت هذا العنصر ثلاث مرّات من باب توضيح أنّه يمكنك استخدامه في أكثر من مكان ضمن الصفحة.
</p>

<h2>
	ختامًا
</h2>

<p>
	لقد كان هذا الدرس غنيًّا بالمعلومات المتنوّعة والمهمّة خصوصًا لما يليه من دروس. سأحيلك بشكل متكرّر إلى هذا الدرس في المستقبل، كلّما اقتضت الضرورة إلى الرجوع إلى مفهوم ذُكر هنا. سننتقل في الدرس التالي إلى مستوى جديد، حيث سنتعلّم كيفية بناء تطبيقات عمليّة حقيقية، وسنتوسّع بمفهوم المكوّنات.
</p>

<h2>
	تمارين داعمة
</h2>

<h3>
	تمرين 1
</h3>

<p>
	أجر تعديلًا على تطبيق تحويل الواحدات الذي بنيناه قبل قليل، بحيث يسمح بالتحويل بالاتجاهين: من كيلوغرام إلى باوند، ومن باوند الى كيلو غرام بشكل مباشر.
</p>

<h3>
	تمرين 2
</h3>

<p>
	أنشئ مكوّن جديد، عبارة عن مؤقّت زمني تنازلي (Countdown Timer). قيمته الابتدائية دقيقة واحدة، ثم يتناقص حتى يصل للصفر. ثم استخدام هذا المكوّن ضمن تطبيق بسيط لتجربته فقط.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-vuejs-r1031/" rel="">مدخل إلى التعامل مع المكونات في Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-vuejs-r991/" rel="">الموجهات الشرطية والتكرارية في Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب<a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel=""> أساسيات إطار العمل Vue.js</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">992</guid><pubDate>Sat, 19 Sep 2020 18:08:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x645;&#x648;&#x62C;&#x647;&#x627;&#x62A; &#x627;&#x644;&#x634;&#x631;&#x637;&#x64A;&#x629; &#x648;&#x627;&#x644;&#x62A;&#x643;&#x631;&#x627;&#x631;&#x64A;&#x629; &#x641;&#x64A; Vue.js</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-vuejs-r991/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.25b04599bc12fb160f0048212eb86fb1.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		كتابة شفرات JavaScript مباشرةً ضمن القوالب
	</li>
	<li>
		التصيير الشرطي باستخدام <code>v-if</code> و <code>v-else</code> و <code>v-else-if</code>
	</li>
	<li>
		الفرق بين <code>v-if</code> و <code>v-show</code>
	</li>
	<li>
		تصيير القوائم باستخدام <code>v-for</code>
	</li>
	<li>
		المرور على خاصيات كائن
	</li>
</ul>
<p>
	نتابع عملنا في هذا الدرس وهو الدرس الثالث من سلسلة دروس تعلّم Vue.js. سنتعلّم في هذا الدرس كيفية كتابة شفرات JavaScript مباشرةً ضمن القوالب دون الحاجة إلى الاستعانة بالتوابع كما كنَّا نفعل من قبل، بالإضافة إلى استخدام التصيير (rendering) الشرطي باستخدام 'v-if' وأخواته 'v-else' و 'v-else-if'. كما سنتحدّث عن الفرق بين 'v-if' و 'v-show' اللذان لهما نفس التأثير من الناحية الشكليّة، ونختم الدرس بالحديث عن التكرار باستخدام 'v-for'. هيَّا بنا لنسبر أغوار Vue.js!
</p>

<h2>
	كتابة شفرات JavaScript مباشرة ضمن القوالب
</h2>

<p>
	يمكننا في الكثير من الأحيان أن نكتب شيفرة JavaScript مباشرةً ضمن القوالب، دون الحاجة إلى إنشاء تابع خاص ووضعه في قسم methods. نلجأ إلى هذا الأسلوب، في حال كانت الشيفرة قصيرة ولا تحتوي على الكثير من التعقيد، بالإضافة إلى ضرورة أن يكون الناتج النهائي للشيفرة عبارة عن تعبير (expression). انظر معي إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_7" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;span&gt;</span><span class="pln">Current temperature:</span><span class="tag">&lt;/span&gt;&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text'</span><span class="pln"> </span><span class="atn">v-model</span><span class="pun">=</span><span class="atv">'temperature'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">
    {{temperature &gt; 35 ? 'Hot': temperature &lt; 20 ? 'Cold' : 'Moderate' }}
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_9" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    temperature</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يعمل التطبيق السابق على عرض مربّع إدخال للمستخدم، حيث يعرض عليه إدخال درجة الحرارة الحالية، ثم يُقيّم دخل المستخدم آنيًّا أثناء الكتابة على النحو التالي:
</p>

<ul>
<li>
		إذا كانت درجة الحرارة أكبر من 35، سيعرض التطبيق الرسالة Hot
	</li>
	<li>
		إذا كانت درجة الحرارة أصغر من 20، سيعرض التطبيق الرسالة Cold
	</li>
	<li>
		إذا لم يتحقّق الشرطان السابقان سيعرض التطبيق الرسالة Moderate أي معتدل. إذا نظرت إلى قسم HTML فستجد الشيفرة التالية ضمن الاستبدال النصّي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_11" style="">
<span class="pln">temperature </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">35</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Hot'</span><span class="pun">:</span><span class="pln"> temperature </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">20</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">'Cold'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'Moderate'</span></pre>

<p>
	شيفرة JavaScript هذه عبارة عن تعبير بسيط يستخدم العامل (operator) الثلاثي <code>:?</code> بشكل متداخل لاختبار الحالات الثلاث السابقة.
</p>

<p>
	لاحظ معي أنّنا قد استخدمنا هنا الربط ثنائي الاتجاه 'v-model' لربط قيمة الحقل <code>temperature</code> مباشرة بدخل المستخدم (يمكنك العودة للدرس السابق لمراجعة هذا الموضوع).
</p>

<p>
	لاحظ أيضًا أنّ كائن Vue.js في قسم JavaScript بسيط للغاية ولا يحتوي على أية توابع.
</p>

<h2>
	التصيير الشرطي باستخدام v-if و v-else و v-else-if
</h2>

<p>
	نحتاج في الكثير من الأحيان إلى إخفاء جزء من الصفحة في حال تحقّق (أو عدم تحقّق) شرط ما. يمكن تحقيق هذا الأمر بسهولة في Vue.js من خلال استخدام الموجّه <code>v-if</code> وأخواته. لنستخدم أولًا الموجّه <code>v-if</code> لوحده:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_13" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"show = !show"</span><span class="tag">&gt;</span><span class="pln">
    Click this!
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-if</span><span class="pun">=</span><span class="atv">"show"</span><span class="tag">&gt;</span><span class="pln">
    Welcome to Hsoub Academy!
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_15" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    show</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	التطبيق السابق بسيط، تتكوّن الواجهة من زر عادي ورسالة. عند نقر هذا الزر بشكل متكرّر، تظهر الرسالة في الأسفل أو تختفي وفقًا لذلك.
</p>

<p>
	نلاحظ أولًا الحقل <code>show</code> المعرّف ضمن قسم data، والذي أسندت إليه القيمة 'true' افتراضيًا. بالنسبة لشيفرة HTML لاحظ الموجّه <code>v-on:click</code> وكيف أسندت إليه شيفرة JavaScript مباشرةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_19" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">click </span><span class="pun">=</span><span class="pln"> </span><span class="pun">“</span><span class="pln">show  </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">show</span><span class="pun">”</span></pre>

<p>
	اعتدنا مسبقًا على إدراج تابع معالج للحدث، ولكن من الممكن كتابة شيفرة JavaScript أيضًا. ما تفعله هذه الشيفرة بسيط جدًّا، فهي تعمل على تغيير قيمة <code>show</code> بين 'true' و 'false' بشكل متناوب كلّما نقر المستخدم على الزر.
</p>

<p>
	وضعت الموجّه <code>v-if</code> ضمن عنصر <code>p</code> الذي سيحتوي على النص Welcome to Hsoub Academy. أسندت لهذا الموجّه قيمة الحقل <code>show</code>. فعندما تكون قيمة <code>show</code> تساوي <code>true</code> سيظهر عنصر <code>p</code> مع الرسالة المطلوبة للمستخدم، وإلّا سيختفي عنصر <code>p</code> بشكل كامل، ليس من أمام المستخدم فحسب، وإنّما من كامل بنية DOM، وهذا النقطة من الضروري الانتباه إليها.
</p>

<p>
	من الممكن أيضًا استخدام الموجه <code>v-else</code> بعد الموجّه <code>v-if</code>. يلعب الموجّه <code>v-else</code> نفس الدور الذي تلعبه عبارة <code>else</code> في JavaScript، انظر إلى المثال البسيط التالي وهو تعديل بسيط عن المثال السابق، سيكون التعديل على شيفرة HTML فقط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_21" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"show = !show"</span><span class="tag">&gt;</span><span class="pln">
    Click this!
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-if</span><span class="pun">=</span><span class="atv">"show"</span><span class="tag">&gt;</span><span class="pln">
    Welcome in Hsoub Academy!
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-else</span><span class="tag">&gt;</span><span class="pln">
    Welcome in Vue.js!
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	الإضافة الوحيدة هي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_23" style="">
<span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-else</span><span class="tag">&gt;</span><span class="pln">
    Welcome in Vue.js!
  </span><span class="tag">&lt;/p&gt;</span></pre>

<p>
	استخدمت الموجّه <code>v-else</code>. وهكذا فعندما ينقر المستخدم الزر بشكل متكرر، ستتناوب قيمة <code>show</code> تبعًا لذلك بين 'true' و 'false'، عندما تكون قيمة <code>show</code> تساوي <code>ture</code> يظهر النص <code>Welcome to Hsoub Academy!</code> أمّا عندما تكون <code>false</code> يظهر النص <code>Welcome in Vue.js!</code>.
</p>

<p>
	ويمكن أيضًا اعتبارًا من الإصدار 2.1 للمكتبة Vue.js استخدام الموجّه <code>v-else-if</code> الذي يقابل <code>else if</code> في لغة JavaScript .
</p>

<p>
	يمكن استخدام كل من الموجّهات الشرطية السابقة مع عناصر HTML أخرى مثل <code>div</code> و <code>template</code>. الميزة في استخدام العنصر <code>template</code> هو أنّه لا يظهر في DOM عند عرض الصفحة. فهو يلعب دور حاوية لا تُصيَّر عند عرض الصفحة. سأعدّل المثال السابق ضمن قسم HTML فقط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_25" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"show = !show"</span><span class="tag">&gt;</span><span class="pln">
    Click this!
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;template</span><span class="pln"> </span><span class="atn">v-if</span><span class="pun">=</span><span class="atv">"show"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h2&gt;</span><span class="pln">
      Welcome to Hsoub Academy!
    </span><span class="tag">&lt;/h2&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">
      Here you can learn Vue.js.
    </span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/template&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	وضعت العنصرين <code>h1</code> و <code>p</code> ضمن العنصر <code>template</code>. هذه المرة، وضعت الموجّه <code>v-if</code> ضمن العنصر <code>template</code> وهكذا سنتمكّن من إخفاء كامل العنصر <code>template</code> مع العناصر الموجودة ضمنه، أو إظهاره بعناصره، وذلك بحسب قيمة الحقل <code>show</code> كما مرّ معنا.
</p>

<p>
	يمكن استخدام العنصر <code>div</code> مكان العنصر <code>template</code> بنفس الأسلوب تمامًأ، ولكن في هذه الحالة يظهر العنصر <code>div</code> ضمن DOM في حال كان شرط الإظهار محقّقًا (قيمة الحقل <code>show</code> تساوي <code>true</code>) في حين لا يظهر العنصر <code>template</code> في DOM حتى ولو كان شرط الإظهار محقّقًا، فالأمر يعود إليك في تحديد العنصر المناسب لاحتياجاتك.
</p>

<h2>
	الفرق بين <code>v-if</code> و <code>v-show</code>
</h2>

<p>
	من الممكن استخدام الموجّه <code>v-show</code> عوضًا عن الموجّه <code>v-if</code>، في إخفاء أو إظهار عنصر وفقًا لشرط معيّن كما وسبق أن رأينا قبل قليل.
</p>

<p>
	يكمن الفرق الأساسي بين الموجّهين السابقين، في أنّ الموجّه <code>v-if</code> يؤدي إلى إزالة العنصر بشكل كامل من DOM كما لو أنّه غير موجود بالأصل. أمّا الموجّه <code>v-show</code> فيعمل على إخفاء العنصر فقط، دون إزالته بالكامل من DOM.
</p>

<p>
	يمكن أن تلحظ الفرق بينهما بسهولة من خلال المثال البسيط التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_27" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"show = !show"</span><span class="tag">&gt;</span><span class="pln">
    Click this!
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
    </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-if</span><span class="pun">=</span><span class="atv">"show"</span><span class="tag">&gt;</span><span class="pln">
      Welcome to Hsoub Academy!
    </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	لاحظ أنّني استخدمت الآن الموجّه <code>v-if</code>. بالنسبة لقسم JavaScript فهو نفسه كما في الأمثلة السابقة.
</p>

<p>
	عندما يكون النص <code>Welcome to Hsoub Academy!1</code> ظاهرًا. انقر عليه بزر الفأرة الأيمن واختر <code>Inspect</code> من القائمة المنبثقة إذا كنت تستخدم Google Chrome أو اختر <code>Inspect Element</code> إذا كنت تستخدم FireFox. سترى شيئًا شبيهًا بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50898" href="https://academy.hsoub.com/uploads/monthly_2020_09/1.png.ccd559d14819604652cdf0158e118de9.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50898" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/1.png.ccd559d14819604652cdf0158e118de9.png"></a>
</p>

<p>
	انقر الآن على الزر ، سيختفي النص بالطبع. انظر إلى نافذة العناصر مرّة أخرى، لتجد أنّ عنصر <code>p</code> الذي يحتوي النص السابق قد اختفى تمامًا من المستند، وحلّ مكانه رمز تعليق (comment) كما في الشكل التالي (لاحظ المستطيل الأحمر):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50899" href="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.61d4e90443db7ef4db01594930a7ea23.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50899" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.61d4e90443db7ef4db01594930a7ea23.png"></a>
</p>

<p>
	كرّر الآن نفس التجربة السابقة، ولكن بعد أن تستبدل بالموجّه <code>v-if</code> الموجّه <code>v-show</code>. هذه المرّة لن يختفي العنصر <code>p</code> كليًّا من DOM، إنّما ستستخدم Vue.js تنسيق CSS واسمه <code>display</code> لإخفائه من أمام المستخدم دون إزالته تمامًا من DOM. انظر الشكل التالي (لاحظ المستطيل الأحمر مرّة أخرى):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50900" href="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.d682505f659b65784ac554445ee6204c.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50900" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.d682505f659b65784ac554445ee6204c.png"></a>
</p>

<h2>
	تصيير القوائم باستخدام <code>v-for</code>
</h2>

<p>
	من الممكن توليد قائمة من العناصر اعتبارًا من بيانات موجودة على شكل مصفوفة وذلك بشكل تلقائي من خلال استخدام الموجّه <code>v-for</code>، وهو يشبه إلى حدّ كبير حلقة <code>for</code> التكراريّة في لغات البرمجة عمومًا. ليكن لدينا مصفوفة اسمها <code>fruits</code> تحتوي على العناصر التالية: <code>Apple</code> و <code>Banana</code> و <code>Orange</code> و <code>Kiwi</code>. نريد إظهار هذه البيانات ضمن قائمة غير مرتّبة. يمكن استخدام البرنامج التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_29" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;ul&gt;</span><span class="pln">
    </span><span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">'fruit in fruits'</span><span class="tag">&gt;</span><span class="pln">{{fruit}}</span><span class="tag">&lt;/li&gt;</span><span class="pln">
  </span><span class="tag">&lt;/ul&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_31" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#app"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fruits</span><span class="pun">:[</span><span class="str">'Apple'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Banana'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Orange'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Kiwi'</span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وضعنا الموجّه <code>v-for</code> ضمن العنصر <code>li</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_33" style="">
<span class="pln">v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">'fruit in fruits'</span></pre>

<p>
	اسم المتغيّر <code>fruit</code> هنا كيفي، يمكنك استخدام أي اسم آخر. أمّا <code>fruits</code> فهو نفس الحقل المعرّف ضمن القسم <code>data</code> في كائن Vue.js. النتيجة ستكون على النحو التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50901" href="https://academy.hsoub.com/uploads/monthly_2020_09/4.png.f3e2cd3ee0442084742f2802972e7c09.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50901" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/4.png.f3e2cd3ee0442084742f2802972e7c09.png"></a>
</p>

<p>
	من الممكن بالطبع أن نحصل على البيانات الموجودة ضمن الحقل <code>fruits</code> من خدمة ويب (Web Service) مثلًا.
</p>

<p>
	إذا أردت أن تحصل على دليل (index) العنصر أيضًا، يمكن ذلك بسهولة بإجراء التعديل التالي على الموجّه <code>v-for</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_35" style="">
<span class="pun">&lt;</span><span class="pln">li v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">'(fruit, i) in fruits'</span><span class="pun">&gt;{{</span><span class="pln">fruit</span><span class="pun">}}</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="pun">({{</span><span class="pln">i</span><span class="pun">}})&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span></pre>

<p>
	الإضافتين الجديدتين: <code>(fruit, i)</code> و <code>({{i}})</code>. لاحظ كيف وضعنا المتغير <code>fruit</code> أولًا ثم المتغير الذي سيعبّر عن الدليل بعده، والاثنان ضمن قوسين عاديين <code>(fruit, i)</code> والترتيب بهذه الصورة مهم بالطبع. عند التنفيذ سيظهر دليل كل عنصر بجواره بين قوسين عاديين، مع الملاحظة أنّ الترقيم سيبدأ من الصفر، أي أنّ دليل العنصر الأوّل سيكون صفرًا، وهذا بديهي بالطبع. في الواقع يذكرني هذا الأسلوب المتمثّل في استخلاص الدليل، بأسلوب <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">لغة البرمجة بايثون</a> في ذلك.
</p>

<h2>
	المرور على خصائص كائن
</h2>

<p>
	يمكن استخدام الموجّه <code>v-for</code> أيضًا في المرور على خصائص كائن ما. سيكون هذا الكائن عبارة عن كائن JavaScript عادي سنعمل باستخدام هذا الموجه على استخلاص قيمة كل خاصيّة مع اسمها. ليكن لدينا الكائن التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_37" style="">
<span class="pln">customer</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Ahmad'</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">}</span></pre>

<p>
	يتألف هذا الكائن من ثلاث خصائص: <code>name</code> و <code>age</code> و <code>items</code>.
</p>

<p>
	سنمر الآن على قيم هذه الخصائص على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_39" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">'value in customer'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">
      {{value}}
    </span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_41" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#app"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    customer</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Ahmad'</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكنك بالطبع استخدام أي عنصر من HTML لعرض هذه القيم. ستظهر كل قيمة ضمن عنصر <code>p</code> خاص بها.
</p>

<p>
	إذا أردنا تطوير المثال البسيط السابق، بحيث يصبح من الممكن أن يكون لدينا مجموعة من الزبائن (customers) ونريد أن نمرّ على هذه المجموعة، مع عرض خصائص كل كائن (زبون) منها، فإنّنا سنستخدم موجّهي <code>v-for</code> متداخلين على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1012_43" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">'customer in customers'</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">v-for</span><span class="pun">=</span><span class="atv">'value in customer'</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;p&gt;</span><span class="pln">
        {{value}}
      </span><span class="tag">&lt;/p&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
    </span><span class="tag">&lt;hr&gt;</span><span class="pln">
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_45" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">"#app"</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    customers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Ahmad'</span><span class="pun">,</span><span class="pln">
        age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln">
        items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Saeed'</span><span class="pun">,</span><span class="pln">
        age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">28</span><span class="pun">,</span><span class="pln">
        items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">13</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Majd'</span><span class="pun">,</span><span class="pln">
        age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">21</span><span class="pun">,</span><span class="pln">
        items</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ كيف أجريت تعديلًا على اسم الحقل <code>customer</code> ليصبح <code>customers</code> ضمن القسم data من كائن Vue.js. لاحظ أيضًا موجّهي <code>v-for</code> المتداخلين، يمرّ الخارجي على كل عنصر من عناصر المصفوفة <code>customers</code>، في حين يمرّ الداخلي على جميع قيم الخصائص الموجودة ضمن كائن <code>customer</code> محدّد. ستحصل عند التنفيذ على خرج شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50902" href="https://academy.hsoub.com/uploads/monthly_2020_09/5.png.c263cfa8ff1d8978fa942bc2f83f9396.png" rel=""><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50902" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/5.png.c263cfa8ff1d8978fa942bc2f83f9396.png"></a>
</p>

<p>
	في المثالين الأخيرين حصلنا على قيمة الخاصيّة دون اسمها. يمكن بأسلوب مشابه لعملية الحصول على دليل العنصر ضمن المصفوفة، الحصول على اسم الخاصيّة بالإضافة إلى قيمتها. أجرِ التعديل البسيط التالي على موجّه <code>v-for</code> الداخلي الذي يمرّ على الخصائص ليصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_47" style="">
<span class="pun">&lt;</span><span class="pln">div v</span><span class="pun">-</span><span class="kwd">for</span><span class="pun">=</span><span class="str">'(value, key) in customer'</span><span class="pun">&gt;</span></pre>

<p>
	والترتيب هنا مهم أيضًا. <em>ملاحظة</em> تراقب Vue.js بعض توابع المصفوفة <code>customers</code> التي تعاملنا معها في المثال السابق باستخدام الموجّه <code>v-for</code>. هذه التوابع التي سأسردها الآن، تُغيّر في الحالة الداخلية للمصفوفة، وبالتالي تعمل Vue.js إلى إحداث تغيير فوري على الخرج يتوافق مع التغيير الذي حدث. هذه التوابع هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_49" style="">
<span class="pln">push</span><span class="pun">()</span><span class="pln">
pop</span><span class="pun">()</span><span class="pln">
shift</span><span class="pun">()</span><span class="pln">
unshift</span><span class="pun">()</span><span class="pln">
splice</span><span class="pun">()</span><span class="pln">
sort</span><span class="pun">()</span><span class="pln">
reverse</span><span class="pun">()</span></pre>

<p>
	جرّب أن تضيف إلى المثال الأخير زر، وأسند إليه الموجّه <code>v-on:click</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1012_51" style="">
<span class="pun">&lt;</span><span class="pln">button v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">click</span><span class="pun">=</span><span class="str">'customers.push({name: "Hasan", age:24, items:15})'</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="typ">Add</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> customer
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	بعد تنفيذ البرنامج ونقر هذا الزر، ستلاحظ أنّ الزبون الذي اسمه <code>Hasan</code> قد أُضيف إلى الخرج تلقائيًّا رغم أنّنا أضفناه إلى المصفوفة <code>customers</code> فقط.
</p>

<h2>
	ختامًا
</h2>

<p>
	تعلّمنا في هذا الدرس كيفيّة التعامل مع الموجّهات الشرطية مثل <code>v-if</code> و <code>v-else</code> و <code>v-else-if</code> و <code>v-show</code> وكيفيّة استخدامها في تطبيقات Vue.js. كما ميّزنا بين الموجهين <code>v-if</code> و <code>v-show</code> وتعلّمنا متى نستخدم كل منهما. كما تعرّفنا أيضًا في هذا الدرس على الموجّه <code>v-for</code> الذي يلعب نفس الدور الذي تلعبه الحلقات التكرارية في لغات البرمجة بشكل عام، واستخدمناه للمرور على عناصر المصفوفات، بالإضافة إلى المرور على خصائص كائن محدّد.
</p>

<h2>
	تمارين داعمة
</h2>

<h3>
	تمرين 1
</h3>

<p>
	أجر تعديلًا على التطبيق الزبائن <code>customers</code> السابق. في هذه المرة يجب أن تظهر أسماء الزبائن فقط، ضمن عنصر القائمة المنسدلة <code>select</code> وذلك باستخدام <code>v-for</code> أيضًا.
</p>

<h3>
	تمرين 2
</h3>

<p>
	يُطلب في هذا التمرين، تطوير التطبيق الموجود في التمرين 2 من الدرس السابق. هذه المرة ستجعل الشيفرة أسهل بكثير بعد استخدام الموجّه <code>v-for</code> بدلًا من الأسلوب الذي استخدمته هناك.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D8%AA%D8%B9%D8%B1%D9%81-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D8%B5%D9%8A%D9%84-%D8%B9%D9%84%D9%89-%D9%83%D8%A7%D8%A6%D9%86-vuejs-r992/" rel="">التعرف بالتفصيل على كائن Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-dom-r990/" rel="">استخدام Vue.js للتعامل مع DOM</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">991</guid><pubDate>Wed, 16 Sep 2020 18:06:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Vue.js &#x644;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; DOM</title><link>https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-vuejs-%D9%84%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-dom-r990/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.cb9abf3902669d3df70b8a804242a63a.png" /></p>

<p>
	سنتعلّم في هذا الدرس:
</p>

<ul>
<li>
		فهم قوالب Vue.js
	</li>
	<li>
		الوصول إلى البيانات والتوابع من كائنات Vue.js
	</li>
	<li>
		الربط مع السمات Attributes
	</li>
	<li>
		كتابة شيفرة HTML خام
	</li>
	<li>
		التعامل مع الأحداث Events
	</li>
	<li>
		استخدام الربط ثنائي الاتجاه
	</li>
</ul>
<p>
	نتابع عملنا في هذا الدرس وهو الدرس الثاني من سلسلة دروس تعلّم Vue.js. سنتعلم هذه المرّة كيفية الوصول والتعامل مع DOM، حيث سنتعلّم كيف نستخدم موجّهات Vue.js مختلفة للوصول إلى بيانات كائن Vue.js والتفاعل معها، وسنتوسّع في التعامل مع الأحداث events بالإضافة إلى كيفية استخدام الربط ثنائي الاتجاه مع العناصر.
</p>

<h2>
	فهم قوالب Vue.js
</h2>

<p>
	تعاملنا في الدرس السابق مع تطبيقات استخدمت مزايا بسيطة من Vue.js، وإذا كنت تذكر أنّنا قد كتبنا شيفرة HTML بسيطة ومن ثمّ استخدمنا الاستبدال النصي '{{ message }}' ، واستخدمنا أيضًا موجّه 'v-on' للاستجابة إلى دخل المستخدم. ما يقوم به Vue.js من وراء الكواليس، هو أخذ نسخة عن شيفرة HTML وحفظها داخليًّا على شكل قالب template، بعد ذلك يتم إجراء عملية تصيير (rendering) على نسخة من القالب السابق، باستخدام الموجّهات وتعابير الاستبدال النصي (في حال وجودها ضمن القالب)، ثمّ بعد الانتهاء من التصيير يتم عرض الخرج النهائي على المستخدم.
</p>

<p>
	الآن، وعندما يُحدَث أي تغيير جديد في قيمة أي حقل مرتبط من كائن Vue.js، ستُجرى عملية تصيير جديدة على نسخة جديدة من القالب السابق المخزّن داخليًّا، ثم يُعرض الخرج النهائي من جديد على المستخدم.
</p>

<p>
	أي كما لو أنّنا أنشأنا ارتباطًا دائمًا بين كائن Vue.js وبين شيفرة HTML. وهذا ما رأيناه فعليًا في التطبيقات البسيطة التي تناولناها في الدرس السابق. <strong>ملاحظة</strong> من باب التذكير، نستخدم في هذه السلسلة الموقع jsfiddle.net بشكل افتراضي لتشغيل جميع التطبيقات التي نكتبها. ونحتاج بالطبع إلى إدراج <a href="https://unpkg.com/vue@2.6.11/dist/vue.js" rel="external nofollow">ملف إطار العمل Vue.js</a> لكي نستطيع تنفيذ هذه التطبيقات. إذا أردت أن تعرف كيف ذلك، يمكنك العودة إلى الدرس السابق.
</p>

<h2>
	الوصول إلى البيانات والتوابع من كائنات Vue.js
</h2>

<p>
	انظر إلى المثال التالي (مثل العادة، أول مقطع يمثّل شيفرة HTML وثاني مقطع يمثّل شيفرة JavaScript):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_7" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  {{ title }}
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_9" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hello Vue!'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	عندما نستخدم الاستبدال النصي '{{ title }}' كما وسبق أن فعلنا مسبقًا، لا نستخدم الكلمة 'this' قبل 'title' كما هو واضح. في الحقيقة أنّ أي كلمة تُشير إلى حقل (مثل 'title') موجودة ضمن حاضنة مزدوجة، سيتم اعتبارها على أنّها حقل ضمن القسم data في كائن Vue.js الموافق. الآن عند تنفيذ التطبيق السابق سيؤدي إلى ظهور الجملة Hello Vue! كما هو متوقّع. وبالمثل أيضًا، يمكننا في الواقع استخدام تابع مثل <code>displayMessage()‎</code> ليحقّق نفس الخرج السابق تمامًا، وبنفس الأسلوب تقريبًا. استخدم المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_11" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  {{ displayMessage() }}
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_13" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    title</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hello Vue!'</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:{</span><span class="pln">
               displayMessage</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">title</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لاحظ أنّنا استخدمنا هذه المرة التابع <code>displayMessage()‎</code> ضمن الحاضنة المزدوجة <code>{{ displayMessage()‎ }}</code> ومرّة أخرى لم نستخدم الكلمة <code>this</code> قبل اسم التابع. أي تابع يُكتب بهذه الطريقة سيُعتَبر افتراضيًّا على أنّه تابع موجود ضمن القسم <code>methods</code> من كائن Vue.js. ولكن هذا السلوك الافتراضي لا يسري على شيفرة JavaScript الموجودة ضمن كائن Vue.js حيث يجب استخدام الكلمة <code>this</code> في كلّ مرّة أردنا فيها الوصول إلى أحد أعضاء كائن Vue.js.
</p>

<h2>
	الربط مع السمات Attributes
</h2>

<p>
	لا يمكن استخدام تقنية الاستبدال النصي (باستخدام الحاضنة المزدوجة) لإدراج قيم ضمن سمات العناصر. لفهم هذا الموضوع بشكل جيّد، انظر معي إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_15" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln"> {{ message }} - </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">'{{link}}'</span><span class="tag">&gt;</span><span class="pln">Hsoub Academy</span><span class="tag">&lt;/a&gt;</span><span class="pln">  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_17" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    message</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hello Vue!'</span><span class="pun">,</span><span class="pln">
    link</span><span class="pun">:</span><span class="pln"> </span><span class="str">'https://academy.hsoub.com/'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	عند تنفيذ التطبيق السابق في jsfiddle.net ستحصل على الخرج التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50891" href="https://academy.hsoub.com/uploads/monthly_2020_09/1.png.e696fab5a8a32d159354bc317679ce07.png" rel=""><img alt="1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50891" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/1.png.e696fab5a8a32d159354bc317679ce07.png"></a>
</p>

<p>
	لاحظ أنّه خرج منسّق كما هو متوقّع، ولكن إذا جربت النقر على الرابط لن ينقلك إلى موقع أكاديمية حسوب كما هو متوقّع، في الحقيقة سينقلك هذا الرابط إلى صفحة ضمن نفس موقع jsfiddle.net وهذه الصفحة بالطبع ستكون غير موجودة. السبب في ذلك أنّ تقنية الاستبدال النصّي تُعامِل محتويات الحقل <code>link</code> كنص مجرّد، يمكنك ملاحظة الرابط الناتج بعد النقر: <a href="https://fiddle.jshell.net/_display/%7B%7Btitle%7D%7D" ipsnoembed="true" rel="external nofollow">https://fiddle.jshell.net/_display/{{title}}</a> الحل لهذه المشكلة بسيط، ويتمثّل في تجنّب استخدام السمة <code>href</code> بهذا الشكل، إنّما ينبغي استخدام الموجّه <code>v-bind</code> مع الوسيط <code>href</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_19" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">bind</span><span class="pun">:</span><span class="pln">href </span><span class="pun">=</span><span class="pln"> </span><span class="str">'link'</span></pre>

<p>
	حيث <code>link</code> هو نفسه الحقل الموجود ضمن كائن Vue.js. استبدل بالتعبير السابق السمة href القديمة الموجودة ضمن شيفرة HTML الموجود في المثال السابق، بعد الاستبدال سيصبح شكل شيفرة HTML على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_21" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln"> {{ message }} - </span><span class="tag">&lt;a</span><span class="pln"> </span><span class="atn">v-bind:href</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="atv">'link'</span><span class="tag">&gt;</span><span class="pln">Hsoub Academy</span><span class="tag">&lt;/a&gt;</span><span class="pln">  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	أعد تشغيل التطبيق مرّة أخرى، ستحصل على نفس الخرج، ولكن هذه المرّة إذا نقرت على الرابط ستنتقل إلى موقع أكاديمية حسوب. إذًا كخلاصة على ما سبق، إذا أردت أن تربط مع السمات فعليك استخدام موجّه مع الوسيط المناسب بدلًا من استخدام تقنية الاستبدال النصّي. سنتناول عددًا من هذه الموجّهات خلال هذه السلسلة، ويمكنك دومًا زيارة الصفحة الرسمية لإطار العمل Vue.js على الرابط <a href="https://Vue.js.org/v2/guide/" rel="external nofollow">رابط</a> للاطلاع على جميع الموجّهات المتوفّرة.
</p>

<h2>
	كتابة شيفرة HTML خام
</h2>

<p>
	نحتاج في بعض الأحيان إلى كتابة شيفرة HTML خام مباشرةً في الصفحة. قد يتبادر إلى ذهنك أن تستخدم الاستبدال النصي مع الحاضنة المزدوجة، ولكن لن تنفع هذه التقنية في هذه الحالة. تأمّل معي المثال التالي لفهم أفضل حول هذه المشكلة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_23" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  {{ raw }}
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_25" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    raw</span><span class="pun">:</span><span class="pln"> </span><span class="str">'&lt;ul&gt;&lt;li&gt;First Item&lt;/li&gt;&lt;li&gt;Second Item&lt;/li&gt;&lt;li&gt;Third Item&lt;/li&gt;&lt;/ul&gt;'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	الهدف من التطبيق السابق هو عرض قائمة غير مرتّبة عن طريق العنصر 'ul' تُظهر ثلاثة عناصر فقط: First Item و Second Item و Third Item. ولكن عند التنفيذ لن تحصل على ما هو متوقع، ستحصل على الخرج التالي:
</p>

<pre class="ipsCode" id="ips_uid_4116_52">
First Item
Second Item
Third Item</pre>

<p>
	أي أنّك ستحصل على نص عادي دون أن يتعرّف عليه المتصفّح على أنّه شيفرة HTML. يمكن هذه المشكلة بسهولة بإجراء تعديل على شيفرة HTML فقط على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_54" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-html</span><span class="pun">=</span><span class="atv">'raw'</span><span class="tag">&gt;</span><span class="pln">

  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	التعديل الذي أجريته هو استخدام الموجّه <code>v-html</code> الذي يسمح في حالتنا هذه باستخدام محتويات الحقل <code>raw</code> كشيفرة HTML نظامية وليس مجرّد نص عادي (لاحظ أنّني قد تخلصت من الاستبدال النصّي <code>{{ raw }}</code>. أعد تنفيذ التطبيق، لتحصل على قائمة مُنسّقة بشكل صحيح.
</p>

<h2>
	التعامل مع الأحداث (Events)
</h2>

<p>
	للأحدث كما نعلم أهميّة عظيمة في تطوير التطبيقات التي تتفاعل مع المستخدم. تدعم Vue.js الأحداث بشكل جيّد، ولقد تعاملنا في الدرس السابق مع نوعين من الأحداث: حدث الإدخال ضمن مربّع النص، وحدث النقر بزر الفأرة على عنصر HTML. سنتناول في هذا الدرس الأحداث بشيء من التفصيل، حيث سنتعلّم كيف ننصت إلى أحداث الفأرة، بالإضافة إلى الإنصات إلى أحداث لوحة المفاتيح.
</p>

<h3>
	الإنصات إلى أحداث الفأرة
</h3>

<p>
	نبدأ بالتعامل مع أحداث الفأرة، لتُنعش ذاكرتك، انظر معي إلى التطبيق البسيط الموجود في الدرس السابق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_56" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text'</span><span class="pln"> </span><span class="atn">v-on:input</span><span class="pun">=</span><span class="atv">"updateInfo"</span><span class="tag">/&gt;</span><span class="pln">
  {{ message }}
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_58" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    message</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hello Vue!'</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:{</span><span class="pln">
            updateInfo</span><span class="pun">:</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">){</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">message </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	سبق وأن ذكرنا في الدرس السابق أنّه يتم الإنصات إلى أي حدث ضمن عنصر ما باستخدام الموجّه<code>v-on</code>، حيث يتم تغيير الوسيط المُمرّر لهذا الموجّه بتغيّر نوع الحدث المراد الإنصات له. بعد تحديد نوع الوسيط المراد تمريره للموجّه <code>v-on</code> يتم تحديد التابع الذي سيستجيب (سيعالج) هذا الحدث، وهو عبارة عن تابع ضمن القسم <code>methods</code> ضمن كائن Vue.js يتم استدعاؤه عند وقوع الحدث.
</p>

<p>
	بالنسبة للتابع المعالج للحدث (التابع <code>updateInfo</code> في المثال السابق) سيتم توليد كائن يحتوي على معلومات مهمّة حول الحدث الذي وقع، ويتم تمرير هذا الكائن بشكل تلقائي إلى التابع المعالج للحدث.
</p>

<p>
	على العموم، يمكن الاستغناء عن هذا السلوك التلقائي، وتمرير قيمة كيفيّة للتابع المعالج للحدث. انظر معي إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_60" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'app'</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"increase(2)"</span><span class="tag">&gt;</span><span class="pln">Increase!</span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">{{counter}}</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span><span class="pln"> </span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_62" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    counter</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:{</span><span class="pln">
               increase</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">value</span><span class="pun">){</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">counter </span><span class="pun">+=</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	الشيفرة السابقة مألوفة، مع ملاحظتين جديدتين. الأولى أنّنا لم نكتفي بكتابة اسم التابع المعالج للحدث ضمن الموجّه <code>v-on:click</code> فحسب، إنّما قد مرّرنا القيمة 2 كوسيط لهذا التابع على الشكل: <code>increase(2)‎</code> (لاحظ شيفرة HTML). بالمقابل، إذا تأملت شيفرة JavaScript ضمن تعريف التابع <code>increase</code> في القسم <code>methods</code>، فستلاحظ أنّنا نعامل الوسيط <code>value</code> كمتغيّر يحمل قيمة عددية وليس ككائن يحمل معلومات حول الحدث الذي وقع. أي أنّنا قد استطعنا تغيير السلوك الإفتراضي لعمليّة استدعاء التابع المعالج. بالنسبة للمثال السابق، فكما هو واضح، يعمل التطبيق على زيادة قيمة المتغيّر <code>counter</code> بمقدار القيمة <code>value</code> (في مثالنا السابق ستكون تساوي 2) في كل مرّة يتم فيها نقر الزر.
</p>

<p>
	في بعض الحالات قد نحتاج إلى تمرير كائن الحدث بالإضافة إلى تمرير قيمة كيفيّة بنفس الوقت. تدعم Vue.js هذا الأمر ببساطة من خلال تمرير الكلمة المحجوزة <code>‎$event</code> إلى التابع المعالج بالإضافة إلى القيمة الكيفية المراد تمريرها. إذا أردنا تطبيق ذلك على المثال الأخير فسيصبح تعريف الزر <code>button</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_64" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">v-on:click</span><span class="pun">=</span><span class="atv">"increase(2, $event)"</span><span class="tag">&gt;</span><span class="pln">Increase!</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	وبالنسبة لتعريف التابع المعالج ضمن القسم methods فسيصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_66" style="">
<span class="pln">increase</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">){</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">counter </span><span class="pun">+=</span><span class="pln"> value</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	أي مجرّد إضافة وسيط آخر.
</p>

<h3>
	التعديل على كيفية الاستجابة للأحداث
</h3>

<p>
	نحتاج في بعض الأحيان أن نُعدّل على كيفيّة الاستجابة للأحداث، فربما نحتاج في وقت ما إلى إيقاف الاستجابة لحدث ما لأحد العناصر دونًا عن العناصر الأخرى في HTML. لكي أضرب لك مثالًا جميلًا حول هذا الأمر، اسمح لي أولًا أن أقدّم لك حدث حركة الفأرة <code>mousemove</code>. يُولّد هذا الحدث عند مرور مؤشّر الفأرة فوق عنصر ما، ويتم استخدامه كما هو متوقّع مع الموجّه <code>v-on</code>. انظر إلى المثال البسيط التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_68" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-on:mousemove</span><span class="pun">=</span><span class="atv">'updateCoordinates'</span><span class="tag">&gt;</span><span class="pln">
    Mouse cursor at: ({{x}}, {{y}})
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_70" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x</span><span class="pun">:</span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    y</span><span class="pun">:</span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:{</span><span class="pln">
      updateCoordinates</span><span class="pun">:</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">){</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	جرّب تنفيذ التطبيق البسيط السابق، ثمّ حرّك الفأرة فوق العنصر الوحيد الظاهر أمامك. ستحصل على خرج شبيه بما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50892" href="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.42316c43d4957c4dde0315a402c72287.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50892" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/2.png.42316c43d4957c4dde0315a402c72287.png"></a>
</p>

<p>
	الجديد هنا هو استخدام الموجّه <code>v-on:mousemove</code> حيث أسندنا إليه التابع المعالج <code>updateCoordinates</code> المعرَّف بطبيعة الحال ضمن القسم <code>methods</code> في كائن Vue.js. لاحظ معي أيضًا كيف نحصل على الإحداثيات الحالية لمؤشّر الفأرة (الفاصلة x والتراتيب y) ضمن التابع <code>updateCoordinates</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_72" style="">
<span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY</span><span class="pun">;</span></pre>

<p>
	الآن إذا أردنا أن ننشئ منطقة "ميتة" (ضمن عنصر <a href="https://wiki.hsoub.com/HTML/span" rel="external"><code>span</code></a> مثلًا) ضمن عنصر <code>p</code> الذي يعرض الإحداثيات، بحيث لايؤدّي مرور مؤشّر الفأرة فوق هذه المنطقة إلى توليد الحدث <code>mousemove</code>، فينبغي علينا عندها التعديل على الحدث <code>mousemove</code> كما يلي (سألوّن التعديلات الإضافية بالأخضر):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_74" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p</span><span class="pln"> </span><span class="atn">v-on:mousemove</span><span class="pun">=</span><span class="atv">'updateCoordinates'</span><span class="tag">&gt;</span><span class="pln">
    Mouse cursor at: ({{x}}, {{y}}) -
    </span><span class="tag">&lt;span</span><span class="pln"> </span><span class="atn">v-on:mousemove</span><span class="pun">=</span><span class="atv">'uncoveredArea'</span><span class="tag">&gt;</span><span class="pln">Uncovered Area</span><span class="tag">&lt;/span&gt;</span><span class="pln">
  </span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_76" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    x</span><span class="pun">:</span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    y</span><span class="pun">:</span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:{</span><span class="pln">
      updateCoordinates</span><span class="pun">:</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">){</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">x </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientX</span><span class="pun">;</span><span class="pln">
      </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">y </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">clientY</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    uncoveredArea</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">){</span><span class="pln">
        event</span><span class="pun">.</span><span class="pln">stopPropagation</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	أضفت الموجّه <code>v-on:mousemove</code> إلى العنصر <code>span</code> وأسندت المعالج <code>uncoveredArea</code> له. بالنسبة للتابع <code>uncoveredArea</code> فقد أجريت تعديل على الحدث من خلال استدعاء التابع <code>stopPropagation()‎</code> من الكائن <code>event</code>. المعنى الحرفي لهذا التابع هو "إيقاف الانتشار" أي أنّنا سنمنع الإستجابة لهذا الحدث عندما يمر مؤشّر الفأرة فوق العنصر <code>span</code>. جرّب تنفيذ التطبيق السابق، ولاحظ التغيير الذي سيحدث عندما يمر مؤشّر الفأرة فوق عنصر <code>span</code>. إذا أردت الإحساس بالفرق، يمكنك أن تحذف التعليمة <code>event.stopPropagation()‎</code> ثم أعد تنفيذ التطبيق مرّة أخرى، لترى كيف أنّ الإحداثيات ستتغيّر عندما يمر مؤشّر الفأرة فوق عنصر <code>span</code> هذه المرة. يمكن استخدام صيغة أبسط للتعديل على الأحداث، فمن الممكن حذف التابع <code>uncoveredArea</code> بالكامل من قسم <code>methods</code>، والاكتفاء بالقسم الخاص بالموجّه على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_78" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">mousemove</span><span class="pun">.</span><span class="pln">stop</span><span class="pun">=</span><span class="str">''</span></pre>

<p>
	أي أنّنا قد استغنينا عن الشيفرة اللازمة لإيقاف انتشار الحدث <code>mousemove</code>. نسمي <code>‎.stop</code> هنا بمعدِّل الحدث (event modifiers). هناك عدّة معدّلات أحداث مفيدة سنستعرض بعضها منها خلال مسيرتنا في هذه السلسلة.
</p>

<h3>
	الإنصات إلى أحداث لوحة المفاتيح
</h3>

<p>
	يمكننا أحيانًا أن نحتاج إلى الإنصات أيضًا إلى الأحداث الناشئة من لوحة المفاتيح. والأسلوب المتبع هنا، يشبه إلى حدّ كبير ما كنّا نفعله مع أحداث الفأرة. إذا أردنا مثلًا الإنصات إلى حدث تحرير مفتاح من لوحة المفاتيح يمكن أن نستخدم الوسيط 'keyup' للموجّه <code>v-on</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_80" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">keyup</span><span class="pun">=</span><span class="str">'methodName'</span></pre>

<p>
	حيث 'methodName' هو اسم التابع المعالج للحدث 'keyup' والذي يجب أن يُوضَع ضمن القسم methods. دعنا الآن نوظّف ذلك في مثال بسيط:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4116_82" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"app"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">'text'</span><span class="pln"> </span><span class="atn">v-on:keyup</span><span class="pun">=</span><span class="atv">'keyIsUp'</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">
    {{message}}
    </span><span class="tag">&lt;/p&gt;</span><span class="pln">

</span><span class="tag">&lt;/div&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_84" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    message</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  methods</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    keyIsUp</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">message </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يعمل هذا التطبيق البسيط على تحديث الحقل 'message' كلّما تمّ تحرير مفتاح من لوحة المفاتيح، وبالتالي سيؤدّي ذلك إلى تحديث محتويات عنصر 'p' ضمن الواجهة. ولكن دعنا نتساءل، ماذا لو أردنا أن يستجيب المعالج 'keyIsUp' كلّما حُرِّر مفتاح المسافة (space) فقط، وليس عند أيّ مفتاح يُحرِّره المستخدم. الجواب ببساطة، هو في استخدام معدّل الحدث '.space' بعد 'keyup'. أضف فقط الكلمة '.space' إلى 'keyup' إلى المثال السابق. أي على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_86" style="">
<span class="pln">v</span><span class="pun">-</span><span class="pln">on</span><span class="pun">:</span><span class="pln">keyup</span><span class="pun">.</span><span class="pln">space </span><span class="pun">=</span><span class="pln"> </span><span class="str">'keyIsUp'</span></pre>

<p>
	أعد تنفيذ التطبيق لترى أنّ محتويات عنصر 'p' أصبحت لا تُحدَّث إلّا بعد تحرير المفتاح space. يوجد بالطبع العديد من المعدّلات التي تمثّل جميع المفاتيح على لوحة المفاتيح، فهناك مثلًا 'enter' و 'tab' و 'up' لمفتاح السهم العلوي، و 'down' لمفتاح السهم السفلي وهكذا. لمعدّلات أحداث لوحة المفاتيح الكثير من الفوائد، يتمثّل أبسطها في إرسال المحتوى الذي أدخله المستخدم بمجرد ضغطه للمفتاح Enter، أو إرسال البيانات مباشرةً بينما يكتبها المستخدم للحصول على مقترحات أثناء عملية الكتابة (كما يفعل محرّك البحث غوغل أثناء كتابة المستخدم للمفردات المراد البحث عنها). وغيرها الكثير من الاستخدامات.
</p>

<h2>
	استخدام الربط ثنائي الاتجاه
</h2>

<p>
	في معظم الأمثلة السابقة عمدنا إلى استخدام ربط باتجاه واحد، من الشيفرة إلى عنصر HTML. وفي بعض الحالات استطعنا أن نعكس هذا الأمر. أي استطعنا تعديل قيمة الحقل عن طريق الانصات إلى حدث الإدخال v-on:input وبالتالي معالج حدث مخصّص لهذه الغاية. ولكن توجد طريقة مباشرة وسهلة لإيجاد ربط ثنائي الاتجاه فعلي في Vue.js وذلك باستخدام الموجّه v-model وبدون الحاجة إلى معالج حدث، كمال في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_88" style="">
<span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"app"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln"> v</span><span class="pun">-</span><span class="pln">model</span><span class="pun">=</span><span class="str">'name'</span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">{{</span><span class="pln"> name </span><span class="pun">}}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4116_90" style="">
<span class="kwd">var</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Vue</span><span class="pun">({</span><span class="pln">
  el</span><span class="pun">:</span><span class="pln"> </span><span class="str">'#app'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hello Vue!'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	التطبيق السابق بسيط، وهو يعمل على إجراء ربط ثنائي الاتجاه بين الحقل name وبين عنصر مربّع النص، أي سيكون هناك ارتباط آني بين الحقل name وبين عنصر مربّع النص، فإذا حدث تغيّر لأحدهما سينعكس مباشرةً على الآخر. نفّذ التطبيق السابق وسترى مباشرةً الخرج التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50893" href="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.33b6e9a642afe8ad34ab177bcc3f26a9.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50893" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/3.png.33b6e9a642afe8ad34ab177bcc3f26a9.png"></a>
</p>

<p>
	لاحظ كيف أنّ محتوى مربّع النص قد تمّت تعبئته تلقائيًا بقيمة الحقل name، وبالمثل إذا حاولت الآن كتابة أي شيء ضمن مربّع النص سيتم تعديل قيمة الحقل name فورًا وفقًا له، وبالتالي سيُعدّل محتوى النص الموجود في الطرف الأيمن بسبب وجود الاستبدال النصي {{name}}.
</p>

<h2>
	ختامًا
</h2>

<p>
	تعلّمنا في هذا الدرس كيفيّة التعامل مع DOM، حيث تحدثنا عن القوالب، وكيف نصل إلى البيانات والتوابع بشيء من التفصيل، كما تعلّمنا كيفيّة الربط مع السمات، والتعامل مع الأحداث، وتعلّمنا كيفية الربط ثنائي الاتجاه الذي يسمح لنا بمزامنة البيانات بالاتجاهين.
</p>

<h2>
	تمارين داعمة
</h2>

<h3>
	تمرين 1
</h3>

<p>
	يُطلب في هذا التمرين تطوير تطبيق الآلة الحاسبة البسيط الذي بنيناه في الدرس السابق. بحيث يسمح التطبيق الجديد بإجراء العمليات الحسابية الأربع بدلًا من عملية الجمع الوحيدة التي كان يدعمها التطبيق السابق. أقترح الواجهة التالية للتطبيق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50894" href="https://academy.hsoub.com/uploads/monthly_2020_09/4.png.309d5a8dc6d5ca1613dac7e869729ddf.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50894" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/4.png.309d5a8dc6d5ca1613dac7e869729ddf.png"></a>
</p>

<p>
	لاحظ أنّني قد استخدمت عنصر 'select'، يمكنك استخدام أي طريقة أخرى لاختيار العمليات الحسابية الأربع. من الضروري أن يُوجِد التطبيق الناتج النهائي إذا حدث أحد الأمرين التاليين:
</p>

<ul>
<li>
		تغيير قيمة أحد المعاملين على طرفي العملية الحسابية.
	</li>
	<li>
		تغيير العملية الحسابية عن طريق القائمة المنسدلة.
	</li>
</ul>
<p>
	أرجو أن يتمكن التطبيق من تمييز حالة القسمة على صفر، وإظهار رسالة مناسبة للمستخدم.
</p>

<h3>
	تمرين 2
</h3>

<p>
	يُطلب في هذا التمرين إنشاء تطبيق يقدّم للمستخدم مقترحات نصيّة بينما يكتب المستخدم ضمن مربّع نص. سنحاكي عملية الاتصال مع خادوم بعيد عن طريق استخدام مصفوفة نصيّة ضمن الشيفرة. وسأعتبر أنّ المستخدم يحاول أن يُدخل اسم دولة عربية، فتظهر قائمة المقترحات بالأسفل بينما تتم عملية الإدخال. كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="50895" href="https://academy.hsoub.com/uploads/monthly_2020_09/5.png.f42052ca65c670fbd3abf98760e0288f.png" rel=""><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="50895" data-unique="data-unique" src="https://academy.hsoub.com/uploads/monthly_2020_09/5.png.f42052ca65c670fbd3abf98760e0288f.png"></a>
</p>

<p>
	ستحتاج بالطبع إلى التعامل مع أحداث لوحة المفاتيح. ولكي يكون الأمر أكثر سهولة بالنسبة إليك. يمكنك استخدام المصفوفة الجاهزة التالية كمصدر للبيانات التي يُفترَض أن تكون قادمة من الخادوم:
</p>

<pre class="ipsCode">
[
      'السعودية',
      'البحرين',
      'مصر',
      'السودان',
      'ليبيا',
      'الجزائر',
      'المغرب',
      'تونس',
      'موريتانيا',
      'العراق',
      'سوريا',
      'لبنان',
      'قطر',
      'الإمارات',
      'الصومال',
      'جزر القمر',
      'الكويت',
      'سلطنة عُمان',
      'الأردن',
      'اليمن',
      'فلسطين'
    ]
</pre>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-vuejs-r991/" rel="">الموجهات الشرطية والتكرارية في Vue.js</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/javascript/vuejs/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-vuejs-r989/" rel="">مقدمة إلى Vue.js</a>
	</li>
	<li>
		النسخة الكاملة لكتاب <a href="https://academy.hsoub.com/files/22-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-vuejs/" rel="">أساسيات إطار العمل Vue.js </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">990</guid><pubDate>Sat, 12 Sep 2020 18:06:00 +0000</pubDate></item></channel></rss>
