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

مدخل إلى التعامل مع المكونات في Vue.js


حسام برهان

سنتعلّم في هذا الدرس:

  • تجهيز هيكل التطبيق على حاسوب محلّي.
  • بناء مكوّن جديد: مكوّن المهام.
  • تحسين تجربة الاستخدام للمكوّن.
  • تمرير وسائط إلى المكوّنات.
  • إنشاء أكثر من نسخة من المكون ضمن نفس الصفحة.
  • إضافة ميزة التصفية لمكوّن المهام.
  • إضافة ميزة مهمة جديدة لمكوّن المهام.

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

تجهيز هيكل التطبيق على حاسوب محلّي

سنسلك هذه المرّة منحًى مغايرًا عمّا اعتدناه في الدروس السابقة. كان تركيزنا في الدروس السابقة منصبًّا على كتابة تطبيقات vue.js ضمن موقع JSFiddle، وهذا الأمر جيّد في الواقع عندما نريد التعلّم أو تجريب بعض المزايا الخفيفة. ولكن عند الانتقال إلى مستوى أعلى ببناء تطبيقات عملية وواقعية، ينبغي علينا بالتأكيد الانتقال إلى أدوات تطوير فعًالة ومناسبة.

تشتمل هذه الأدوات بطبيعة الحال على خادوم نستخدمه أثناء بناء التطبيق، نحاكي من خلاله سلوك الخواديم الفعلية التي ستستضيف تطبيقنا النهائي الذي سيعمل عليه المستخدم في نهاية المطاف. في الحقيقة، أنصح دومًا بجعل ظروف تجريب التطبيق مماثلة قدر المستطاع لما سيكون عليه الوضع النهائي للتطبيق.

سنستخدم في هذا الدرس وغيره من الدروس اللاحقة، محرّر الشيفرة البرمجيّة Visual Studio Code من Microsoft. يمكنك في الواقع اختيار المحرّر الذي ترغب به، أو حتى يمكنك استخدام بيئة تطوير متكاملة إن أحببت. يوجد العديد من محرّرات النصوص البرمجية الأخرى مثل Atom و Sublime Text و Brackets.

لتنصيب Visual Studio Code يمكنك زيارة الصفحة التالية code.visualstudio.com/download. يمكنك اختيار نظام التشغيل المناسب لك من الأسفل. بالنسبة لنا سنختار النسخة الخاصة بويندوز. بعد التنزيل، نصّب التطبيق مع ترك الخيارات الافتراضية كما هي (قد تحتاج إلى صلاحيات مدير النظام).

بعد تثبيت Visual Studio Code انتقل إلى الإضافات Extensions الخاصّة به، واعمل على تثبيت الإضافة Live Server التي سنستخدمها كخادوم بسيط. انظر الشكل التالي:

1.png

يمكنك الوصول مباشرةً إلى مدير الإضافات من الناحية اليسرى من الشاشة، كما هو ظاهر من الشكل السابق. بعد ذلك أدخل اسم الإضافة: Live Server في خانة البحث. بعد أن يجده، اختره، لتظهر النافذة الخاصة به كما في الشكل السابق، ثم انقر الزر الأخضر Install لتثبيته.

من المفيد أيضًا تثبيت الإضافتين التاليتين:

  • الإضافة Vetur لتنسيق الشيفرة الخاصة بـ vue.js.
  • الإضافة HTML5 Boilerplate لتنسيق شيفرة HTML.

اكتب اسم كل من هاتين الإضافتين في خانة البحث، واعمل على تثبيتهما كما فعلنا قبل قليل مع الإضافة Live Server.

ملاحظة: أنصح بإعادة تشغيل Visual Studio Code عند هذه المرحلة حتى ولو لم يطلب منك ذلك.

لنبدأ ببناء مشروعنا! انتقل إلى المكان الذي ترغب فيه بإنشاء المشروع على القرص الصلب، وأنشئ مجلّدًا سمّه veujs-mytasks. انتقل مرّة أخرة إلى Visual Studio Code ثم اختر الأمر File -> ‏Open Folder واختر المجلّد الذي أنشأته توًّا.

