Vue.js للمبتدئين ، الدرس 10: النماذج

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







درس المبتدئين Vue.js 1: المثال Vue

Vue.js للمبتدئين ، الدرس 2: سمات الربط

Vue.js الدرس 3: العرض الشرطي

Vue.js للمبتدئين الدرس 4: عرض القوائم

Vue .js للمبتدئين الدرس 5: معالجة الأحداث

Vue.js للمبتدئين الدرس 6: فئات وأنماط الربط

Vue.js للمبتدئين الدرس 7: الخصائص المحسوبة

Vue.js للمبتدئين الدرس 8: المكونات

Vue. js للمبتدئين الدرس 9: أحداث مخصصة



الغرض من الدرس



سنقوم بإنشاء نموذج يسمح لزوار الموقع بإرسال مراجعات المنتج. في الوقت نفسه ، من الضروري إرسال المراجعة فقط إذا تم ملء جميع حقول النموذج ، والتي يجب ملؤها.



الكود الأولي



إليك ما يوجد الآن index.html:



<div id="app">
  <div class="cart">
    <p>Cart({{ cart.length }})</p>
  </div>

  <product :premium="premium" @add-to-cart="updateCart"></product>
</div>


يبدو مثل هذا main.js:



Vue.component('product', {
  props: {
    premium: {
      type: Boolean,
      required: true
    }
  },
  template: `
  <div class="product">
    <div class="product-image">
      <img :src="image" />
    </div>

    <div class="product-info">
      <h1>{{ title }}</h1>
      <p v-if="inStock">In stock</p>
      <p v-else>Out of Stock</p>
      <p>Shipping: {{ shipping }}</p>

      <ul>
        <li v-for="detail in details">{{ detail }}</li>
      </ul>
      <div
        class="color-box"
        v-for="(variant, index) in variants"
        :key="variant.variantId"
        :style="{ backgroundColor: variant.variantColor }"
        @mouseover="updateProduct(index)"
      ></div>

      <button
        v-on:click="addToCart"
        :disabled="!inStock"
        :class="{ disabledButton: !inStock }"
      >
        Add to cart
      </button>

    </div>
  </div>
  `,
  data() {
    return {
      product: 'Socks',
      brand: 'Vue Mastery',
      selectedVariant: 0,
      details: ['80% cotton', '20% polyester', 'Gender-neutral'],
      variants: [
        {
          variantId: 2234,
          variantColor: 'green',
          variantImage: './assets/vmSocks-green.jpg',
          variantQuantity: 10
        },
        {
          variantId: 2235,
          variantColor: 'blue',
          variantImage: './assets/vmSocks-blue.jpg',
          variantQuantity: 0
        }
      ]
    }
  },
    methods: {
      addToCart() {
        this.$emit('add-to-cart', this.variants[this.selectedVariant].variantId);
      },
      updateProduct(index) {
        this.selectedVariant = index;
        console.log(index);
      }
    },
    computed: {
      title() {
        return this.brand + ' ' + this.product;
      },
      image() {
        return this.variants[this.selectedVariant].variantImage;
      },
      inStock() {
        return this.variants[this.selectedVariant].variantQuantity;
      },
      shipping() {
        if (this.premium) {
          return "Free";
        } else {
          return 2.99
        }
      }
    }
})

var app = new Vue({
  el: '#app',
  data: {
    premium: true,
    cart: []
  },
  methods: {
    updateCart(id) {
      this.cart.push(id);
    }
  }
})


مهمة



نريد أن يكون زوار الموقع قادرين على ترك تعليقات على المنتجات ، لكن موقعنا لا يملك حتى الآن الوسائل لتلقي البيانات من المستخدمين. الأشكال هي مثل هذه الوسائل.



حل المشكلة



لحل المهمة التي أمامنا ، نحتاج إلى إنشاء نموذج. لنبدأ بإنشاء مكون جديد خصيصًا للعمل مع نموذج. دعنا نسمي هذا المكون product-review. تم اختيار هذا الاسم لأن المكون سيدعم نموذج تجميع مراجعات المنتج. المكون product-reviewسوف تكون متداخلة داخل المكون product.



دعنا نسجل مكونًا جديدًا ، ونبدأ في تشكيل القالب الخاص به وتجهيزه ببعض البيانات:



Vue.component('product-review', {
  template: `
    <input>
  `,
  data() {
    return {
      name: null
    }
  }
})


كما ترى ، يوجد عنصر في قالب المكون <input>، وهناك خاصية في بيانات المكون data، بينما تكون فارغة.



كيف يمكنني ربط ما يدخله المستخدم في حقل بخاصية name؟



في الدروس السابقة ، تحدثنا عن ربط البيانات باستخدام التوجيهات v-bind، ولكن بعد ذلك نظرنا فقط في الربط أحادي الاتجاه. انتقل تدفق البيانات من الخاصية التي تخزن البيانات إلى عنصر التحكم الذي يعرضها. والآن نحتاج إلى أن ما يدخله المستخدم في الحقل سيكون في الخاصية nameالمخزنة في بيانات المكون. بمعنى آخر ، نريد توجيه تدفق البيانات من حقل الإدخال إلى الخاصية.



توجيه نموذج V.



v-modelيسمح التوجيه بتنظيم ربط البيانات ثنائي الاتجاه. باستخدام مخطط العمل هذا ، إذا ظهر شيء جديد في حقل الإدخال ، فهذا يؤدي إلى تغيير في البيانات. وبالتالي ، عندما تتغير البيانات ، يتم تحديث حالة عنصر التحكم الذي يستخدم هذه البيانات.



دعنا نضيف توجيهًا إلى حقل الإدخال v-modelونربط هذا الحقل بخاصية nameمن بيانات المكون.



<input v-model="name">


الآن دعنا نضيف كود النموذج الكامل إلى قالب المكون:



<form class="review-form" @submit.prevent="onSubmit">
  <p>
    <label for="name">Name:</label>
    <input id="name" v-model="name" placeholder="name">
  </p>

  <p>
    <label for="review">Review:</label>
    <textarea id="review" v-model="review"></textarea>
  </p>

  <p>
    <label for="rating">Rating:</label>
    <select id="rating" v-model.number="rating">
      <option>5</option>
      <option>4</option>
      <option>3</option>
      <option>2</option>
      <option>1</option>
    </select>
  </p>

  <p>
    <input type="submit" value="Submit">  
  </p>

</form>


كما ترون، و v-modelالحقول input، textareaو مجهزة التوجيه select. يرجى ملاحظة أنه عند إعداد الحقل select، تم استخدام أداة تعديل .number(سنتحدث عنها بمزيد من التفصيل أدناه). يتيح لك هذا تحويل البيانات المقابلة إلى نوع Number، بينما يتم تمثيلها عادةً في سلسلة.



دعنا نكمل مجموعة بيانات المكون عن طريق إضافة البيانات التي ترتبط بها عناصر التحكم الموضحة أعلاه:



data() {
  return {
    name: null,
    review: null,
    rating: null
  }
}


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



هذا هو معدل الحدث. يمنع إعادة تحميل الصفحة بعد رفع الحدث submit. هناك معدّلات أخرى مفيدة للأحداث أيضًا . صحيح ، لن نتحدث عنها.



نحن الآن جاهزون لإنشاء طريقة onSubmit. لنبدأ بهذا الكود:



onSubmit() {
  let productReview = {
    name: this.name,
    review: this.review,
    rating: this.rating
  }
  this.name = null
  this.review = null
  this.rating = null
}


كما ترى ، تنشئ هذه الطريقة كائنًا بناءً على البيانات التي يدخلها المستخدم. تتم كتابة إشارة إليه إلى متغير productReview. هنا نسقط في nullقيم الممتلكات name، review، rating. لكن العمل لم ينته بعد. ما زلنا بحاجة إلى الإرسال إلى مكان ما productReview. إلى أين ترسل هذا الشيء؟



من المنطقي تخزين مراجعات المنتج في نفس المكان الذي يتم فيه تخزين بيانات المكونات product. بالنظر إلى أن المكون product-reviewمتداخل داخل المكون product، يمكننا القول أنه product-reviewعنصر تابع للمكون product. كما تعلمنا في الدرس السابق ، يمكنك استخدام الأحداث التي تم إنشاؤها باستخدام لإرسال البيانات من المكونات الفرعية إلى المكونات الرئيسية $emit.



