Formulir validasi dalam Vue.js

Halo, Habr!

Validasi formulir adalah salah satu tugas paling penting di situs. Kami harus memvalidasi data untuk keberadaan, untuk mencocokkan pola, membuat validasi asinkron, menerapkan validasi hanya setelah menghapus fokus dari bidang atau sebelum mengirimkan formulir ... Kadang-kadang ini menjadi sakit kepala nyata bagi pengembang.

Vue.js berisi banyak pendekatan validasi yang menarik dan tidak biasa yang akan membantu menyelesaikan masalah Anda. Ikhtisar di bawah cut!


TL; DR


Gunakan Vuelidate .

Kesalahan umum


Validasi HTML5


HTML5 memberi pengembang kemampuan untuk memvalidasi formulir menggunakan atribut bidang baru dan API Validasi . Kita dapat menggunakannya secara langsung di templat vue kami.

Di sini, misalnya, adalah formulir pendaftaran sederhana yang terdiri dari tiga bidang: bidang untuk email, untuk kata sandi dan ulangan kata sandi. Untuk dua yang pertama, kami menggunakan validasi menggunakan atribut, untuk atribut yang menggunakan ketiga dan API Validasi:

<template> <form @submit.prevent="someAction()"> <input v-model="email" type="email" required> <input v-model="password" type="password" required> <input v-model="repeatedPassword" type="password" required ref="repeatedPasswordEl"> <button type="submit">   </button> </form> </template> <script> export default { data() { return { email: null, password: null, repeatedPassword: null, }; }, watch: { repeatedPassword: 'checkPasswordsEquality', password: 'checkPasswordsEquality', }, methods: { checkPasswordsEquality() { const { password, repeatedPassword } = this; const { repeatedPasswordEl } = this.$refs; if (password !== repeatedPassword) { repeatedPasswordEl.setCustomValidity( '  ', ); } else { repeatedPasswordEl.setCustomValidity(''); } }, }, }; </script> 

Kotak pasir dengan contoh

Bahkan dalam contoh sederhana seperti itu, Anda dapat melihat banyak masalah:

  • Peramban hanya menampilkan satu kesalahan setiap kali. Pengguna harus mencoba mengirimkan formulir beberapa kali untuk melihat semua kesalahan mereka.
  • Kesalahan ditampilkan kepada pengguna hanya setelah mencoba mengirimkan formulir. Untuk mengubah perilaku ini, Anda harus menulis satu ton kode lagi: panggil fungsi reportValidity () pada setiap elemen pada acara blur.
  • Untuk bidang input penataan, hanya ada kelas pseudo: valid dan: tidak valid, tidak ada cara untuk mengetahui keadaan saat data di bidang input salah, tetapi pengguna belum berinteraksi dengannya.
  • Setiap browser menampilkan kesalahan validasi dengan caranya sendiri, mereka mungkin terlihat jelek di desain Anda.
  • API validasi di Vue.js tidak nyaman untuk digunakan: Anda harus menyimpan elemen dalam $ ref.

Jika Anda hanya memiliki satu formulir di proyek, dan hanya digunakan oleh Anda, maka validasi HTML5 adalah pilihan yang sangat baik. Dalam semua kasus lain, cobalah untuk menggunakan pendekatan lain.

Validasi Perpustakaan


Masalah umum lain yang saya temui dalam proyek adalah validasi perpustakaan.

 <template> <form @submit.prevent="someAction()"> <input v-model="email" type="email" @blur="isEmailTouched = true" :class="{ error: isEmailError }" > <div v-if="isEmailError">    </div> <button :disabled="!isEmailValid" type="submit">   </button> </form> </template> <script> const emailCheckRegex = /^... RegExp   Email...$/; export default { data() { return { email: null, isEmailTouched: false, }; }, computed: { isEmailValid() { return emailCheckRegex.test(this.email); }, isEmailError() { return !this.isEmailValid && this.isEmailTouched; }, }, }; </script> 

Kotak pasir dengan contoh

Tidak ada masalah dengan pendekatan ini. Kecuali bahwa dalam bentuk dengan lebih dari satu bidang, banyak kode berulang yang lahir, dan setiap pengembang menulis validasi dengan caranya sendiri.

Cara terbaik dari semua masalah adalah dengan menggunakan perpustakaan yang ditawarkan komunitas kepada kami. Saat ini ada dua solusi validasi formulir populer:


Masing-masing memiliki pendekatan unik sendiri, yang akan kami pertimbangkan secara rinci di bawah ini.

memvalidasi


vee-validate - perpustakaan untuk validasi yang muncul selama versi pertama Vue.js, memiliki komunitas besar dan digunakan dalam sejumlah besar proyek.

Usia memengaruhi berat badan - 31 KB (diperkecil + GZIP), satu setengah kali lebih banyak daripada Vue.js sendiri! Ini disebabkan oleh fakta bahwa perpustakaan segera memuat banyak hal:

  • 35 validator bawaan
  • Terjemahan kesalahan bahasa Inggris
  • Arahan Validasi
  • Komponen Validasi