من نافذة المستكشف Explorer الموجودة في الطرف الأيسر، لاحظ الأيقونتين الصغيرتين، ضع مؤشّر الفأرة للحظات فوق كل منهما لتكتشف وظيفة كل منهما. الأيقونة الأولى من اليسار وظيفتها إنشاء ملف جديد ضمن المجلّد الحالي، والأيقونة الأخرى وظيفتها إنشاء مجلّد جديد ضمن المجلّد الحالي.

2.png

استخدم زر ملف جديد لتُنشئ ملفين، واختر الاسمين index.html و app.js لهما على الترتيب. ستحصل في النهاية على شكل شبيه بما يلي:

3.png

اختر الملف index.html لكي تفتحه، ثم انسخ شيفرة HTML التالية إليه:

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>My Tasks</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
</head>

<body>
    <h1>Welcome to MyTasks Application</h1>
    <p>This application is built to explain how to deal with components</p>

    <div id='app'>
        <tasks></tasks>
    </div>




    <script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
    <script src="app.js"></script>
</body>

</html>

شيفرة HTML السابقة عبارة عن شيفرة بسيطة، الأمر الجديد الوحيد فيها هو إضافة العنصر tasks وهو المكوّن الذي سنبنيه بعد قليل وسيمثّل قائمة المهام التي نرغب ببنائها. لاحظ أيضًا أنّنا وضعنا هذا العنصر الجديد ضمن عنصر div له الوسم id = 'app'‎ وهو العنصر المستهدَف في كائن vue.js كما اعتدنا سابقًا. وأخيرًا، لاحظ كيف أضفت مرجعين لملف إطار العمل vue.js بالإضافة إلى مرجع للملف app.js الذي سيحتوي على الشيفرة البرمجية لكل من المكوّن والتطبيق:

<script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
<script src="app.js"></script>

لننتقل الآن إلى الملف app.js، انسخ الشيفرة البرمجية التالية إليه:

Vue.component('tasks', {
    template: '<strong><p>{{name}} - Tasks</p></strong>',
    data() {
        return {
            name: 'Husam'
        }
    }
})

new Vue({
    el: '#app'
})

الشيفرة البرمجيّة هنا مماثلة لتلك التي تعاملها معها في الدرس السابق، حيث نسجّل مكوّن جديد باسم tasks بحيث نُسند له قالب بسيط، يعرض اسم الشخص الذي سنُسند إليه هذه المهام عن طريق الخاصية {{name}} كما هو واضح. ثم ننشئ كائن vue.js بسيط ونعيّن العنصر المستهدف.

انتقل الآن إلى نافذة المستكشف Explorer، وانقر بزر الفأرة الأيمن على الملف index.html ثم اختر الأمر Open with Live Server (تذكّر أننا ثبتنا الإضافة Live Server قبل قليل)، سيؤدي ذلك إلى فتح نافذة أو تبويب جديد ضمن متصفّح الانترنت الافتراضي لديك بحيث يتجه إلى العنوان http://127.0.0.1:5500/index.html وهو العنوان مع المنفذ الافتراضي الذي ينصت عنده الخادوم Live Server. ستحصل على شكل شبيه بما يلي:

4.png

هذا دليل على أنّ الأمور تسير على ما يرام. وأنّ نجحنا ببناء الهيكل العام للتطبيق. لننتقل الآن للمرحلة التالية.

بناء مكوّن جديد: مكوّن المهام

لنبدأ الآن بالعمل الفعلي في بناء المكوّن الخاص بالمهام، والذي أسميناه tasks. سأنقل أولًا شيفرة HTML المسندة للحقل template ضمن المكوّن، وأضعها ضمن مكان منفصل لأنّها ستصبح بعد قليل كبيرة ومعقدة بعض الشيء لتُوضع في مكان كهذا. أجرِ التعديل التالي في الملف app.js ضمن الحقل template للمكوّن ليصبح على النحو التالي:

template: '#tasks-template'

لاحظ أنني قد عرضت مكان التعديل فقط طلبًا للاختصار. الجديد هنا أنّني وضعت معرّف القالب الجديد الذي سيحتوي على الشيفرة. انتقل الآن إلى الملف index.html وأضف الشيفرة التالية مباشرةً بعد عنصر div المُستهدَف الخاص بتطبيق vue.js:

<script type='text/x-template' id='tasks-template'>
        <div>
            <h3>{{ name }} - Tasks</h3>       
        </div>
 </script>

كما ترى أجريت بعض التعديل على شيفرة HTML التي كانت موجودة سابقًا. انتقل الآن إلى الصفحة index.html في المتصّح ثم حدثها (إن لم تُحدّث بشكل تلقائي)، يجب أن تحصل على شكل قريب من الشكل الذي حصلنا عليه في الفقرة السابقة.

الجديد هنا هو فصل القالب ووضعه ضمن مكان مخصّص له. في هذه الحالة سيكون ضمن العنصر script والذي تحمل السمة type له القيمة text/x-template كما هو واضح. بالإضافة لذلك لاحظ كيف جعلت قيمة المعرف id له نفس القيمة التي أسندتها للحقل template ضمن المكوّن قبل قليل.

من المهم جدًّا تحقيق مبدأ الفصل في بناء المكوّنات. لأنّه كلما أصبح المكوّن أكثر تعقيدًا كما سترى بعد قليل، كلما برزت الحاجة إلى تحقيق مبدأ الفصل بشكل أفضل.

لنُكسِب الآن مكوّننا الوليد بعض المزايا الإضافية لكي يصبح قادرًا على عرض بعض المهام للمستخدم. أجر التعديلات التالية ضمن الملف app.js ليصبح مشابهًا لما يلي:

Vue.component('tasks', {
    template: '#tasks-template',
    data() {
        return {
            name: 'Husam',
            tasks_list: [
                { title: "Write an introduction about vue.js components.", done: true },
                { title: "Drink a cup of team.", done: false },
                { title: "Call Jamil.", done: false },
                { title: "Buy new book.", done: true }
            ]
        }
    }
})

new Vue({
    el: '#app'
})

في الواقع، لقد أضفت حقلًا جديدًا أسميته tasks_list يحتوي على بيانات المهام التي أرغب بعرضها. لاحظ كيف أنّ كل مهمّة ضمن القائمة عبارة عن كائن بسيط، يحتوي على خاصيتين: تضم الأولى النص الخاص بالمهمة، أمّا الثانية فتضم قيمة منطقية تشير إلى أنّ المهمة قد نُفّذت true أم ليس بعد false.

انتقل الآن إلى الملف index.html وأجر بعض التعديلات التي ستكون أكبر هذه المرة، ليصبح مماثلًا لما يلي:

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>My Tasks</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>

    <style>
        .tasks-container {
            border-width: 1px;
            border-style: solid;
            display: inline-block;
    margin-right: 20px;
            padding: 8px;
        }

        .w3-table-all {
            border-collapse: collapse;
            border-spacing: 0;
            width: 100%;
            display: table;
            border: 1px solid #ccc
        }

        .w3-table-all tr {
            border-bottom: 1px solid #ddd
        }

        .w3-table-all tr:nth-child(odd) {
            background-color: #fff
        }

        .w3-table-all tr:nth-child(even) {
            background-color: #f1f1f1
        }

        .w3-table-all td,
        .w3-table-all th {
            padding: 8px 8px;
            display: table-cell;
            text-align: left;
            vertical-align: top
        }

        .w3-table-all th:first-child,
        .w3-table-all td:first-child {
            padding-left: 16px
        }

        .w3-table-all th{
            background-color: #d0d0d0;
        }
    </style>
</head>

<body>
    <h1>Welcome to MyTasks Application</h1>
    <p>This application is built to explain how to deal with components</p>

    <div id='app'>
        <tasks></tasks>
    </div>



    <script type='text/x-template' id='tasks-template'>
        <div class='tasks-container'>
            <table class='w3-table-all'>
                <colgroup>
                    <col style="width:15%">
                    <col style="width:85%">
                </colgroup>  
                <tbody>
                    <tr>
                        <th colspan="2">
                            <center>{{ name }} - Tasks</center>
                        </th>
                    </tr>
                    <tr>
                        <td>
                            <strong>Done</strong>
                        </td>
                        <td>
                            <strong>Title</strong>
                        </td>
                    </tr>

                    <tr v-for="task in tasks_list" v-bind:key="task.title">
                        <td>
                            {{ task.done }}
                        </td>
                        <td>
                            {{ task.title }}
                        </td>
                    </tr>
                </tbody>
            </table>      
        </div>
    </script>

    <script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
    <script src="app.js"></script>