دعونا نحسن الطريقة onSubmit:



onSubmit() {
  let productReview = {
    name: this.name,
    review: this.review,
    rating: this.rating
  }
  this.$emit('review-submitted', productReview)
  this.name = null
  this.review = null
  this.rating = null
}


الآن نقوم بإنشاء حدث باسم review-submittedونمرر الكائن الذي تم إنشاؤه حديثًا فيه productReview.



بعد ذلك ، نحتاج إلى تنظيم الاستماع لهذا الحدث من خلال وضع ما productيلي في النموذج :



<product-review @review-submitted="addReview"></product-review>


يقرأ هذا السطر على النحو التالي: "عند حدوث حدث review-submitted، يجب تشغيل طريقة addReviewالمكون product."



إليك رمز هذه الطريقة:



addReview(productReview) {
  this.reviews.push(productReview)
}


تأخذ هذه الطريقة الكائن productReviewالذي أتى من الطريقة onSubmit، ثم تضعه في مصفوفة reviewsمخزنة في بيانات المكون product. لكن لا توجد مثل هذه المصفوفة في بيانات هذا المكون حتى الآن. لذلك دعونا نضيفها هناك:



reviews: []


رائع! عناصر النموذج مرتبطة الآن ببيانات المكون product-review. يتم استخدام هذه البيانات لإنشاء الكائن productReview. ويتم تمرير هذا الكائن ، عند تقديم النموذج ، إلى المكون product. نتيجة لذلك ، يتم productReviewإضافة الكائن إلى الصفيف reviews، والذي يتم تخزينه في بيانات المكون product.



عرض مراجعات المنتج



الآن يبقى فقط عرض المراجعات التي تركها زوار الموقع على صفحة المنتج. سنفعل ذلك في المكون productعن طريق وضع الكود المقابل أعلى الكود الذي product-reviewيوضع به المكون في المكون product.



<div>
 <h2>Reviews</h2>
 <p v-if="!reviews.length">There are no reviews yet.</p>
 <ul>
   <li v-for="review in reviews">
   <p>{{ review.name }}</p>
   <p>Rating: {{ review.rating }}</p>
   <p>{{ review.review }}</p>
   </li>
 </ul>
</div>


هنا نقوم بإنشاء قائمة من المراجعات باستخدام التوجيه v-forوعرض البيانات المخزنة في الكائن reviewباستخدام تدوين النقطة. 



في العلامة ، <p>نتحقق مما إذا كان هناك شيء ما في المصفوفة reviews(عن طريق التحقق من طولها). إذا لم يكن هناك شيء في المصفوفة ، نطبع رسالة There are no reviews yet.





صفحة نموذج الملاحظات



التحقق من صحة النموذج



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



لحسن الحظ بالنسبة لنا ، يدعم HTML5 امتداد required. يبدو استخدامه كالتالي:



<input required >


سيؤدي هذا البناء إلى عرض تلقائي لرسالة الخطأ إذا حاول المستخدم إرسال نموذج يكون فيه الحقل المطلوب فارغًا.





رسالة الخطأ



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



التحقق من صحة النموذج المخصص



لنتحدث عن كيفية إنشاء نظام التحقق من صحة النموذج الخاص بك.



لنقم بتضمين product-reviewمصفوفة لتخزين رسائل الخطأ في بيانات المكون . دعنا نسميها errors:



data() {
  return {
    name: null,
    review: null,
    rating: null,
    errors: []
  }
}


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



if(!this.name) this.errors.push("Name required.")
if(!this.review) this.errors.push("Review required.")
if(!this.rating) this.errors.push("Rating required.")


يخبر أول هذه السطور النظام nameبوضع errorsرسالة خطأ في المصفوفة إذا كان الحقل فارغًا Name required. السلاسل الأخرى التي تحقق من صحة reviewو مجالات العمل بالمثل rating. إذا كان أي منها فارغًا ، arrayفسيتم إرسال رسالة خطأ إلى المصفوفة .



أين أضع هذا الرمز؟