Perpustakaan mendukung 41 bahasa untuk kesalahan. Untuk menginstal dan menggunakannya dengan pelokalan yang diinginkan, Anda hanya perlu melakukan beberapa langkah:

 npm i vee-validate 

 /* main.js */ import Vue from 'vue'; import VeeValidate, { Validator } from 'vee-validate'; import ru from 'vee-validate/dist/locale/ru'; Validator.localize('ru', ru); Vue.use(VeeValidate, { locale: 'ru', }); /* ... */ 

Vee-validate memiliki dua pendekatan untuk validasi: menggunakan direktif dan menggunakan komponen.

Validasi dengan arahan validasi-v


Pendekatan menggunakan arahan sangat sederhana: Anda menempatkan arahan v-validate pada bidang input, yang Anda lulus daftar validator. Status validasi dan garis kesalahan kemudian dapat diperoleh dari bidang isian dan kesalahan di dalam komponen.

Untuk melihat penggunaannya sebagai contoh, mari kita buat formulir sederhana yang:

- Berisi bidang "Seri dan nomor paspor"
- Berisi bidang "Tanggal penerbitan paspor"
- Berisi bidang "Nama"
- Menambahkan atribut yang dinonaktifkan ke tombol kirim formulir jika data salah

 <template> <form @submit.prevent="someAction()"> <div> <!--             data-vv-as -          name -      --> <input type="text" v-model="passportData" v-validate="{ required: true, regex: /^\d{4} \d{6}$/ }" data-vv-as="   " name="passport_data" > <span v-if="errors.has('passport_data')"> {{ errors.first('passport_data') }} </span> </div> <div> <!--           .      v-model- lazy     fields.passport_date  invalid  ,       touched ,      blur --> <input type="text" v-model.lazy="passportDate" v-validate="{ required: true, date_format: 'dd.MM.yyyy' }" data-vv-as="  " name="passport_date" > <span v-if="fields.passport_date && fields.passport_date.touched && fields.passport_date.invalid" > {{ errors.first('passport_date') }} </span> </div> <div> <!--       ,    continues   errors.collect() --> <input type="text" v-model="name" v-validate.continues="{ required: true, alpha: true, max: 10 }" data-vv-as="" name="name" > <span v-for="error in errors.collect('name')" :key="error" > {{ error }} </span> </div> <button type="submit" :disabled="!isFormValid" >   </button> </form> </template> <script> export default { data() { return { passportData: null, name: null, passportDate: null, }; }, computed: { // ,      isFormValid () { return Object.keys(this.fields).every(field => this.fields[field].valid); }, }, }; </script> 

Kotak pasir dengan contoh

Seperti yang Anda lihat, ketika menggunakan flag di dalam fields.passport_date, saya harus memeriksa field passport_date untuk kehadiran - selama render pertama, vee-validate tidak memiliki informasi tentang bidang Anda dan, karenanya, tidak ada objek dengan flag. Untuk menghilangkan pemeriksaan ini, gunakan bantuan mapFields khusus.

Validasi Komponen


Metode validasi baru yang muncul pada akhir tahun lalu adalah penggunaan komponen. Penulis sendiri merekomendasikan untuk menggunakan pendekatan ini, dan itu berjalan dengan baik dengan sintaks slot baru dari Vue.js@2.6.

Perpustakaan menyediakan dua komponen:

  • ValidationProvider - komponen di mana Anda menjelaskan validasi dan di mana Anda membungkus bidang input.
  • ValidationObserver - komponen yang menggabungkan flag validasi dari beberapa ValidationProviders.

Ini adalah formulir dari contoh sebelumnya, tetapi ditulis menggunakan komponen:

 <template> <!-- ValidationObserver      .      valid      --> <ValidationObserver v-slot="{ valid }"> <form @submit.prevent="doAction()"> <!-- ValidationProvider                 name - ,      --> <ValidationProvider name="   " :rules="{ required: true, regex: /^\d{4} \d{6}$/ }" v-slot="{ errors }" > <input type="text" v-model="passportData"> <span v-if="errors[0]"> {{ errors[0] }} </span> </ValidationProvider> <!--         input,    blur  change  mode="lazy"  mode="eager" --> <ValidationProvider name="  " :rules="{ required: true, date_format: 'dd.MM.yyyy' }" v-slot="{ errors }" mode="lazy" > <input type="text" v-model="passportDate"> <span v-if="errors[0]"> {{ errors[0] }} </span> </ValidationProvider> <!--       ,     :bails="false" --> <ValidationProvider name="" :rules="{ required: true, alpha: true, max: 10 }" v-slot="{ errors }" :bails="false" > <input type="text" v-model="name"> <span v-for="error in errors" :key="error" > {{ error }} </span> </ValidationProvider> <button type="submit" :disabled="!valid">   </button> </form> </ValidationObserver> </template> <script> import { ValidationProvider, ValidationObserver } from 'vee-validate'; export default { components: { ValidationProvider, ValidationObserver, }, data() { return { passportData: null, passportDate: null, name: null, }; }, }; </script> 

Kotak pasir dengan contoh

Fitur perpustakaan lainnya



Masalahnya


Masalah pertama dan terbesar tentu saja adalah ukurannya. Perpustakaan tidak mendukung pengguncang pohon dan penambahan validator selektif. Suka atau tidak suka, geng Anda akan selalu memiliki 2 komponen dan arahan validasi, terjemahan ke dalam bahasa Inggris dan 35 validator.

Masalah kedua adalah karena pendekatan berlangganan berbasis acara, masalah dapat muncul ketika berintegrasi dengan perpustakaan lain yang juga mengubah perilaku bidang input (masker, dll.).

Masalah ketiga - yang lebih subjektif - terjemahan kesalahan bersifat umum dan jelek, tidak mencerminkan esensi nyata.

Ambil formulir dari contoh sebelumnya. Jika Anda memasukkan nomor dan tanggal paspor yang salah, Anda akan menerima kesalahan berikut:

        .         dd.MM.yyyy. 

Saya ingin menggantinya dengan sesuatu yang lebih mudah dibaca:

          1234 567890         .. 

Vuelidate


Perpustakaan Vuelidate muncul sebagai respons terhadap masalah dengan pendekatan yang berisi perpustakaan vee-validate. Vuelidate tidak memiliki pengendali acara untuk bidang, atau terjemahan untuk kesalahan validasi.

Anda hanya perlu satu hal - untuk menjelaskan validasi dalam objek validasi. Lalu dia sendiri akan membuat bidang yang dihitung $ v dengan tanda validasi bidang dan fungsi untuk mengubah tanda ini.

Berkat pendekatan validasinya yang sederhana, Vuelidate memiliki berat hanya 3,4 KB (diperkecil + GZIP), hampir 10 kali lebih kecil dari validasi-vee.

Itu diinstal dengan mudah:

 npm i vuelidate 

 /* main.js */ import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate) /* ... */ 

Tulis ulang formulir dari contoh sebelumnya menggunakan Vuelidate:

 <template> <form @submit.prevent="someAction()"> <!--      ,  $v.passportData.$invalid   ,     --> <div> <input type="text" v-model="passportData"> <span v-if="$v.passportData.$invalid">         1234 567890 </span> </div> <!--      blur  $touch()   $v.passportDate.$dirty  true.  $v.passportDate.$error   $v.passportDate.$invalid && $v.passportDate.$dirty --> <div> <input type="text" v-model="passportDate" @blur="$v.passportDate.$touch()"> <span v-if="$v.passportDate.$error">      .. </span> </div> <!-- ,       blur,     $v.passportDate.$model - ,     : - Vuelidate     passportDate - Vuelidate   $touch()   $v.passportDate  lazy ,      blur --> <div> <input type="text" v-model.lazy="$v.passportDate.$model"> <span v-if="$v.passportDate.$error">      .. </span> </div> <!--     --> <div> <input type="text" v-model="name" @blur="$v.name.$touch()"> <span v-if="$v.name.$error"> <template v-if="!$v.name.maxLength">      {{ $v.name.$params.maxLength.max }}  </template> <template v-else-if="!$v.name.alpha">      </template> <template v-else>     </template> </span> </div> <button type="submit" :disabled="$v.$invalid">   </button> </form> </template> <script> import { required, maxLength } from 'vuelidate/lib/validators'; import moment from 'moment'; export default { data() { return { passportData: null, name: null, passportDate: null, }; }, //   ,  Vuelidate   computed- $v validations: { //        data passportData: { required, validFormat: val => /^\d{4} \d{6}$/.test(val), }, passportDate: { required, validDate: val => moment(val, 'DD.MM.YYYY', true).isValid(), }, name: { required, maxLength: maxLength(10), alpha: val => /^[-]*$/i.test(val), }, }, }; </script> 

Kotak pasir dengan contoh

Validator khusus dapat dengan cepat dan mudah dijelaskan menggunakan fungsi. Jika Anda ingin parameter validator Anda jatuh ke objek $ params, gunakan pembantu withParams khusus.

Seperti yang Anda lihat, bidang dengan beberapa kesalahan membutuhkan banyak ruang dan terlihat mengerikan - ini diselesaikan dengan membuat komponen terpisah untuk menampilkan validasi.

Fitur perpustakaan lainnya



Masalahnya


Dari masalah-masalah tersebut, seseorang dapat memilih jumlah validator yang relatif sedikit di luar kotak, Anda sering harus menulis fungsi Anda sendiri untuk validasi.

Kesimpulan


Saya menggunakan perpustakaan Vuelidate di banyak proyek dan tidak pernah mengalami masalah yang tidak dapat diselesaikan. Bagi saya, dia tetap pilihan terbaik. Jika Anda peduli tentang ukuran kode Anda dan lebih suka pendekatan model terhadap deskripsi validasi - ambil saja, dokumentasi sederhana dan api kaya akan memungkinkan memvalidasi bentuk kompleksitas apa pun.

Jika Anda melakukan panel admin untuk penggunaan internal, tidak ingin menghabiskan setetes waktu pada baris kesalahan - pilih vee-validate. Ini akan membantu untuk menulis banyak validasi dengan cepat dan tanpa masalah.

Terima kasih atas perhatian anda!

Source: https://habr.com/ru/post/id444900/


All Articles