</body>

</html>

حدّث الصفحة index.html ضمن متصفّح الانترنت لديك لتحصل على شكل شبيه بما يلي:

5.png

ربما تشعر أنّ الشيفرة قد أصبحت كبيرة ومعقّدة نسبيًا، إلّا أنّ الأمر في الحقيقة ليس كذلك. حدثت نسبة كبيرة من التعديلات عندما أضفت عنصر التنسيق style مع تنسيقاته إلى الملف index.html. كان من الأفضل وضع تنسيقات CSS ضمن ملف مستقل، وهذا ما سأعمل عليه بعد قليل. التنسيقات المستخدمة هنا استعرتها من موقع W3Schools الشهير. بالإضافة إلى ذلك، لاحظ أنّني قد استخدمت عنصر الجدول table لعرض قائمة المهام. عدا عن ذلك، أعتقد أنّ معظم الشيفرة البرمجيّة واضحة، باستثناء الموجّه الجديد: v-bind:key:

<li v-for="task in tasks_list" v-bind:key="task.title">

في الواقع لقد استخدمنا موجّه آخر مسبقًا، وهو v-bind:href وذلك في الدرس الثاني (استخدام vue.js للتعامل مع DOM). لكننا سنستخدم اليوم الكلمة key بدلًا من href. لاستخدام v-bind:key مزيّة مهمّة تتمثّل في الأداء (Performance)، وخصوصًا عندما يكون حجم البيانات كبيرًا. نستخدم هذا الموجّه لتعيين مفتاح ربط key للموجّه التكراري for.

من الواضح أنّه في الوضع الحالي، من غير الممكن لنا أن نعدّل على أي مهمة بحيث تصبح منفّذة أو غير منفّذة. سنعمل في الفقرة التالية على تحسين تجربة الاستخدام، من خلال توفير إمكانية إجراء هذه التعديلات.

تحسين تجربة الاستخدام للمكوّن

سنعمل الآن على السماح للمستخدم بتعديل حالة المهمة وذلك بإضافة عنصر اختيار Checkbox. قبل ذلك دعنا ننقل تنسيقات CSS إلى ملف منفصل. أنشئ ملف جديد ضمن نافذة المستكشف في Visual Studio Code لهذا الغرض ولنسمه tasks.css.

انقل محتويات العنصر style في الملف index.html إلى ملفنا الجديد، ثم احذف العنصر style. لاستخدام التنسيقات ضمن الملف الجديد، أضف مرجعًا إليه في الملف index.html ضمن القسم head على النحو التالي:

<link rel="stylesheet" href="tasks.css">

سنجري الآن تغييرًا ضمن الشيفرة البرمجية للقالب فقط، وتحديدًا بالقسم الخاص بإنهاء أو عدم إنهاء المهمة أي في القسم Done فقط. استبدل بالشيفرة التالي:

...
<td>
       {{ task.done }}
</td>
...

الشيفرة الجديدة التالية:

...
<td>
       <input type="checkbox" v-model="task.done"/>
</td>
...

أعد تحديث الصفحة لتحصل على شكل شبيه بما يلي:

6.png

لاحظ أنّني قد استخدمت الربط ثنائي الاتجاه v-model="task.done"‎ للربط الثنائي للبيانات.

ملاحظة: الاختصارات في vue.js يمكن دومًا استبدال الرمز @ بالموجّه v-on. أي أنّ v-on:click مثلًا سيصبح: ‎@:click. وبنفس الأسلوب، يمكننا حذف الموجّه v-bind بالكامل، وسيفهم vue.js أنّ هذا الموجّه موجود. فمثلًا يمكن كتابة ‎:href فقط بدلًا من v-bind:href، وكتابة ‎:key بدلًا من v-bind:key.

تمرير وسائط إلى المكوّنات