وبما أننا نريد رسائل الخطأ المراد كتابتها إلى مجموعة فقط عندما، عند محاولة إرسال النموذج، اتضح أن الحقول name، reviewأو submitلا شغل، يمكننا وضع هذه التعليمات البرمجية في الأسلوب onSubmit. بالإضافة إلى ذلك ، سنعيد كتابة الكود الموجود بالفعل ، بإضافة بعض الشيكات إليه:



onSubmit() {
  if(this.name && this.review && this.rating) {
    let productReview = {
      name: this.name,
      review: this.review,
      rating: this.rating
    }
    this.$emit('review-submitted', productReview)
    this.name = null
    this.review = null
    this.rating = null
  } else {
    if(!this.name) this.errors.push("Name required.")
    if(!this.review) this.errors.push("Review required.")
    if(!this.rating) this.errors.push("Rating required.")
  }
}


الآن علينا التحقق من المجالات name، reviewو rating. إذا كانت هناك بيانات في جميع هذه الحقول ، فإننا ننشئ كائنًا بناءً عليها productReviewونرسلها إلى المكون الرئيسي. ثم يتم إعادة تعيين الخصائص المقابلة.



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



كل ما تبقى هو عرض هذه الأخطاء التي يمكن القيام بها بالكود التالي:



<p v-if="errors.length">
  <b>Please correct the following error(s):</b>
  <ul>
    <li v-for="error in errors">{{ error }}</li>
  </ul>
</p>


هنا يتم استخدام توجيه v-ifنتحقق من خلاله errorsمن وجود رسائل خطأ في المصفوفة (في الواقع ، نقوم بتحليل طول المصفوفة). إذا كان هناك شيء ما في المصفوفة ، فسيتم عرض عنصر يعرض <p>، عند تطبيقه v-for، قائمة بالأخطاء من المصفوفة errors.





رسائل الخطأ



لدينا الآن نظام التحقق من صحة النموذج الخاص بنا.



استخدام معدِّل الرقم



يمكن أن يكون المُعدِّل .numberالمستخدم في التوجيه v-modelمفيدًا جدًا. ولكن عند تطبيقه ، ضع في اعتبارك أن هناك مشكلة واحدة مرتبطة به. إذا كانت القيمة المقابلة فارغة ، فسيتم تمثيلها كسلسلة وليس كرقم. و صفة فيو الكتاب يقدم حلا لهذه المشكلة. يتمثل في تحويل القيمة المقابلة صراحةً إلى نوع رقمي:



Number(this.myNumber)


ورشة عمل



أضف السؤال التالي إلى النموذج: "هل تنصح بهذا المنتج؟" اجعلها حتى يتمكن المستخدم من الإجابة عليها باستخدام أزرار الاختيار "نعم" و "لا". تحقق من إجابة هذا السؤال وقم بتضمين البيانات ذات الصلة في الكائن productReview.



  • إليك نموذج يمكنك استخدامه لحل هذه المشكلة.
  • هذا هو الحل للمشكلة.


النتيجة



تحدثنا اليوم عن العمل مع النماذج. إليك أهم شيء تعلمته اليوم:



  • يمكنك استخدام التوجيه لتنظيم ربط البيانات ثنائي الاتجاه لعناصر النموذج v-model.
  • .numberيخبر المُعدِّل Vue أن يلقي القيمة المقابلة إلى نوع رقمي. ولكن عند العمل بها ، هناك مشكلة واحدة تتعلق بحقيقة أن القيم الفارغة تظل سلاسل.
  • .preventيسمح لك معدِّل الحدث بمنع إعادة تحميل الصفحة بعد إرسال النموذج.
  • باستخدام Vue ، يمكنك تنفيذ آلية بسيطة إلى حد ما للتحقق من صحة النموذج المخصص.


هل قمت بواجبك اليوم؟



درس المبتدئين Vue.js 1: المثال Vue

Vue.js للمبتدئين ، الدرس 2: سمات الربط

Vue.js الدرس 3: العرض الشرطي

Vue.js للمبتدئين الدرس 4: عرض القوائم

Vue .js للمبتدئين الدرس 5: معالجة الأحداث

Vue.js للمبتدئين الدرس 6: فئات وأنماط الربط

Vue.js للمبتدئين الدرس 7: الخصائص المحسوبة

Vue.js للمبتدئين الدرس 8: المكونات

Vue. js للمبتدئين الدرس 9: أحداث مخصصة






All Articles