لدينا الآن عينة من البيانات وحلقة تأخذ كل جزء من هذه البيانات وتصيّره أو تعرضه Render ضمن المكوِّن ToDoItem
في تطبيقنا، كما نريد السماح لمستخدِمينا بإدخال عناصر مهامهم في التطبيق، لذلك سنحتاج إلى نص إدخال <input>
وحدث يُطلَق عند إرسال البيانات وتابع لإطلاق الإرسال بهدف إضافة البيانات وتصيير القائمة ونموذج للتحكم في البيانات، وهذا هو موضوعنا في هذا المقال.
- المتطلبات الأساسية: الإلمام بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة استخدام سطر الأوامر أو الطرفية، إذ تُكتَب مكوّنات Vue بوصفها مجموعةً من كائنات جافاسكربت التي تدير بيانات التطبيق وصيغة القوالب المستنِدة إلى لغة HTML المرتبطة مع بنية DOM الأساسية، وستحتاج إلى طرفية مثبَّت عليها node و npm لتثبيت Vue ولاستخدام بعض ميزاته الأكثر تقدمًا مثل مكوّنات الملف المفرد Single File Components أو دوال التصيير Render.
- الهدف: تعلّم كيفية التعامل مع الاستمارات Forms في Vue والأحداث Events والنماذج Models والتوابع Methods المرتبطة بها.
إنشاء استمارة مهام جديدة
لدينا الآن تطبيق يعرض قائمةً بعناصر المهام، ولكن لا يمكننا تعديل قائمة العناصر دون تغيير شيفرتنا البرمجية يدويًا، إذًا لنصلح ذلك ولْننشئ مكوِّنًا جديدًا يسمح لنا بإضافة عنصر مهام جديد.
أنشئ ملفًا جديدًا يسمى ToDoForm.vue
في مجلد المكوّنات، ثم أضِف عنصر <template>
فارغًا ووسم <script>
كما يلي:
<template></template> <script> export default {}; </script>
أضِف استمارة HTML الذي يتيح إدخال عنصر مهام جديد وإرساله إلى التطبيق، كما نحتاج إلى العنصر <form>
مع العناصر <label>
و<input>
و<button>
، لذا عدِّل قالبك ليبدو كما يلي:
<template> <form> <label for="new-todo-input"> What needs to be done? </label> <input type="text" id="new-todo-input" name="new-todo" autocomplete="off" /> <button type="submit"> Add </button> </form> </template>
لدينا الآن مكوِّن استمارة يمكننا من خلاله إدخال عنوان عنصر مهام جديد والذي سيصبح عنوانًا أو تسمية label
للمكوِّن ToDoItem
المقابل عند تصييره لاحقًا، ولنحمِّل هذا المكوِّن في تطبيقنا، لذا ارجع إلى الملف App.vue وأضف تعليمة الاستيراد import
التالية بعد تعليمة الاستيراد السابقة مباشرةً ضمن العنصر <script>
:
import ToDoForm from './components/ToDoForm';
يجب تسجيل المكوِّن الجديد في المكون App
من خلال تعديل الخاصية components
الخاصة بكائن المكوِّن بحيث تبدو كما يلي:
components: { ToDoItem, ToDoForm }
صيّر المكوِّن ToDoForm
ضمن تطبيقك من خلال إضافة العنصر <to-do-form />
إلى العنصر <template>
ضمن المكوِّن App
كما يلي:
<template> <div id="app"> <h1>My To-Do List</h1> <to-do-form></to-do-form> <ul> <li v-for="item in ToDoItems" :key="item.id"> <to-do-item :label="item.label" :done="item.done" :id="item.id"></to-do-item> </li> </ul> </div> </template>
إذا شغّلت موقعك الآن، فيجب أن ترى الاستمارة الجديدة كما يلي:
إذا ملأت الاستمارة ونقرت على زر "الإضافة Add"، فستسرسل الصفحة الاستمارة مرةً أخرى إلى الخادم، ولكننا لا نريد ذلك، وإنما نريد تشغيل تابع على الحدث submit
الذي سيضيف المهام الجديدة إلى قائمة بيانات ToDoItem
المُعرَّفة ضمن المكوِّن App
، لذلك يجب إضافة تابع إلى نسخة المكوِّن.
إنشاء تابع وربطه بحدث باستخدام الموجه v-on
يمكن إتاحة تابع للمكوِّن ToDoForm
من خلال إضافته إلى كائن المكوِّن ضمن الخاصية methods
التي تشبه الخاصيات data()
و props
وما إلى ذلك، إذ تحتوي الخاصية methods
على أيّ تابع قد نحتاجه لاستدعاء مكوننا. كما تُشغَّل جميع التوابع عند استدعاء هذه الخاصية، لذلك لا يُعَدّ استخدامها لعرض المعلومات ضمن القالب أمرًا جيدًا، وبالتالي يجب استخدام الخاصية computed
-التي سنتحدث عنها لاحقًا- لعرض البيانات الناتجة عن العمليات الحسابية.
يجب إضافة التابع onSubmit()
إلى الخاصية methods
ضمن كائن المكوِّن ToDoForm
، إذ سنستخدِم هذا التابع للتعامل مع إجراء الإرسال، لذا أضف هذا التابع كما يلي:
export default { methods: { onSubmit() { console.log('form submitted') } } }
يجب بعد ذلك ربط التابع بمعالج حدث الإرسال submit
للعنصر <form>
، ويشبه ذلك إلى حد كبير كيفية استخدام إطار العمل Vue لصيغة v-bind بهدف ربط السمات، إذ يمتلك Vue موجِّهًا خاصًا لمعالجة الأحداث وهو v-on
الذي يعمل باستخدام الصيغة v-on:event="method"
، كما توجد صيغة مختصرة هي @event="method"
، إذ سنستخدِم الصيغة المختصرة في هذا المقال، وبالتالي أضف معالج حدث الإرسال submit
إلى العنصر <form>
كما يلي:
<form @submit="onSubmit">
إذا شغّلنا معالج حدث الإرسال، فلا يزال التطبيق يرسل البيانات إلى الخادم مما يتسبب في تحديث الصفحة، وبما أننا نطبّق كل عمليات المعالجة على العميل، فلا يوجد خادم ليتعامل مع إعادة الإرسال وسنفقد جميع الحالات المحلية عند تحديث الصفحة، إذ يمكن منع المتصفح من الإرسال إلى الخادم من خلال إيقاف إجراء الحدث الافتراضي أثناء انتشاره للأعلى Bubbling Up في الصفحة باستخدام التابع Event.preventDefault()
في لغة جافاسكربت الصرفة Vanilla JavaScript مثلًا. كما يحتوي إطار عمل Vue على صيغة خاصة تُسمَّى معدِّلات الأحداث Event Modifiers التي يمكنها معالجة هذا الأمر مباشرةً في قالبنا، في حين تُضاف المُعدِّلات إلى نهاية الحدث مع نقطة بالصورة @event.modifier
، ونوضِّح فيما يلي قائمةً بمعدِّلات الأحداث:
.stop
: يوقِف انتشار الحدث ويكافئ التابعEvent.stopPropagation()
في أحداث جافاسكربت العادية..prevent
: يمنع سلوك الحدث الافتراضي ويكافئ التابعEvent.preventDefault()
..self
: يؤدي إلى تشغيل المعالج فقط إذا أُرسِل الحدث من هذا العنصر المُحدَّد.{.key}
: يؤدي إلى تشغيل معالج الأحداث باستخدام مفتاح محدَّد فقط، ويحتوي موقع MDN على قائمة بقيم المفاتيح الصالحة، ولكن يجب تحويل المفاتيح متعددة الكلمات إلى حالة الأحرف التي تسمى نمط أسياخ الشواء Kebab Case مثلpage-down
..native
: يستمع إلى الحدث الأصيل Native في عنصر الجذر أو الغلاف الخارجي Outer-most Wrapping لمكوِّنك..once
: يستمع إلى الحدث حتى تشغيله لمرة واحدة فقط لا أكثر..left
: يشغِّل المعالج باستخدام حدث زر الفأرة الأيسر فقط..right
: يشغِّل المعالج باستخدام حدث زر الفأرة الأيمن فقط..middle
: يشغِّل المعالج باستخدام حدث زر الفأرة الأوسط فقط..passive
: يكافئ استخدام المعامِل{ passive: true }
عند إنشاء مستمع حدث في لغة جافاسكربت الصرفة Vanilla JavaScript باستخدام التابعaddEventListener()
.
سنستخدِم في حالتنا المعالِج .prevent
لإيقاف إجراء الإرسال الافتراضي للمتصفح، لذا أضِف .prevent
إلى معالج الإرسال @submit
في قالبك كما يلي:
<form @submit.prevent="onSubmit">
إذا حاولت إرسال الاستمارة الآن، فستلاحظ عدم إعادة تحميل الصفحة، وإذا فتحت الطرفية، فيمكنك رؤية نتائج التابع console.log()
التي أضفناها ضمن التابع onSubmit()
.
ربط البيانات مع الدخل باستخدام الموجه v-model
نحتاج الآن إلى طريقة للحصول على القيمة الموجودة في حقل الإدخال <input>
من الاستمارة لنتمكّن من إضافة عنصر المهام الجديد إلى قائمة بيانات ToDoItems
، إذ يكون أول شيء نحتاجه هو الخاصية data
في استمارتنا لتعقّب قيمة المهمة.
أضِف التابع data()
إلى كائن مكون ToDoForm
الذي يعيد الحقل label
، إذ يمكننا ضبط قيمة الحقل label
الأولية بوصفها سلسلة نصية فارغة، ويجب أن يبدو كائن المكوِّن الآن كما يلي:
export default { methods: { onSubmit() { console.log("form submitted"); } }, data() { return { label: "" }; } };
نحتاج الآن إلى طريقة ما لربط قيمة حقل الإدخال <input>
ذي المعرِّف new-todo-input
بالحقل label
، إذ يمتلك إطار العمل Vue موجِّهًا خاصًا لذلك وهو v-model
الذي يرتبط مع خاصية البيانات التي ضبطتها عليه ويبقيها متزامنةً مع حقل الإدخال <input>
، في حين يعمل الموجّه v-model
مع جميع أنواع حقول الإدخال المختلفة بما في ذلك مربعات الاختيار Checkboxes وأزرار الانتقاء Radios وحقول الاختيار Select Inputs، كما يُستخدَم هذا الموجِّه من خلال إضافة سمة بالصورة v-model="variable"
إلى العنصر <input>
كما يلي:
<input type="text" id="new-todo-input" name="new-todo" autocomplete="off" v-model="label" />
ملاحظة: يمكنك مزامنة البيانات مع قيم العنصر <input>
باستخدام تركيبة من الأحداث مع سمات v-bind
وهذا ما يفعله الموجّه v-model
، كما تختلف تركيبة الأحداث والسمات وفقًا لنوع حقل الإدخال وستتطلب شيفرةً برمجيةً أكبر من مجرد استخدام صيغة v-model
المختصرة.
لنختبر استخدام الموجِّه v-model
عن طريق تسجيل قيمة البيانات المقدَّمة في التابع onSubmit()
، إذ يمكن الوصول إلى سمات البيانات في المكوّنات باستخدام الكلمة this
، وبالتالي يمكن الوصول إلى الحقل label
بالصورة this.label
، لذا عدّل التابع onSubmit()
ليبدو كما يلي:
methods: { onSubmit() { console.log('Label value: ', this.label); } },
عد الآن إلى تطبيقك المُشغَّل، وأضِف نصًا في الحقل <input>
ثم انقر على زر "الإضافة Add"، إذ يجب أن ترى القيمة التي أدخلتها مسجلةً في الطرفية كما يلي على سبيل المثال:
Label value: My value
تغيير سلوك الموجه v-model باستخدام المعدلات
يمكننا إضافة معدِّلات Modifiers لتغيير سلوك الموجِّه v-model
بطريقة مماثلة لمعدِّلات الأحداث، ومن أبزر هذه المعدِّلات:
.trim
: يزيل المسافة الفارغة الموجودة قبل نص الإدخال أو بعده، ويمكننا إضافة هذا المُعدِّل إلى تعليمةv-model
بالصورةv-model.trim="label"
.lazy
: يتغير هذا المعدِّل عندما يتزامنv-model
مع قيمة نص حقل الإدخال، كما يمكن مزامنة الموجِّهv-model
عن طريق تحديث المتغير الذي يستخدم الأحداث، بينما تحدُث هذه المزامنة مع نص حقل الإدخال باستخدام الحدثinput
، ويعني ذلك أنّ إطار عمل Vue يزامن البيانات بعد كل ضغطة مفتاح، في حين يتسبب المعدِّل.lazy
في أن يستخدِم الموجّهv-model
الحدثchange
بدلًا من ذلك، وهذا يعني أنّ Vue لن يزامن البيانات إلّا عندما يفقد حقل الإدخال التركيز أو عند إرسال الاستمارة، وهذا منطقي أكثر لأننا نحتاج إلى البيانات النهائية فقط.
ملاحظة: يمكن استخدام المعدِّلَين .trim
و.lazy
مع بعضهما البعض من خلال استخدامهما بالشكل v-model.lazy.trim="label"
.
عدّل السمة v-model
إلى سلسلة lazy
و trim
كما هو موضَّح أعلاه، ثم اختبر تطبيقك مرةً أخرى، وجرّب إرسال قيمة بمسافة فارغة في كل نهاية مثلًا.
تمرير البيانات إلى العناصر الآباء مع الأحداث المخصصة
يجب الآن تمرير عنصر المهام الذي أنشأناه إلى المكوِّن App
من خلال جعل المكوِّن ToDoForm
يصدر حدثًا مخصَّصًا يمرِّر البيانات، وجعل المكون App
يستمع إلى هذا الحدث، وتعمل هذه الطريقة بصورة مشابهة جدًا للأحداث الأصيلة مع عناصر HTML، إذ يمكن للمكوِّن الابن إصدار حدث يمكن الاستماع إليه باستخدام الموجِّه v-on
.
لنضِف الحدث todo-added
إلى الحدث onSubmit
الخاص بالمكوِّن ToDoForm
، كما يمكن إصدار الأحداث المخصَّصة بالصورة this.$emit("event-name")
، ويجدر بالذكر أنّ معالجات الأحداث حساسة لحالة الأحرف ولا يمكن أن تتضمن مسافات، وتُحوَّل قوالب Vue إلى أحرف صغيرة، مما يعني أنها لا تستطيع الاستماع إلى الأحداث المُسمَّاة بأحرف كبيرة.
ضَع ما يلي بدلًا من التابع console.log()
الموجود في التابع onSubmit()
:
this.$emit("todo-added");
ارجع بعد ذلك إلى المكوِّن App.vue
وأضِف الخاصية methods
إلى كائن المكوِّن الذي يحتوي على التابع addToDo()
كما هو موضّح أدناه، إذ يمكن لهذا التابع فقط إظهار العبارة To-do added
على الطرفية حاليًا.
export default { name: 'app', components: { ToDoItem, ToDoForm }, data() { return { ToDoItems: [ { id:uniqueId('todo-'), label: 'Learn Vue', done: false }, { id:uniqueId('todo-'), label: 'Create a Vue project with the CLI', done: true }, { id:uniqueId('todo-'), label: 'Have fun', done: true }, { id:uniqueId('todo-'), label: 'Create a to-do list', done: false } ] }; }, methods: { addToDo() { console.log('To-do added'); } } };
أضِف بعد ذلك مستمع حدث إلى الحدث todo-added
في العنصر <to-do-form></to-do-form>
، إذ يستدعي هذا المستمع التابع addToDo()
عند إطلاق الحدث، وسيبدو المستمع بالصورة @todo-added="addToDo"
باستخدام الاختصار @
:
<to-do-form @todo-added="addToDo"></to-do-form>
يجب أن ترى سجل الطرفية من التابع addToDo()
عند إرسال المكوِّن ToDoForm
، ويُعَدّ ذلك أمرًا جيدًا، لكننا ما زلنا لا نعيد أيّ بيانات إلى المكوِّن App.vue
، ويمكن ذلك عن طريق إعادة وسائط إضافية إلى الدالة this.$emit()
في المكوِّن ToDoForm
، إذ نريد في حالتنا تمرير بيانات العنصر label
مع الحدث عند إطلاقه من خلال تضمين البيانات التي نريد تمريرها بوصفها معاملًا آخرًا في التابع $emit()
بالصورة this.$emit("todo-added", this.label)
، وهذا مشابه لكيفية تضمين أحداث جافاسكربت الأصيلة للبيانات باستثناء أنّ أحداث Vue المخصَّصة التي لا تتضمن أيّ كائن حدث افتراضيًا، وبالتالي سيتطابق الحدث المنطلق مع أيّ كائن ترسله مباشرةً، كما سيكون كائن الحدث في حالتنا سلسلةً نصيةً فقط، لذا عدِّل التابع onSubmit()
كما يلي:
onSubmit() { this.$emit('todo-added', this.label) }
يمكن التقاط هذه البيانات ضمن المكوِّن App.vue
من خلال إضافة معامِل إلى التابع addToDo()
الذي يتضمن عنصر label
خاص بعنصر المهام الجديد، لذا ارجع إلى المكوِّن App.vue
وعدّله ليبدو كما يلي:
methods: { addToDo(toDoLabel) { console.log('To-do added:', toDoLabel); } }
إذا اختبرت استمارتك مرةً أخرى، فسترى أنّ أيّ نص تدخله مسجَّل في الطرفية عند الإرسال، كما يمرِّر Vue تلقائيًا الوسائط بعد أن يكون اسم الحدث في this.$emit()
هو معالِج الأحداث خاصتك.
إضافة المهام الجديدة إلى بياناتنا
يجب الآن إضافة عنصر يمثِّل بيانات المكوِّن ToDoForm
التي أصبحت متوفرةً في المكوِّن App.vue
في المصفوفة ToDoItems
، ويمكن ذلك عن طريق دفع كائن عنصر مهام جديد إلى المصفوفة التي تحتوي على البيانات الجديدة.
عدِّل التابع addToDo()
كما يلي:
addToDo(toDoLabel) { this.ToDoItems.push({id:uniqueId('todo-'), label: toDoLabel, done: false}); }
اختبر الاستمارة مرةً أخرى، إذ يُفترَض أن ترى عناصر مهام جديدة تُلحَق بنهاية القائمة، وإذا أرسلتَ الاستمارة وحقل الإدخال فارغ، فستُضاف عناصر المهام التي لا تحتوي على نص إلى القائمة، ويمكن إصلاح ذلك من خلال منع تشغيل الحدث todo-added
عندما يكون الاسم فارغًا، وبما أنّ الاسم قد أزيل باستخدام الموجِّه .trim
، فيجب اختبار السلسلة النصية الفارغة فقط، لذا ارجع إلى المكوِّن ToDoForm
وعدِّل التابع onSubmit()
كما يلي، وإذا كانت قيمة الحقل label
فارغةً، فيجب عدم إصدار الحدث todo-added
.
onSubmit() { if(this.label === "") { return; } this.$emit('todo-added', this.label); }
جرّب استمارتك مرةً أخرى، إذ لن تتمكّن الآن من إضافة عناصر فارغة إلى قائمة المهام.
استخدام الموجه v-model لتحديث قيمة حقل الإدخال
لا يزال العنصر <input>
يحتوي على القيمة القديمة بعد الإرسال، ويمكن إصلاح ذلك لأننا نستخدم الموجّه v-model
لربط البيانات بالعنصر <input>
في المكوِّن ToDoForm
، فإذا ضبطنا معامِل الاسم name
ليكون سلسلة نصية فارغة، فسيُحدَّث حقل الإدخال.
عدِّل التابع onSubmit()
الخاص بالمكوِّن ToDoForm
كما يلي:
onSubmit() { if(this.label === "") { return; } this.$emit('todo-added', this.label); this.label = ""; }
إذا نقرتَ الآن على زر "الإضافة Add"، فسيمسح حقل إدخال المهمة الجديدة "new-todo-input" نفسه.
الخلاصة
يمكننا الآن إضافة عناصر المهام إلى استمارتنا، وبالتالي بدأ تطبيقنا الآن يصبح تفاعليًا، ولكننا تجاهلنا شكله وتنسيقه تمامًا، وسنركز في المقال التالي على إصلاح ذلك، كما سنتعرف على الطرق المختلفة التي يوفرها إطار العمل Vue لمكوّنات التنسيق.
ترجمة -وبتصرّف- للمقال Adding a new todo form: Vue events, methods, and models.
تعليقات
إرسال تعليق