لعلك قد لاحظت أنّنا استخدمنا بيانات ثابتة في التعامل مع مكوّن المهام. ولكن في الواقع العملي سنحتاج إلى أن تكون هذه البيانات قابلة للتغيير كما هو واضح, لهذا الهدف توفّر المكوّنات في vue.js ميزة الخصائص props، حيث يمكن وضع قسم جديد اسمه props ضمن الوسيط الممرّر إلى المكوّن عند إنشاءه لهذه الغاية. في الحقيقة للخصائص الموجودة ضمن القسم props فوائد مهمة عندما سنتحدث عن المكونات المتداخلة لاحقًا في الدرس التالي، حيث سنستخدمها لتمرير البيانات من المكون الأساسي إلى المكون الفرعي.

لنبدأ بإجراء التعديلات اللازمة. أجر التعديلات التالية في الملف app.js ليصبح على الشكل التالي:

 Vue.component('tasks', {
    template: '#tasks-template',
    props: {
        name: String,
        tasks_list: Array
    }
})

new Vue({
    el: '#app'
})

لقد أزلت قسم data وأضفت بدلًا منه القسم props (يمكن بالطبع أن يكونا معًا بنفس الوقت). عرفت الوسائط التي يمكن أن أمرّرها للمكوّن ضمن القسم props بالشكل التالي:

props: {
        name: String,
        tasks_list: Array
    }

الوسيط الأول هو name وهو من النوع String أي نص، والوسيط الثاني هو tasks_list وهو من نوع Array أي مصفوفة كما هو واضح. بالنسبة لطريقة الاستخدام فهي سهلة جدا. أجر التعديل التالي على الوسم tasks ضمن الملف index.html:

<tasks name='Husam' v-bind:tasks_list='[{ title: "Write an introduction about vue.js components.", done: true },
        { title: "Drink a cup of team.", done: false },
        { title: "Call Jamil.", done: false },
        { title: "Buy new book.", done: true }]'></tasks>

مرّرت البيانات إلى المكوّن كما لو أنّها وسوم عادية. الشيء الوحيد الملفت للنظر هو أنّني قد استخدمت الموجه v-bind:‎ عند تمرير المصفوفة tasks_list وهذا الأمر إلزامي عند تمرير وسائط ديناميكية إلى المكوّنات، في حين أنّه لا يجب استخدام هذا الموجه عند تمرير وسائط نصية ساكنة كما فعلنا عند تمرير الوسيط name.

ملاحظة: يوجد العديد من أنواع الوسائط التي يمكن تمريرها إلى المكونات وهي:

String, Number, Boolean, Array, Object, Function, Promise

إنشاء أكثر من نسخة من المكون ضمن نفس الصفحة

لنعمل الآن على استخدام أكثر من مكون واحد ضمن الصفحة لنكتشف قوة المكونات. انسخ شيفرة HTML الأخيرة والصقها مرة آخرى مع إجراء بعض التعديلات البسيطة عليها:

<tasks name='My house' v-bind:tasks_list='[{ title: "Do a cleaning for windows.", done: false},
        { title: "Bring some vegetables and fruits.", done: true},
        { title: "Wash clothes", done: false}]'></tasks>

حدث الصفحة index.html من جديد لتحصل على شكل شبيه بما يلي:

7.png

يمكننا بسهولة أن نستخدم هذا المكون في المكان الذي نحتاج إليه في الصفحة، كما يمكن مشاركته مع الآخرين. مازال هناك الكثير للتحدث عنه حول المكوّنات، سنتناول في الدروس اللاحقة العديد من المزايا الخاصة بها، والطرق المثالية للتعامل معها. يمكنك الحصول على الشيفرات الكاملة بالملفات الثلاثة التي عملنا عليها في هذا الدرس في المقاطع الثلاثة التالية:

الملف index.html:

<!DOCTYPE html>
<html>

<head>
    <meta charset='utf-8'>
    <meta http-equiv='X-UA-Compatible' content='IE=edge'>
    <title>My Tasks</title>
    <meta name='viewport' content='width=device-width, initial-scale=1'>
    <link rel="stylesheet" href="tasks.css">
</head>

