Bonjour, Habr!
La validation des formulaires est l'une des tâches les plus importantes du site. Nous devons valider les données pour la présence, pour faire correspondre le modèle, créer des validations asynchrones, appliquer des validations uniquement après avoir supprimé le focus du champ ou avant de soumettre le formulaire ... Parfois, cela devient un vrai casse-tête pour le développeur.
Vue.js contient de nombreuses approches de validation intéressantes et inhabituelles qui vous aideront à résoudre vos problèmes. Aperçu sous la coupe!
TL; DR
Utilisez
Vuelidate .
Erreurs courantes
Validations HTML5
HTML5 a donné aux développeurs la possibilité de valider des formulaires à l'aide de
nouveaux attributs de champ et de l'API de validation . Nous pouvons les utiliser directement dans nos modèles de vue.
Voici, par exemple, un simple formulaire d'inscription composé de trois champs: les champs pour l'e-mail, pour le mot de passe et la relecture du mot de passe. Pour les deux premiers, nous utilisons des validations à l'aide d'attributs, pour le troisième - à l'aide d'attributs et de l'API de validation:
<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>
Sandbox avec un exempleMême dans un exemple aussi simple, vous pouvez voir de nombreux problèmes:
- Les navigateurs n'affichent qu'une seule erreur à la fois. L'utilisateur devra essayer de soumettre le formulaire plusieurs fois pour voir toutes ses erreurs.
- Les erreurs ne sont affichées pour l'utilisateur qu'après avoir tenté de soumettre le formulaire. Pour changer ce comportement, vous devrez écrire une autre tonne de code: appelez la fonction reportValidity () sur chaque élément de l'événement flou.
- Pour styliser les champs de saisie, il n'y a que des pseudo-classes: valide et: invalide, il n'y a aucun moyen d'attraper un état lorsque les données du champ de saisie sont incorrectes, mais l'utilisateur n'a pas encore interagi avec elles.
- Chaque navigateur affiche des erreurs de validation à sa manière, elles peuvent sembler laides dans votre conception.
- L'API de validation dans Vue.js est peu pratique à utiliser: vous devez enregistrer les éléments dans $ refs.
Si vous n'avez qu'un seul formulaire dans le projet et qu'il n'est utilisé que par vous, la validation HTML5 est un excellent choix. Dans tous les autres cas, essayez d'utiliser d'autres approches.
Validations de bibliothèque
Un autre problème commun que je rencontre dans les projets est la validation de la bibliothèque.
<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>
Sandbox avec un exempleIl n'y a aucun problème avec cette approche. Sauf que dans les formulaires avec plus d'un champ, beaucoup de code répété est né, et chaque développeur écrit des validations à sa manière.
Le meilleur moyen de sortir de tous les problèmes est d'utiliser les bibliothèques que la communauté nous offre. Il existe actuellement deux solutions de validation de formulaires populaires:
Chacun a sa propre approche unique, que nous examinerons en détail ci-dessous.
vee-validate
vee-validate - une bibliothèque pour les validations apparues lors de la première version de Vue.js, a une grande communauté et est utilisée dans un grand nombre de projets.
L'âge affecte le poids - 31 Ko (minifié + GZIP), une fois et demie plus que Vue.js lui-même! Cela est dû au fait que la bibliothèque contient immédiatement un tas de choses:
- 35 validateurs intégrés
- Traduction en anglais des erreurs
- Directives de validation
- Composants de validation
La bibliothèque prend en charge 41 langues pour les erreurs. Pour l'installer et l'utiliser avec la localisation souhaitée, vous devez effectuer seulement quelques étapes:
npm i vee-validate
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 a deux approches de validation: en utilisant la directive et en utilisant des composants.
Validation avec la directive v-validate
L'approche utilisant la directive est très simple: vous mettez la directive v-validate dans le champ de saisie, à laquelle vous passez la liste des validateurs. L'état de validation et les lignes d'erreur peuvent ensuite être obtenus à partir des champs de champs et des erreurs à l'intérieur du composant.
Pour voir son utilisation comme exemple, créons un formulaire simple qui:
- Contient le champ "Numéro de série et de passeport"
- Contient le champ "Date de délivrance du passeport"
- Contient le champ "Nom"
- Ajoute l'attribut désactivé au bouton d'envoi du formulaire si les données sont incorrectes
<template> <form @submit.prevent="someAction()"> <div> <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> <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> <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: { </script>
Sandbox avec un exempleComme vous pouvez le voir, lors de l'utilisation des drapeaux à l'intérieur de fields.passport_date, j'ai dû vérifier la présence du champ passport_date - lors du premier rendu, vee-validate n'a aucune information sur vos champs et, par conséquent, il n'y a aucun objet avec des drapeaux. Pour vous débarrasser de cette vérification, utilisez l'assistant spécial
mapFields .
Validations des composants
La nouvelle méthode de validation qui est apparue à la fin de l'année dernière est l'utilisation de composants. Les auteurs eux-mêmes recommandent d'utiliser cette approche, et cela va bien avec la nouvelle syntaxe de slot de Vue.js@2.6.
La bibliothèque comprend deux composants:
- ValidationProvider - un composant dans lequel vous décrivez les validations et dans lequel vous encapsulez le champ de saisie.
- ValidationObserver - un composant qui combine les drapeaux de validation de plusieurs ValidationProviders.
Voici un formulaire d'un exemple passé, mais écrit à l'aide de composants:
<template> <ValidationObserver v-slot="{ valid }"> <form @submit.prevent="doAction()"> <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> <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> <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>
Sandbox avec un exempleAutres fonctionnalités de la bibliothèque
Les problèmes
Le premier et le plus gros problème est, bien sûr, sa taille. La bibliothèque ne prend pas en charge le tremblement d'arbre et l'ajout sélectif de validateurs. Que cela vous plaise ou non, votre gang aura toujours 2 composants et une directive de validation, une traduction en anglais et 35 validateurs.
Le deuxième problème est dû à l'approche d'abonnement basée sur les événements, des problèmes peuvent survenir lors de l'intégration avec d'autres bibliothèques qui modifient également le comportement des champs d'entrée (masqueurs, etc.).
Le troisième problème - plus subjectif - les traductions des erreurs sont générales et laides, ne reflètent pas la véritable essence.
Prenez la forme d'exemples passés. Si vous entrez le mauvais numéro et la mauvaise date du passeport, vous recevrez les erreurs suivantes:
. dd.MM.yyyy.
Je voudrais les remplacer par quelque chose de plus lisible:
1234 567890 ..
Vuelidate
La bibliothèque Vuelidate est apparue en réponse à des problèmes avec les approches contenues dans la bibliothèque vee-validate. Vuelidate n'a ni gestionnaires d'événements pour les champs, ni traductions pour les erreurs de validation.
Cela ne vous demande qu'une seule chose - pour décrire les validations dans l'objet validations. Puis elle créera elle-même un champ calculé $ v avec des drapeaux de validation de champ et des fonctions pour changer ces drapeaux.
Grâce à son approche de validation simple, Vuelidate ne pèse que 3,4 Ko (minifié + GZIP), presque 10 fois moins que vee-validate.
Il s'installe tout aussi facilement:
npm i vuelidate
import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate)
Réécrivez le formulaire de l'exemple précédent en utilisant Vuelidate:
<template> <form @submit.prevent="someAction()"> <div> <input type="text" v-model="passportData"> <span v-if="$v.passportData.$invalid"> 1234 567890 </span> </div> <div> <input type="text" v-model="passportDate" @blur="$v.passportDate.$touch()"> <span v-if="$v.passportDate.$error"> .. </span> </div> <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, }; }, </script>
Sandbox avec un exempleLes validateurs personnalisés peuvent être décrits rapidement et facilement à l'aide de fonctions. Si vous voulez que vos paramètres de validation tombent dans l'objet $ params, utilisez l'aide spéciale
withParams .
Comme vous pouvez le voir, les champs avec plusieurs erreurs prennent beaucoup de place et semblent monstrueux - ceci est résolu en créant un composant séparé pour afficher les validations.
Autres fonctionnalités de la bibliothèque
Les problèmes
Parmi les problèmes, on peut distinguer le nombre relativement faible de validateurs hors de la boîte; vous devez souvent écrire vos propres fonctions pour la validation.
Conclusion
J'ai utilisé la bibliothèque Vuelidate dans de nombreux projets et je n'ai jamais rencontré de problèmes insolubles. Pour moi, elle reste le meilleur choix. Si vous vous souciez de la taille de votre code et préférez une approche modèle à la description des validations - prenez-le, une documentation simple et une API riche permettront de valider des formes de toute complexité.
Si vous utilisez le panneau d'administration pour un usage interne, ne voulez pas passer une seule goutte de temps sur les lignes d'erreur - choisissez vee-validate. Cela aidera à écrire de nombreuses validations rapidement et sans problème.
Merci de votre attention!