Проверка формы - одна из самых сложных тем, с которой сталкиваются многие фронтенд-инженеры. Хотя реализовать это несложно, организовать логику валидации сложно.
С Vue у вас есть два основных варианта: проверка на основе шаблона с vee-validate или проверка на основе модели с vuelidate. Оба они - отличная библиотека. vee-validate очень прост и может быть быстрым решением. vuelidate обладает большей гибкостью.
С другой стороны, благодаря членам основной команды Vue выпускается Vue 3.0. Одно из серьезных изменений Vue 3.0 - это композиция api. Это позволяет нам писать более организованные и компонуемые коды.
Затем vuelidate также представит новый api с api композиции Vue 3.0. В этой статье объясняется, что он очень гибкий и позволяет разработчикам писать суперорганизованный код.
- Разница в реализации между vuelidate, совместимым с Vue 2.x, и Vue 3.0
- Как организовать логику валидации с помощью API композиции и vuelidate
Обзор валидаций Vue 2.x
Прежде чем представить следующее поколение vuelidate, позвольте мне показать вам, как это выглядит с Vue 2.x. Я подготовил простую форму входа, как показано ниже.
<template> <div> <input type="email" placeholder="Email" v-model="email" /> <input type="password" placeholder="Password" v-model="password" /> <button type="submit">Login</button> </div> </template>
Чтобы реализовать логику проверки с помощью vuelidate, вам нужно сделать 3 вещи.
- Реализуйте логику проверки
- Контролируйте, когда проверять
- При необходимости показать ошибки
Реализуйте логику проверки
Логика проверки выглядит очень простой, как показано ниже. validations
раздел используется для реализации того, как проверять все данные.
<script> import { required, email, minLength } from "vuelidate/lib/validators"; export default { data() { return { email: "", password: "", } }, validations: { email: { required, email }, password: { required, minLength: minLength(8) } } }; </script>
Если вы настроили, как указано выше, вы можете проверить статус валидации с помощью vue devtool. $v
вычисляемое свойство показывает каждый статус проверки. Перед вводом любого значения $v.email.$invalid
истинно, потому что проверка адреса электронной почты не выполняется. При вводе чего-либо $v.email.required
становится ложным, а $v.email.email
становится ложным. После ввода отформатированного электронного письма $v.email.email
и $v.email.$invalid
становятся истинными.
Контролируйте, когда проверять
Чтобы контролировать время проверки, вы должны знать свойства $error
и $dirty
. Свойство $error
представляет собой логическую комбинацию $dirty
и $invalid
.
$invalid
имеет статус проверки. Как вы проверили выше, $invalid
истинно до того, как пользователь что-то сделает. Но только с $invalid
, статус проверки не выполняется до того, как пользователь что-то сделает. Для решения этой проблемы существует свойство $dirty
. $dirty
проверка свойств, касается ли пользователь целевого поля ввода. Если пользователь что-то вводит, вы должны изменить $dirty
на true.
Хорошо, достаточно подумать, когда проводить проверку. В этом примере эти 2 тайминга могут быть хорошими.
- каждая проверка поля ввода должна запускаться на
@blur
- Перед отправкой формы. Лучше отключить кнопку входа в систему, если есть ошибка
Чтобы реализовать проверку времени размытия, вы можете добавить $touch()
к @blur
, как показано ниже. $touch
функция изменит $dirty
на true. Итак, свойства $dirty
и $invalid
готовы.
// To fire validation in each blur <input type="email" placeholder="Email" v-model="email" @blur="$v.email.$touch()" /> ... <input type="password" placeholder="Password" v-model="password" @blur="$v.password.$touch()" />
Чтобы отключить кнопку отправки, вы можете передать $v.$invalid
. Он проверяет $invalid
всех ключей проверки. Тогда div
tag должен быть тегом form
и добавить вызов функции отправки. Внутри функции отправки сначала вызовите $touch()
. Он запускает все проверки и проверяет наличие ошибок.
// To disable submit button disabled <button :disabled="$v.$invalid" type="submit">Login</button> // To validate before submission <template> <form @submit.prevent="login" > ... </form> </template> <script> ... methods: { login() { this.$v.$touch(); if (this.$v.$invalid) { // DO SOMETHING HERE } } } ...
Итак, теперь вы можете контролировать, когда проводить проверку.
При необходимости показать ошибки
Так что давайте, если нужно, покажем пользователям ошибки. Если вы хотите отображать ошибки, вы должны реализовать то, что показано ниже. Вам необходимо проверить, имеет ли целевое значение $error
, и отображать сообщения об ошибках для каждой проверки.
<template> <form @submit.prevent="login"> <input type="email" placeholder="Email" v-model="email" @blur="$v.email.$touch()" /> <div v-if="$v.email.$error"> <p v-if="!$v.email.email">Please enter a valid email</p> <p v-if="!$v.email.required">Please enter an email</p> </div> <input type="password" placeholder="Password" v-model="password" @blur="$v.password.$touch()" /> <div v-if="$v.password.$error"> <p v-if="!$v.password.minLength"> Password must be more than {{ passwordMinLength }} characters </p> <p v-if="!$v.password.required">Please enter an password</p> </div> <button :disabled="$v.$invalid" type="submit">Login</button> </form> </template>
При использовании vuelidate, совместимого с Vue 2.x, вам необходимо создавать свои собственные сообщения проверки.
Пока все проверки были выполнены. Позвольте мне показать вам, как выглядят все коды.
<template> <form @submit.prevent="login"> <input type="email" placeholder="Email" v-model="email" @blur="$v.email.$touch()" /> <div v-if="$v.email.$error"> <p v-if="!$v.email.email">Please enter a valid email</p> <p v-if="!$v.email.required">Please enter an email</p> </div> <input type="password" placeholder="Password" v-model="password" @blur="$v.password.touch()" /> <div v-if="$v.password.$error"> <p v-if="!$v.password.minLength"> Password must be more than {{ passwordMinLength }} characters </p> <p v-if="!$v.password.required">Please enter an password</p> </div> <button :disabled="$v.$invalid" type="submit">Login</button> </div> </template> <script> import { required, email, minLength } from "vuelidate/lib/validators"; export default { data() { return { email: "", password: "", } }, validations: { email: { required, email }, password: { required, minLength: minLength(8) } }, methods: { login() { this.$v.$touch(); if (this.$v.$invalid) { // DO SOMETHING HERE } } } }; </script>
Как вы понимаете, даже в этой сверхпростой форме входа в систему много кодов. Так что, если у вас больше поля и больше другой логики, все легко усложняется. Когда я впервые увидел эту реализацию, я подумал, что раздел validations
и сообщение об ошибке в шаблоне можно извлечь или просто.
Проверка Vue 3.0 с помощью vuelidate
Api композиции Vue 3.0 позволяет нам очень легко составлять и организовывать логику. Если вы хотите узнать api композиции, посмотрите Vue mastery course.
Итак, давайте реализуем ту же форму входа с API композиции Vue 3.0 и vuelidate. Прежде всего, давайте создадим проект vue с api композиции. vue-cli
- это самый простой способ. API композиции предоставляется с @vue/composition-api
.
※ Если выпущен Vue 3.0, вы можете просто использовать vue-cli и установить Vue 3.0.
$ yarn global add @vue/cli // If you don't have it $ vue create vuelidate-with-vue-composition-api $ cd vuelidate-with-vue-composition-api $ yarn add @vue/composition-api
Измените src/components/HelloWorld.vue
, как показано ниже.
// Form.vue <template> <div> <input type="text" v-model="email"> <input type="password" v-model="password"> <button type="submit">Login</button> </div> </template> <script> import { reactive, toRefs } from "@vue/composition-api"; export default { name: "Form", setup(){ const state = reactive({ email: "", password: "" }); return { ...toRefs(state) }; } }; </script> // STYLE CAN BE ANYTHING <style scoped> div,form { display: flex; flex-direction: column; justify-content: center; } input, button { width: 300px; height: 50px; font-size: 1rem; margin: 20px auto 0px; } p { margin: 5px 60px 0 0; } </style>
И App.vue
должен выглядеть так, как показано ниже.
// Replace HelloWorld component with Form component <template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" /> <Form /> </div> </template> <script> import Form from "./components/Form.vue"; export default { name: "App", components: { Form } }; </script>
Итак, давайте добавим vuelidate. Фактически, начиная с версии, совместимой с Vue 3.0, vuelidate разделен на два пакета: @vuelidate/core
и @vuelidate/validators
. Логики проверки, такие как required
и minLength
, были разделены. И поскольку vuelidate все еще является бета-версией, для него требуется @vue/composition-api
в качестве зависимостей, возможно, в ближайшем будущем он исчезнет.
$ yarn add @vuelidate/core @vuelidate/validators
И сначала вы должны настроить vuelidate и композицию api.
// main.js import Vue from 'vue'; import VueCompositionApi from '@vue/composition-api'; import { VuelidatePlugin } from '@vuelidate/core'; import App from './App.vue'; Vue.config.productionTip = false; Vue.use(VueCompositionApi); Vue.use(VuelidatePlugin); new Vue({ render: h => h(App), }).$mount("#app");
Все настройки были выполнены! Давайте реализуем проверку формы, как я сделал выше.
Реализуйте логику проверки
Новый vuelidate реализован с использованием API композиции Vue 3.0. Это выглядит так, как показано ниже. Во-первых, вы не можете использовать reactive
сейчас. Это становится проблемой.
// Form.vue <script> import { ref } from "@vue/composition-api"; import useVuelidate from "@vuelidate/core"; import { required, email, minLength } from "@vuelidate/validators"; export default { name: "Form", setup(){ const userEmail = ref(""); const userPassword = ref(""); // Validation Logics const rules = { userEmail: { required, email }, userPassword: { required, minLength: minLength(8) } }; const $v = useVuelidate( rules, { userEmail, userPassword } ); return { userEmail, userPassword, $v }; } }; </script>
На самом деле, когда вы видите только логику проверки, это очень похоже на раздел Vue 2.x validations
. С другой стороны, $v
немного отличается от vuelidate, совместимого с Vue 2.0.
Как вы можете видеть выше, появилось новое свойство new$errors
. Поскольку в нем хранятся сообщения об ошибках по умолчанию, вам не нужно писать собственное сообщение об ошибке.
Контролируйте, когда проверять
Давайте реализуем размытие полей ввода и проверку времени отправки.
К сожалению, поскольку родная функция $touch
не выпущена, вы должны самостоятельно изменить $dirty
на true. Он реализован в handleBlur
и login
функциях. Надеюсь, он будет выпущен в ближайшем будущем.
<template> <form @submit.prevent="login"> <input type="text" v-model="userEmail" @blur="handleBlur('userEmail')" > ... <input type="password" v-model="userPassword" @blur="handleBlur('userPassword')" > <button :disabled="$v.$invalid" type="submit">Login</button> </form> </template> <script> ... setup(){ ... const handleBlur = (key) =>{ $v[key].$dirty = true; }; const login = () => { $v.$dirty = true; if (!$v.$error) { // DO SOMETHING HERE } }; return { userEmail, userPassword, $v, handleBlur }; } }; </script>
При необходимости показать ошибки
Как я уже упоминал выше, vuelidate, совместимый с Vue 3.0, имеет $errors
, в котором хранятся сообщения об ошибках по умолчанию. Давайте использовать его с v-for
.
<template> <form @submit.prevent="login"> <input type="text" v-model="userEmail" @blur="handleBlur('userEmail')" > <div v-if="$v.userEmail.$error"> <p v-for="$error in $v.userEmail.$errors" :key="$error.$property"> {{ $error.$message }} </p> </div> <input type="password" v-model="userPassword" @blur="handleBlur('userPassword')" > <div v-if="$v.userPassword.$error"> <p v-for="$error in $v.userPassword.$errors" :key="$error.$property"> {{ $error.$message }} </p> </div> <button :disabled="$v.$invalid" type="submit">Login</button> </form> </template>
Как видите, раздел сообщения об ошибке можно разделить на разные компоненты, как показано ниже.
// ErrorMessage.vue <template> <div v-if="validationStatus.$error"> <p v-for="$error in validationStatus.$errors" :key="$error.$property"> {{ $error.$message }} </p> </div> </template> <script> export default { name: "ErrorMessage", props: { validationStatus: { type: Object, required: true }, } }; </script> // ADD STYLE IF YOU WANT
После создания компонента ErrorMessage
ваш шаблон становится очень чистым. Раздел сообщения об ошибке в шаблоне извлечен 🎉
// Form.vue <template> <form @submit.prevent="login"> <input type="text" v-model="userEmail" @blur="handleBlur('userEmail')"> <ErrorMessage :validationStatus="$v.userEmail" /> <input type="password" v-model="userPassword" @blur="handleBlur('userPassword')"> <ErrorMessage :validationStatus="$v.userPassword" /> <button :disabled="$v.$invalid" type="submit">Login</button> </form> </template>
Реализована вся логика валидации. Итак, позвольте мне показать вам весь код.
// Form.vue <template> <form @submit.prevent="login"> <input type="text" v-model="userEmail" @blur="handleBlur('userEmail')"> <ErrorMessage :validationStatus="$v.userEmail" /> <input type="password" v-model="userPassword" @blur="handleBlur('userPassword')"> <ErrorMessage :validationStatus="$v.userPassword" /> <button :disabled="$v.$invalid" type="submit">Login</button> </form> </template> <script> import { ref } from "@vue/composition-api"; import useVuelidate from "@vuelidate/core"; import { required, email, minLength } from "@vuelidate/validators"; import ErrorMessage from "./ErrorMessage.vue"; export default { name: "Form", components: { ErrorMessage, }, setup(){ const userEmail = ref(""); const userPassword = ref(""); const rules = { userEmail: { required, email }, userPassword: { required, minLength: minLength(8) } }; const $v = useVuelidate( rules, { userEmail, userPassword } ); const handleBlur = (key) =>{ $v[key].$dirty = true; }; const login = () => { $v.$dirty = true; if (!$v.$error) { // DO SOMETHING } }; return { userEmail, userPassword, $v, handleBlur, login }; } }; </script>
С API композиции Vue 3.0 у вас уже есть две вещи.
- Поскольку вам не нужно писать собственные сообщения об ошибках, создать
ErrorMessage
компонент очень просто. - Хотя логики проверки разделены в
validations
,methods
с Vue 2.x, все связанные с проверкой логики организованы в одном месте с Vue 3.0.
Но композиция api может сделать ваш код намного чище. Позвольте мне показать вам, как это сделать!
Составьте логику проверки
Сначала создайте функцию useLoginForm
в Form.vue
и скопируйте и вставьте всю логику в setup
, как показано ниже.
// Form.vue <script> import { ref } from "@vue/composition-api"; ... export default { name: "Form", components: { ErrorMessage }, setup(){ const { userEmail, userPassword, $v, handleBlur, login } = useLoginForm(); return { userEmail, userPassword, $v, handleBlur, login }; } }; const useLoginForm = () =>{ const userEmail = ref(""); const userPassword = ref(""); const rules = { userEmail: { required, email }, userPassword: { required, minLength: minLength(8) } }; const $v = useVuelidate( rules, { userEmail, userPassword } ); const handleBlur = (key) =>{ $v[key].$dirty = true; }; const login = () => { $v.$dirty = true; if (!$v.$error) { // DO SOMETHING } }; return { userEmail, userPassword, $v, handleBlur, login }; }; </script>
Поскольку useLoginForm
функция - это просто функция, ее можно выделить в другой файл, например ,src/composables/useLoginForm.js
.
// Form.vue <script> import { useLoginForm } from "../composables/useLoginForm"; import ErrorMessage from "./ErrorMessage.vue"; export default { name: "Form", components: { ErrorMessage }, setup(){ const { userEmail, userPassword, $v, handleBlur, login } = useLoginForm(); return { userEmail, userPassword, $v, handleBlur, login }; } }; </script> // src/composables/useLoginForm.js import { ref } from "@vue/composition-api"; import useVuelidate from "@vuelidate/core"; import { required, email, minLength } from "@vuelidate/validators"; export const useLoginForm = () =>{ const userEmail = ref(""); const userPassword = ref(""); const rules = { userEmail: { required, email }, userPassword: { required, minLength: minLength(8) } }; const $v = useVuelidate( rules, { userEmail, userPassword } ); const handleBlur = (key) =>{ $v[key].$dirty = true; }; const login = () => { $v.$dirty = true; if (!$v.$error) { // DO SOMETHING } }; return { userEmail, userPassword, $v, handleBlur, login }; };
Теперь Form.vue
супер чисто, но понятно! Даже если в Form.vue
добавлены другие логики, такие как выборка, вы можете составить его таким же образом и сохранить Form.vue
очень чистым.
Заворачивать
Пока в этой статье объясняется, что
- Разница в реализации между vuelidate, совместимым с Vue 2.x, и Vue 3.0
- Как организовать логику валидации с помощью API композиции и vuelidate
Если есть вопросы, пишите комментарии! Я очень жду релиза Vue 3.0! Спасибо.