<body>
    <h1>Welcome to MyTasks Application</h1>
    <p>This application is built to explain how to deal with components</p>

    <div id='app'>
        <tasks name='Husam' v-bind:tasks_list='[{ title: "Write an introduction about vue.js components.", done: true },
        { title: "Drink a cup of tea.", done: false },
        { title: "Call Jamil.", done: false },
        { title: "Buy a new book.", done: true }]'></tasks>

        <tasks name='My house' v-bind:tasks_list='[{ title: "Clean windows.", done: false},
        { title: "Bring some vegetables and fruits.", done: true},
        { title: "Wash clothes", done: false}]'></tasks>
    </div>



    <script type='text/x-template' id='tasks-template'>
        <div class='tasks-container'>
            <table class='w3-table-all'>
                <colgroup>
                    <col style="width:15%">
                    <col style="width:85%">
                </colgroup>  
                <tbody>
                    <tr>
                        <th colspan="2">
                            <center>{{ name }} - Tasks</center>
                        </th>
                    </tr>
                    <tr>
                        <td>
                            <strong>Done</strong>
                        </td>
                        <td>
                            <strong>Title</strong>
                        </td>
                    </tr>

                    <tr v-for="task in tasks_list" v-bind:key="task.title">
                        <td>
                            <input type="checkbox" v-model="task.done"/>
                        </td>
                        <td>
                            {{ task.title }}
                        </td>
                    </tr>
                </tbody>
            </table>      
        </div>
    </script>

    <script src="https://unpkg.com/vue@2.6.11/dist/vue.js"></script>
    <script src="app.js"></script>
</body>

</html>

الملف tasks.css:

.tasks-container {
    border-width: 1px;
    border-style: solid;
    display: inline-block;
    margin-right: 20px;
    padding: 8px;
}

.w3-table-all {
    border-collapse: collapse;
    border-spacing: 0;
    width: 100%;
    display: table;
    border: 1px solid #ccc
}

.w3-table-all tr {
    border-bottom: 1px solid #ddd
}

.w3-table-all tr:nth-child(odd) {
    background-color: #fff
}

.w3-table-all tr:nth-child(even) {
    background-color: #f1f1f1
}

.w3-table-all td,
.w3-table-all th {
    padding: 8px 8px;
    display: table-cell;
    text-align: left;
    vertical-align: top
}

.w3-table-all th:first-child,
.w3-table-all td:first-child {
    padding-left: 16px
}

.w3-table-all th{
    background-color: #d0d0d0;
}

الملف app.js:

Vue.component('tasks', {
    template: '#tasks-template',
    props: {
        name: String,
        tasks_list: Array
    }
})

new Vue({
    el: '#app'
})

إضافة ميزة الترشيح لمكوّن المهام

كثيرًا ما ستحتاج في التطبيقات التي ستكتبها إلى ميزة الترشيح بصرف النظر عن نوع التطبيق الذي تبنيه. سنتناول في هذه الفقرة كيفية إضافة هذه الميزة إلى مكوّن المهام.

رغم أنّ هذه الميزة بسيطة، وتنحصر وظيفتها في إخفاء (أو إظهار) المهام المنجزة، إلّا أنّها ستعطيك فكرة جيدة عن كيفية عمل مثل هذه المزايا.

سنكمل على الشيفرة الأخيرة لتطبيق المهام. ستكون ميزة التصفية على شكل صندوق اختيار Checkbox موجود أعلى قائمة المهام. عندما يختاره المستخدم فإنّ المهام المنجزة ستختفي، والعكس صحيح.

سنبدأ بإضافة عنصر الاختيار هذا إلى الملف index.html ضمن القسم الخاص بقالب المكوّن. أضف الشيفرة التالية بعد الوسم <div class='tasks-container'‎> مباشرة:

 <input id="hide_cmp_tasks" type="checkbox" v-model="hide_completed_tasks"/>
  <label for="hide_cmp_tasks">Hide completed tasks</label>

لاحظ معي أنّ هذا العنصر مرتبط بحقل اسمه hide_competed_tasks سنعرفه بعد قليل ضمن مكوّن المهام.

افتح الآن الملف app.js وأضف القسمين data و computed للمكوّن tasks. سيحتوي قسم data على تعريف الحقل hide_competed_tasks المرتبط بعنصر صندوق الاختيار الذي أضفناه قبل قليل، وسيكون من النوع المنطقي Boolean، في حين أنّ القسم computed فسيحتوي على الخاصية المحسوبة filtered_tasks. سيصبح المكوّن tasks على الشكل التالي:

Vue.component('tasks', {
    template: '#tasks-template',
    props: {
        name: String,
        tasks_list: Array,
    },
    data() {
        return {
            hide_completed_tasks: false
        }
    },
    computed: {
        filtered_tasks() {
            return this.hide_completed_tasks ? this.tasks_list.filter(t => !t.done) : this.tasks_list;
        }
    }
})

إذا تأملت معي محتويات الخاصية المحسوبة filtered_tasks فستجدها عبارة عن شيفرة برمجية بسيطة لتصفية المهام المنجزة من خلال اختبار قيمة الخاصية done. أي أنّ عملية التصفية ستحدث في هذا المكان تحديدًا بناءً على كون الحقل hide_completed_tasks يحمل القيمة true أو false.

هذا كلّ شيء! إذا أحببت الآن، انقر بزر الفأرة الأيمن على الملف index.html الموجود ضمن نافذة المستكشف Explorer، واختر الأمر Open with Live Server كما اعتدنا من قبل. ستحصل على شكل شبيه بما يلي:

8.png

جرب الآن أن تنقر بشكل متكرّر على صندوق الاختيار Hide completed tasks لتجد كيف أنّ المهام المنجزة تختفي وتظهر وفقًا لذلك.

إضافة ميزة مهمة جديدة لمكوّن المهام

لنحسن مكوّن المهام بميزة إضافة مهمة جديدة للمهام الموجودة مسبقًا. سأضع أسفل قائمة المهام عنصر إدخال نصي مع زر للإضافة. و سأضيف أيضًا بعض اللمسات باستخدام CSS لكي أحصل على مظهر مقبول لهما.

افتح الملف tasks.css وأضف أصناف CSS التالية له:

.add-task-container {
    position: relative;
    margin-top: 10px;
}

.add-task-container div{
    position: absolute;
    top: 0;
    right: 60px;
    left: 45px;
}

.add-task-container div input{
   width: 100%;
}

.add-task-container input{
    position: absolute;
    width:50px;
    top: 0;
    right: 0;
}

انتقل الآن إلى الملف index.html وأضف الشيفرة التالية بعد نهاية وسم الإغلاق للجدول مباشرةً (ضمن القالب الخاص بمكوّن المهام):

 <div class="add-task-container">
    <span>Task: </span>
    <div>
        <input type="text" v-model="new_task_text"/>
    </div>
    <input type="button" value="Add" v-on:click="add_new_task"/>
</div>

حان الآن دور الشيفرة البرمجية ضمن الملف app.js. افتح هذا الملف، واحرص على أن تكون محتوياته مطابقة لما يلي:

Vue.component('tasks', {
    template: '#tasks-template',
    props: {
        name: String,
        tasks_list: Array,
    },
    data() {
        return {
            hide_completed_tasks: false,
            new_task_text : ""
        }
    },
    computed: {
        filtered_tasks() {
            return this.hide_completed_tasks ? this.tasks_list.filter(t => !t.done) : this.tasks_list;
        }
    },
    methods: {
        add_new_task(event) {
            this.tasks_list.push({ title: this.new_task_text, done: false });
            this.new_task_text = "";
        }
    }
})

new Vue({
    el: '#app'
})

الجديد هنا هو أنّني أضفت حقلًا جديدًا إلى القسم data وأسميته new_task_text سيرتبط بمربع النص الذي سندخل من خلاله عنوان المهمة. كما قد أضفت القسم methods وعرفت ضمنه التابع الجديد add_new_task، وهذا التابع الذي سيُستدعى عند نقر زر إضافة المهمة.

الشيفرة البرمجية الموجودة في هذا التابع بسيطة، فهي تعمل على إضافة المهمة الجديدة إلى مصفوفة المهام tasks_list ثم تفرّغ عنوان المهمة من جديد لاستقبال المهمة التالية.

جرب كتابة المهمة التالية: My new task! ‎ ضمن مربع النص، ثم انقر الزر Add. ستحصل على شكل شبيه بما يلي:

9.png

ختامًا

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

تمارين داعمة

تمرين 1

أنشئ مكوّنًا سمّه vu-countdowntimer وظيفته العد التنازلي بمقدار ثانية واحدة كل مرّة، ابتداءً من قيمة محددة يمكن تمريرها للمكون، وحتى الصفر.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...