The Vue in the project needs to use form verification. After searching some information on the Internet, VeeValidate seems to work better, at least on Github.

In addition, VeeValidate is mentioned in the Cookbook on the Vue website at the end of “Form validation” in the “Alternative Models” section.

On opening the official website, it is completely the style of Vue official website, which makes people wonder if it is Vue official product. Besides, after a brief browse, the document is very good!

I can’t find the Chinese version, so I’m going to translate it and get familiar with how to use it.

Summary of this Guide

Introduction VeeValidate is a validation library dedicated to vue.js. It has many validation rules out of the box and supports custom validation rules as well. It’s template-based, so it’s similar and familiar to HTML5’s validation API. We can validate the HTML5 input field, as well as our custom Vue components.

It is also built on a localized basis, in fact, it supports approximately 44 languages, supported and maintained by community members. Features: Template-based validation provides many validation rules out of the box. First-class localization support validates HTML5 input fields and custom Vue components with custom rules and error messagesCopy the code

Getting Started Installation: The plug-in can be installed via NPM or CDN

npm: npm install vee-validate --save CDN: Two foreign CDN, Domestic risk estimate < script SRC = "https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js" > < / script > < script SRC = "https://cdn.jsdelivr.net/npm/vee-validate@latest/dist/vee-validate.js" > < / script > use: tip: The example uses ES2015 syntax, if you haven't already, make sure to use import Vue form 'Vue' on ES2015; import VeeValidate form 'vee-validate' Vue.use(VeeValidate); <script SRC ="path/to/vue.js"></script> <script SRC ="path/to/vee-validate.js"></script> <script> Vue.use(VeeValidate); </script> Basic example: All we need to do is add the 'V-validate' directive to the input field that we want to validate, make sure the input field has a name attribute, and after generating the error message, pass the directive a 'rules' string that contains a series of, Use '|' pipe separate validation rules. For the following example, the validation rules are simple. Use 'require' to indicate that the field is required, and 'email' to indicate that the field must be a mailbox. In order to combine the two rules, we will be 'required | email string value as a' v - validate the value of the expression. < - validate input v = "' required | email '" name =" email "type =" text "> to display an error message, we simply use the' errors. The first 'approach, in order to get the field generated by the first mistake: <span>{{errors.first('email')}}</span> Warning: client-side validation should never replace server-side validation. Make sure the backend validates any input from the user.Copy the code

Syntax VeeValidate’s validation rule has a simple Syntax similar to ‘Laravel validation ‘. (Laravel is used at the back end of our project)

Validation expression, consists of a series of, use '|' delimited string of validator: const single = 'required'; / / a single rule const multiple = 'required | numeric'; // Multiple regular rule expressions can also be a complex, more readable rule object: const single = {required: true}; const multiple = { required: true, numeric: true, email: true, }; Const someRule = 'included:1,2,3,4'; const someRule = 'included:1,2,3,4'; Const someRuleObj = {included: [1, 2, 3, 4]}; 3> an object (for rules on object formats, more complex configuration is provided), but take note of const someCplxObj = {email: {allow_uft8_LOCAL_part: true}}; Tip: In object format, if the rule accepts a single parameter, then the rule accepts a single value. If multiple parameters are passed, they should be passed together as an array in the same order. Rule practice: Putting what we've learned into practice, let's create our fields in two expressions and follow the following specification: a mandatory email field:  <input v-validate="'required|email'" type="email" name="email"> <input v-validate="{ required: true, email: True}" type="email" name="email">  <input v-validate="'alpha'" type="text" name="username"> <input v-validate="{ alpha: True}" type="text" name="username"> A mandatory password field with a minimum of 6 characters:  <input v-validate="'required|min:6'" type="password" name="password"> <input v-validate="{ required: true, min: 6}" type="password" name="password"> Tip: string expression with "'"(single quotes). Since the Vue directive evaluates the given expression, and since we want to evaluate it as a string, we need to enclose it with "'"(single quotes), which means that V-validate ="required" will fail, Because V-Validate will try to find a prop or method named 'required' on the Vue instance, which probably doesn't exist, it will fail.Copy the code

Validation Rules VeeValidate has a bunch of Validation Rules out of the box that are localized and cover most Validation requirements.

Specific rules, see the document!!Copy the code

We can easily add Custom Rules to VeeValidate, but our Custom Rules must follow a constract or specific structure:

Create a custom rule: Functional Form This is the most basic way to customize a validator. It consists of a single function that returns a Boolean value or Promise. However, it will have a default error message. Const validator = (value, args) => {// Returns a Boolean or a Promise instance that can be parsed to a Boolean}; Const validator = {getMessage(field, args){// To be added to the default locale message // return a message}, validate(value, Args){// Returns a Boolean value or a Promise instance that can be resolved to a Boolean value}}; The validator object must have a validate method and can contain a getMessage method that will be incorporated into the current dictionary locale. For multiple languages, we should use the Localization API. Tip: Notice how the getMessage method receives 'field', which is the name of the field to validate as its first argument, and how the validate method receives value as its first argument. Both methods receive an 'args' array containing the parameters of the validation rule configuration. Caveat: As we've seen, validation rules must implement one of these two forms. Failure to do so will throw an exception with a corresponding error message detailing what we are missing. Once you have created a custom rule, you can add it to the list of rules using the extend(Name, Validator) method of the validator instance. import {Validator} from 'vee-validate'; // This is the extend() method of 'class' validator.extend ('truthy', {getMessage: field => 'The ' + field + ' value is not truthy', validate: value => !! value }); let instance = new Validator({ trueField: 'truthy' }); Extend ('falsy', (value) =>! // For convenience, there is also a 'extend' method on instances instance.extend('falsy', (value) =>! value); instance.attach({ name: 'falseField', rules: 'falsy' }); Tip: Using the extend method on a class or instance extends all validators with the new validation rules. <input type="text" name="field" V-validate ="'falsy'"> warning: When the validation field is' not required ', our rule may not be enforced at all. This is because VeeValidate skips validation for 'empty fields' that are' not required '. Parameter and rule configuration Our rules may provide different results/behaviors depending on some of our configurations, as mentioned earlier, they are passed to the validator function as an 'array of values', which may not always be best, for example, a rule with three optional parameters, All three arguments need to be received each time just to specify the third argument. By providing a 'paramNames' array in the extension option (parameter 3), we can make our validation rule accept an object instead of an array. This object names the variables in the array we normally receive. Here's an example of a basic 'value between' rule implementation:  const isBetween = (value, { min, max } = {}) => { return Number(min) <= value && Number(max) >= value; }; // The first parameter is called 'min' and the second parameter is called 'Max' const paramNames = ['min', 'Max ']; Validator.extend('between', isBetween, {paramNames // pass it in extension options}); ParamNames isn't really required, but it does allow our rules to work in both sting/object formats. Because the string format cannot pass named parameters. Between: 10,20 In this case, the order controls the parameter names (10 corresponds to min; 20 corresponds to Max, so the order determines the parameter names. The validator uses paramNames to convert the array of strings into an object with the named parameter as the key and the corresponding correct parameter value as the value. Be sure to sort paramNames' in the same order as the parameters specified in the string format '. Warning: The Locale method will still receive the ARGS array. This method will not convert the ARgs to objects, because modifying them may cause the Locale file to need refactoring. Target-dependent rules Sometimes our rules may need to compare a validated field value to another field value. Some built-in rules, such as confirmed, before, and after, require a target field to compare. We can also create custom rules to implement 'target-dependent rules' by setting the hasTarget property on the extension option object (the third argument). Validator.extend('isBigger', (value, [otherValue]) => { return value >= otherValue; }, { hasTarget: true }); Notice that otherValue(other field value) will be injected as the first item in the parameter list. These rules require at least one parameter, and the target field must have a matching REF value. PS: At least one parameter, which means' target field ', There must also be an input box whose ref is' target field '< INPUT V-validate ="'confirmed:confirmation'" name="password" type="password"> <input Name ="passwordConfirmation" ref="confirmation" type="password" placeholder=" confirmation" > Must correspond to an input box whose ref is confirmation. <input ref="confirmation" ... The VeeValidate triggers the initial validation whether or not we use the IMediate modifier, the difference being that if the IMediate modifier is set, errors and flags are updated. Sometimes we don't want to execute rules. Imagine a rule that calls a remote API. We do not want to enforce this rule unless the iMediate modifier is set. This can be done by adding the 'iMediate' Boolean value to the extension option. Validation.extend('remote', (value, [otherValue]) => { }, { imediate: false }); Setting iMediate to false skips this rule during initial verification. Cause In addition, we might want to provide a reason for the 'can change error message' validation failure. For example, we are using an external API and the API provides error messages. To do this, our validator function should return an Object instead of a Boolean. The object should always contain a valid property and an optional data property. The data property is passed to the message generator function as the third argument, after which we should modify the output message with the data property that is passed in. This also applies to promises, which can be resolved using objects containing these properties. The following is a custom rules to realize this purpose: const myRule = {getMessage (field, params, data) {return (data & & data. The message) | | 'wrong'. }, validate(value){ return new Promise(resolve => { resolve({ valid: value === 'trigger' ? false : !! value, data: value ! == 'trigger' ? undefined : { message: 'Not this value' } }); }); }};Copy the code

In the form of the V-validate directive we can specify Rules, but vee-validate also analyzes and deduces other Rules based on the type of input box. For example, if we have the following:

< input name = "email" type = "email" required > specified v - validate = "' required | email" is redundant. Because vee-validate detects the type of the input box, as well as the required attribute, and automatically includes these rules for us, we simply add V-validate to the input box. <input name="email" type="email" required V-validate > Inference Rule Reference: This is an HTML attribute table that will be inferred as rules. Attribute name-value-rule type-email-email type-number-decimal type-date-date_format :YYYY-MM-DD type-datetime-local - Date_format: YYYY-MM-DDTHh: MM type-time - date_format:hh: MM or date_format:hh: MM :ss depends on the time input step type-week - date_format:YYYY-Www type - month - date_format:YYYY-MM min - val - min_value:val max - val - max_value:val pattern - Rgx-regex: RGX Required - none-Required Note: This feature does not apply to custom components, only HTML5 input fields can take advantage of this featureCopy the code

The VeeValidate comes with generic Error Messages that can be overridden or assigned specific Messages for specific fields.

Message generator messages exist in an internal dictionary. These can be strings or functions that return strings, called generators. These generators have the following structure: function rule (fieldName: string, params: any[], data? : any): string { return `Some error message for the ${fieldName} field`; } It accepts the name of the field or its alias as the first parameter (fieldName) and the parameter used to validate the field (params). The third optional argument is any other data returned by the validation rule, which gives the generator more information and makes it more flexible. The (data) override message Validator class and its instances provide a localize method that merges the supplied message with an internal dictionary to override any duplicates. Tip: Since the message dictionary is shared, any merge will affect all validator instances. import { Validator } from 'vee-validate'; const dictionary = { en: { messages:{ alpha: () => 'Some English Message' } }, ar: { messages: { alpha: 'ح an ج ة ع ر ب ي'}}}; // Overwrite and merge dictionary validator.localize (dictionary); const validator = new Validator({ first_name: 'alpha' }); validator.localize('ar'); / / the validator will now generate messages warning: Arabic language must provide information in the form of 'object path, similar' dictionary. Locale. The messages'. Typically, we build our language files for the application rather than hard-coding them as in the example above. Check the localization guide for more information (https://baianat.github.io/vee-validate/guide/localization.html). By default, error messages that do not specify a rule will automatically fall back to using the system default error message. We only need to define the message that we need to customize. As with custom messages, validators share a dictionary containing attribute names. For example, if we want to use 'Email Address' instead of 'Email 'in error messages, we can easily do this by including an Attributes object in the dictionary. Unlike messages, there are no attributes contained in the default dictionary. import { Validator } from 'vee-validate'; const dictionary = { en: { attributes: { email: 'Email Address' } }, ar: { attributes: { email: 'ال ع ر ر ر '| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Validator.localize(dictionary); Tip: If the property is not found in the current locale, the expression or field name using the binding is rolled back. If we used the data-vV-as attribute, it would take precedence over the internal dictionary. Custom messages specifying fields We may want to provide different messages for different fields. For example, we might want to display an error message when the email field is required, but a different message when the name field is required. This allows us to provide users with flexible experiences and context-aware messages. Const dist = {custom: {email: {required: 'Your email is empty'}, name: {required: () => 'Your name is empty' } } }; Validator.localize('en', dict); // Use the example method this.$validator.localize('en', dict); Tip: One thing to keep in mind is that any dictionary replacement in our code must be done before it is actually used to avoid unnecessary merging. For example, a very good common location is in the entry or startup script of our application. Instead, a bad choice is a lifecycle hook for a child component like Mounted, because the validator dictionary is shared globally for all instances.Copy the code

The Localization plug-in only ships with English messages by default to keep it small, but it is architected with a flexible message generation mechanism in mind. ‘English message file ‘(github.com/baianat/vee…) Is an example of how to construct these messages. After that, we might want to update the validator dictionary, which should only happen once when our application starts. However, we can update them at any time from anywhere in our application. Check out the dictionary section below.

Aliases We can not only create and overwrite messages, but also provide aliases for fields used in messages in place of the original names. Seeing 'first_name' in an error message might not be very good for the user experience. There are two solutions. Using data-vV-as We can use data-vV-as on fields like this: <input v-validate="'alpha'" data-vV-as ="First Name" Name ="first_name" type="text"> Now, when the input box above generates any error message, It replaces the real field name with the value of the data-vV-as attribute. While this is useful for simple setup and display of localized names, it only works on a single locale page. For multilingual pages and more advanced usage, we may need to use the 'dictionary API'. Using the Dictionary API, all validators have access to a simple dictionary that is shared between them. The dictionary contains localized error messages and attributes. If the validator finds a localized attribute name for a field, it will use it instead of the field name, much like data-vV-AS, except that data-vV-AS takes higher precedence if both 'dictionary API' and data-vV-AS are used. Here is a code example for how to add support for localized messages and attributes. import Vue from 'vue'; import VeeValidate from 'vee-validate'; import messagesAr from './strings/validator/messages/ar.js'; import attributesAr from './strings/validator/attributes/ar.js'; import attributesEn from './strings/validator/attributes/en.js'; Use (VeeValidate, {locale: 'ar', dictionary: {en: {attributes:); // Pass the option to make all validators use Arabic, and to merge English and Arabic attributes with internal dictionaries. attributesEn }, ar: { messages: messagesAr, attributes: attributesAr } } }); new Vue({ el: '#app', data: { // Some Data ... }, methods { // Cool methods ... }}); Warning: Localization logic should occur in our application entry, as it should only be executed once. The localization API validator class provides a static localize method that is also available on all instances and can be used in three ways: const dictionary = {en: {// properties and messages}, ar: {// Properties and messages}} // Switch the local language validator.localize ('en'); // Merge English in dictionary and set the current local language to English validator. localize('en', dictionary.en); // Merge all languages defined in the dictionary, but not set to the current local language validator.localize (dictionary); The locale of all validators is shared. Calling Localize changes the language Settings for all validators on any available instance in any component. // This.$validator.localize('ar'); import { Validator } from 'vee-validate'; // You can also use validator.localize ('ar') in prototypes; You get a warning if you set the locale to one that has not been incorporated into the dictionary. Any messages generated will fall back to English (the default language pack). Localized files are a collection of localized files in the locale directory of your plug-in. If we can't find the locale we need, we can contribute localized versions to the official code base to help improve the plug-in. We can import these locales as follows: import ar from 'vee-validate/dist/locale/ar'; import VeeValidate, { Validator } from 'vee-validate'; // Install the plugin Vue. Use (VeeValidate); // the localize method accepts the locale object as the second argument (optional) and consolidates it validator. localize('ar', ar); We must note that the localization file needs to export the following object structure: export default {name: '{locale}', messages: {... Also note that if introduced via the <script> tag and VeeValidate is available globally, they will be installed automatically. Loading each locale in the package in different steps is a bit of a waste of user bandwidth, especially if only one locale is used and you don't need to load all of them. With Webpack import(), we can easily do asynchronous localization Settings: import Vue from 'Vue '; import { Validator } from 'vee-validate'; Vue. Mixin ({localize(localeName){// Localize our application here, for example, i18n plugin // asynchronously load localization files, Import ('./path/to/vee-validate-locales/${localeName} '). Then (locale => {validator.localize (localeName, localeName). locale); }); }}); VueI18n integrated VeeValidate supports the VUE-i18n plug-in, considering that it is the most popular of vue.js localization solutions. We can integrate VueI18n into vee-validate by passing the i18N instance to the vee-validate configuration: import VeeValidate from 'vee-validate'; import Vue from 'vue'; import VueI18n from 'vue-i18n'; import validationMessages from 'vee-validate/dist/locale/en'; Vue.use(VueI18n); const i18n = new VueI18n(); Use (VeeValidate, {// customize root path of validationMessages i18nRootkey: 'validations', i18n, dictionary: {en: validationMessages}}); When we pass the dictionary to the configuration, it is merged with our I18N locale message. After installing the plug-in, we should only set the locale using the i18N instance, which means: // Fail and return a warning this.$validator.locale = 'ar'; $i18n.locale = 'ar'; Warning: When using vee-validate and I18N, you may encounter warnings because vee-validate leaves a fallback mechanism for the I18N plug-in that can be safely ignored. We can by setting the i18n silentTranslationWarn (https://kazupon.github.io/vue-i18n/api/#silenttranslationwarn) configuration silence these warnings (silence Them). Custom I18N drivers Our application may have used a different I18N system, vee-validate internally using the driver to generate its messages. To avoid having to maintain two different localized drivers, we can easily integrate our custom drivers into vee-validate. We need to create an object that implements the 'IDictionary interface '. After installing the plug-in, you can apply the new driver to vee-validate. import Vue from 'vue'; import VeeValidate from 'vee-validate'; Vue.use(VeeValidate); Const dictionary = {// our implementation}; VeeValidate.setI18nDriver('custom', dictionary);Copy the code

Vee-validate contains several Flags that help us improve the user experience. Each validation field has its own set of Flags:

Pristine - Indicates that the field is touched or focused untouched - indicates that the field is not touched or focused untouched - Pristine - Indicates that the field is not operated on Valid - Indicates that the field has been validated invalid - Indicates that the field has failed to be validated Pendding - Indicates that the field is being validated - Indicates that validate() or validateAll() has been called manually or through an event Method that has been validated at least once changed - indicates that the value of the field has been changed. These representations are reactive objects, so we can construct computed properties (VUE's computeDs) based on them. For example, here's how to tell if a form has been manipulated, perhaps by 'disabling/enabling' a button export Default {computed: { isFormDirty(){ return Object.keys(this.fields).some(key => this.fields[key].dirty); }} global field flags can be accessed through the following objects: // Whether the 'name' field has been contaminated (operated on) this.fields.name.dirty; For scoped fields, however, FieldBag will group those fields with attribute names prefixed with '$' to indicate that it is a scoped object: // Whether the 'name' field is contaminated (dirty) this.fields.$myscope.name.dirty; Error-form; // Error-form; // error-form; // Error-form; // Error-form; Here's an example of it:  <div class="form-input"> <input type="text" name="email" v-validate="'required|email'" placeholder="Email"> <span v-show="errors.has('field')">{{ errors.first('field') }}</span> <span v-show="fields.email && fields.email.dirty">I'm Dirty</span> <span v-show="fields.email && fields.email.touched">I'm touched</span> <span v-show="fields.email && fields.email.valid">I'm valid</span> </div> <div class="form-input"> <input data-vv-scope="scope" type="text" name="email" v-validate="'required|email'" placeholder="Email"> <span v-show="errors.has('scope.field')">{{ errors.first('scope.field') }}</span> <span v-show="fields.$scope && fields.$scope.email && Fields.$scope.email.dirty">I'm dirty </span> </div> Note that additional checks are done before the actual flag check, because flags are not actually available before the mount() life cycle event, so we need to add these checks to avoid a Created () life cycle error. PS: The so-called extra check is the above: Check fields.email first, then fields.email.dirty, Fields.$scope && fields.$scope.email && fields.$scope.email These checks can become cumbersome if we refer to multiple flags, so it can be useful to use the mapFields helper, which is similar to Vuex's mapGetters and mapActions in that it maps a field object to a calculated property. import { mapFields } from 'vee-validate' export default { // ... computed: mapFields(['name', 'email', 'scope.phone']), // ... } We can also provide an object to rename the attributes of the map: import {mapFields} from 'vee-validate' export default {computed: mapFields({fullName: 'name', phone: 'scope.phone'}),} Note: The named scope field in the array is mapped to a non-nested name we can use the object's 'extension operator '(...) , add the fields to be mapped to the existing computing component: import {mapFields} from 'vee-validate' export default {computed: {... MapFields (['name', 'email', 'scope.phone']), myProp(){}},} $validator.flag('field', {valid: false, dirty: true}); $validator.flag('scoped. Field ', {touched: false, dirty: false}); // Set the scope field flag for this. For custom components, in order for the flags to work completely reliably, we need to emit the following events: the input event (which we might have emitted), which sets the dirty and pristine flags. this.$emit('input', value); // Focus will set the touched and untouched flags this.$emit('focus');Copy the code

Validation Events Vee-validate listens for a specific set of Events on our input field that, when fired, trigger Validation for that field. By default, vee-validate listens for input events.

If input event validation is too aggressive for the user, we can choose another trigger (like: change) to trigger the validation. We can configure the default event listening for vee-validate and even specify specific events for specific fields. Change the default event vue. use(VeeValidate, {events: 'change'}); If we want to listen for multiple events, including custom events. Only need to use a use '|' separate event list: Vue. Use (VeeValidate, {events: 'change | custom'}); We can use the 'data-vv-validate-on' attribute with the same value as the events configuration to specify the event for field validation: < input name = "field" v - validate = "' required '" data - vv - validate - on =" change | custom "> disable event validation We may wish to disable triggered by events of all validation, for instance, We only want to validate after the user clicks the submit button, which we can do by specifying an empty string for events that will disable all listeners for all fields. Vue.use('VeeValidate', { events: '' }); Or use the '.disable' modifier on the 'V-validate' directive to disable event validation for the specified field <input name="field" V-validate. disable="'required'"> Later in our code, Once the user submits the form, you can invoke this.$validator.validate() to trigger validation: export default {//... methods: { onSubmit () { this.$validator.validate().then(result => { if (! Result) {// If not, do some hints}}); }} / /... }Copy the code

A common scenario is to use V-if to display one or two fields based on certain conditions. For example, if the user is from the United States, a ‘state’ field is Displayed. If not, hide it. Or use V-for to generate a list of inputs from JSON data. This is fully supported by vee-validate, with one caveat.

Here is a reference from the Vue document to 'reuse of input fields' : Vue renders elements as efficiently as possible, often reusing existing elements rather than rendering them from scratch. This has other benefits besides making Vue very fast. The official example uses the following template:  <template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username"> </template> <template V-else > <label>Email</label> <input placeholder="Enter your Email address"> </template> Handle V-if When trying to verify these inputs, it appears that vee-validate assumes they are the same, depending on the input that was originally rendered. This is because Vue actually reuses input, and vee-validate does not know that input has been switched due to certain restrictions in the Directive API (v-validate is a component). So we need to help it by using the key attribute on the input, which forces Vue to render these elements independently. <template v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </template> <template v-else> <label>Email</label> <input placeholder="Enter your email address" Key ="email-input"> </template> Now, verify that these fields will work as expected, just remember that the key attribute of the different fields should be unique. Handling V-for Using index as a key in V-for is not sufficient because adding/removing entries causes some fields to occupy the keys of other fields. Therefore, in the case of user interaction adding/removing fields, the following does not work:  <div v-for="(input, idx) in inputs" :key="idx"> <label>Username</label> <input placeholder="Enter your username" key="username-input"> </div> To fix this, try to generate a unique ID for each key in the loop:  <div v-for="input in inputs" :key="input.id"> <label>Username</label> <input placeholder="Enter your username" Key ="username-input"> </div> Here is a basic ID generator: let ID = 0; export default { data: () => ({ inputs: [] }), methods: { addInput () { this.inputs.push({ id: id, value: null }); // The ID +1 ID ++ of the input field created next; }}}; This ensures that each created field is completely separate and Vue does not attempt to reuse them. Tip: We might actually want Vue to reuse these Inputs to ensure that we handle the key attribute correctly in our own project environment.Copy the code

These libraries/helpers make vee-validate and our favorite UI libraries/toolkits a breeze to use together.

Element vee - element element for vee - element - the element - https://github.com/davestewart/vee-element https://github.com/ElemeFE/elementCopy the code

Components

Validation Components
	提示:
		该功能 v2.1.0 以后可用

	VeeValidate 附带了更高级用例的组件。这些组件提供了一种不同的验证方法,使用 'scoped slots'(范围插槽) 功能来传递验证状态和结果。

	当前有2个组件:
		ValidationProvider
		ValidationObserver

Validation Provider
	ValidationProvider 组件是一个常规组件,它包装了我们的 inputs 输入框,并使用 scoped slogs(作用域插槽) 提供验证状态。

	使用 ValidationProvider 为每个字段验证状态,提供了隔离的作用域,并且不会在其插槽外,注入/改变任何内容。我们可以导入它并在需要时随时使用。使用验证上下文,允许我们应用类、标志以及传递状态给我们的模板。

	下面是一个简单的示例:

		<template>
			<div>
				<ValidationProvider rules="required">
					<div slot-scope="{ errors }">
						<input v-model="value" type="text">
						<span id="error">{{ errors[0] }}</span>
					</div>
				</ValidationProvider>
			</div>
		</template>

		<script>
			import { ValidationProvider } from 'vee-validate';

			export default {
				components: {
					ValidationProvider
				}
			};
		</script>

	它也适用于自定义组件,并解决了由于指令限制而难以正常实现的自我验证组件的认证问题。

	提示:
		要验证的字段必须具有 v-model 指令,以便该组件可以正确识别被验证的元素/组件。

	作用域插槽数据
		传递给作用域插槽的对象称为 validation context(验证上下文),它具有以下属性:

			名称 - 类型 - 描述
			errors - string[] - 错误消息列表
			valid - boolean - 当前认证状态
			flags - {[x: string]: boolean} - 映射对象状态的状态
			aria - {[x: string]: string} - 映射 aria 属性的对象。
			classes - {[x: string]: boolean} - 映射基于验证状态配置的类的对象。

		由于插槽作用域可以利用 ES6 的析构功能,(我们可以选择性地使用任何这些属性,并把我们觉得合适的属性传递给我们的插槽模板) | (我们可以选择加入任何这些属性,并根据需要传递给我们的插槽模板。)。上面的例子只需要 errors 数组。

	示例
		之前的简单示例验证简单的 HTML inputs 输入框,让我们提升一个档次,验证流行的第三方组件,例如:Vuetify's TextInput(https://vuetifyjs.com/en/components/text-fields)。

		基本示例:
			这会将错误消息传递给 Vuetify's 的文本字段组件。

				<ValidationProvider rules="required">
				  <VTextField slot-scope="{ errors }" v-model="value" :error-messages="errors" />
				</ValidationProvider>

			提示:
				ValidationProvider 是一个无渲染组件,意味着它不会渲染任何自己的内容。它只渲染其插槽,因此我们的插槽中只能有一个根元素,如果我们使用 template 标签,则可能导致渲染错误。

		手动验证
			在任何 providers 上触发验证都很简单,但它是选择性的。意味着我们需要显式调用 provider 实例上的验证。使用 refs 和公共方法 validate 以及 applyResult 使得这个过程变得轻而易举。

				<template>
					<div>
						<ValidationProvider rules="required" ref="myinput">
							<VTextField slot-scope="{ errors }" v-model="value" :error-messages="errors" />
						</ValidationProvider>

						<v-btn @click="validateField('myinput')" >Submit</v-btn>
					</div>
				</template>

				<script>
				export default {
					// ...
					methods: {
						validateField (field) {
							const provider = this.$refs[field];

							// 验证字段,但是不改变字段的状态
							provider.validate().then(
								// 改变状态
								provider.applyResult
							);
						}
					},
					// ..
				};
				</script>

			提示:
				使用同样的方式,我们可以使用公共方法 reset() 来重置 provider 的验证状态。

		input 输入框组
			类似单选框或复选框(有时),某些 inputs 输入框的行为类似单个 input 输入框。我们可以将整个 inputs 输入框组,包装在单个 Validation provider 组件中,并给它们相同的 v-model。我们可以在 Validation provider 组件中组合任意多的 inputs 输入框。

				<ValidationProvider rules="required">
				  	<div slot-scope="{ errors }">
					    <input type="radio" v-model="drink" value="">
					    <input type="radio" v-model="drink" value="coffe">
					    <input type="radio" v-model="drink" value="coke">
				  	</div>
				</ValidationProvider>

		需要确认的/基于目标的验证
			使用指令时,confirmed 规则把 '匹配到 ref 的其他字段' 作为目标对象。而使用 ValidationProvider 稍有不同,它会查找 '匹配到 vid 属性的其他 provider 组件' 作为目标对象,vid 属性可以是数字或字符串。

				<ValidationProvider rules="required|confirmed:confirm">
				  	<VTextField slot-scope="{ errors }" v-model="password" type="password" :error-messages="errors" />
				</ValidationProvider>

				<ValidationProvider vid="confirm" rules="required">
				  	<VTextField slot-scope="{ errors }" v-model="passwordConfirm" type="password" :error-messages="errors" />
				</ValidationProvider>

	重构 Validation Providers
		ValidationProvider 虽然有它的优点,但它比使用指令更冗长,并且在创建大型表单时非常烦人,有几种方法可以解决这个问题。

		创建高阶组件
			React中的一个常见模式是,使用高阶组件来生成行为略有不同的新组件。除了使用 props/events 来传递状态,它类似于为我们的组件创建包装器或 mixin。

			withValidation 方法接收一个组件,并创建一个启用了验证行为的新组件。让我们使用该方法,来创建一个 VTextFieldWithValidation 组件:
				import { withValidation } from 'vee-validate';
				import { VTextField } from 'vuetify/lib';

				const VTextFieldWithValidation = withValidation(VTextField, ({ errors }) => ({
				  	'error-messages': errors
				}));

				export default {
				  	components: {
				    	VTextFieldWithValidation
				  	}
				};

			提示:
				注意,第二个参数是一个函数,它将验证上下文转换为 props 对象,传递给包装的组件。在本例中,我们希望将 errors 数组作为 error-messages 属性传递给 VTextField 组件。

			以这种方法,最后一个例子变成如下内容:

				<VTextFieldWithValidation rules="required|confirmed:confirm" v-model="password" />

				<VTextFieldWithValidation vid="confirm" rules="required" v-model="password" />

			警告:
				这种方法有一些缺点,例如,如果被包装的组件接受与 ValidationProvider 组件同名的 props - 虽然它会接收它们 - 它可能是不同的类型,可能会导致严重的问题。HOCs 的问题是,我们需要了解底层的组件实现,对于第三方组件,这可能是个问题。

		手动包装组件
			相反,我们可以使用 ValidationProvider 将字段组件包装在新组件中。这更加简单灵活,而且不会有任何 HOC 问题。

			考虑这个新的 VTextFieldWithValidation 组件

				<template>
				  	<ValidationProvider :rules="rules">
				    	<VTextField slot-scope="{ errors }" v-model="innerValue" :error-messages="errors" />
				  	</ValidationProvider>
				</template>

				<script>
					import { ValidationProvider } from 'vee-validate';

					export default {
					 	props: {
						    rules: [String],
						    value: null
					  	},
					  	components: {
				    		ValidationProvider
					  	},
					  	data: () => ({
					  		innerValue: null
					  	}),
					  	watch: {
					  		innerValue (val) {
						  	    this.$emit('input', val);
					  		}
					  	}
					};
				</script>

			理想情况下,我们将所需的 props 传递给 ValidationProvider 或被验证的 VTextField,这种方法可以解决冗长的问题,同时保留简单的作用域插槽 API。它还允许我们在没有冲突问题(与 HOC 不同)的情况下分发 props。

			使用哪种一种方法取决于我们

		参考
			以下是 ValidationProvider 的公共 API 参考

			Props
				以下所有的 props 都是可选的

				Prop - 类型 - 默认值 - 描述
				rules - string - undefined - 验证规则
				vid - string - 自增数字 - 用于 '基于目标/跨字段' 规则的标识符
				immediate - boolean - false - 是否在渲染(初始)之后立即验证该字段
				events - string[] - ['input'] - 将触发验证的事件
				name - string - undefined - 一个字符串,用于替换错误消息和自定义错误消息中的 {field}
				bails - boolean - true - 如果设置为 true,验证会在第一次验证失败后停止
				debounce(消抖) - number - 0 - 验证消抖,指定的毫秒数

		Methods
			这些是公共使用的、仅有的方法,其他可能存在于 ValidationProvider 的方法,是严格内部的。

				Method - 参数 - 返回值 - 描述
				validate - void - Promise<ValidationResult> - 根据定义的规则对当前值进行验证。不会改变验证状态
				applyResult - ValidationResult - void - 获取验证结果对象,并将其应用于当前状态
				reset - void - void - 重置验证状态

			Events
				validation provider 不会 emit 任何事件。

Validation Observer
	使用 providers 进行验证非常方便,但它引入了一些自己的使用问题,例如,我们如何知道当前状态。比方说,我们想要禁用一个按钮,只要表单无效,就一直禁用该按钮,我们会怎么做?

	ValidationObserver 是一个方便的组件,它也使用了 '作用域插槽' 功能来沟通 inputs 整体的当前状态。

	下面是一个小的示例,同样是由 Provider 的 wrap 方法包装的 Vuetify 组件:

		<ValidationObserver>
		  	<form slot-scope="{ invalid }" @submit.prevent="submit">
		    	<InputWithValidation rules="required" v-model="first" :error-messages="errors" />

		    	<InputWithValidation rules="required" v-model="second" :error-messages="errors" />

		    	<v-btn :disabled="invalid">Submit</v-btn>
		 	</form>
		</ValidationObserver>

	提示:
		ValidationObserver 是一个无渲染组件,意味着它不会渲染任何自己的内容。它只渲染其插槽,因此我们的插槽中只能有一个根元素,如果我们使用 template 标签,则可能导致渲染错误。

	作用域插槽数据
		给作用域插槽传递一个包含了 flags 对象的对象,该对象表示在 observer 下注册的所有 providers 的合并状态。它包含以下属性:

			名称 - 类型 - 描述
			dirty - boolean - 如果至少有一个字段是 dirty,则为 true
			pristine - boolean - 如果所有字段是 pristine(非 dirty),则为 true
			valid - boolean - 如果所有字段是有效的,则为 true
			invalid - boolean - 如果至少有一个字段是无效的,则为 true
			pending - boolean - 如果至少有一个字段正在验证过程中,则为 true
			touched - boolean - 如果至少有一个字段被 touched(blurred - 获取过焦点),则为 true
			untouched - boolean - 如果所有字段都没有被 touched(blurred - 获取过焦点),则为 true
			errors - { [x:string]: string[] } - 一个包含了对每个字段错误的引用的对象,每个字段的 key 是它的 'vid' prop。

	示例:
		提交前验证
			提交前验证比旧的方式更容易,使用公共方法和一个简单的 ref,我们可以在提交表单之前验证所有的 providers。

				<template>
				  	<ValidationObserver ref="observer">
				    	<form slot-scope="{ invalid }" @submit.prevent="submit()">
				      		<InputWithValidation rules="required" v-model="first" :error-messages="errors" />

				      		<InputWithValidation rules="required" v-model="second" :error-messages="errors" />

				      		<v-btn :disabled="invalid">Submit</v-btn>
				    	</form>
				  	</ValidationObserver>
				</template>

				<script>
					export default {
					  	methods: {
					    	async submit () {
					      		const isValid = await this.$refs.observer.validate();
					      		if (!isValid) {
					        		// ABORT!!
					      		}

					      		// ? ship it
					    	}
					  	}
					};
				</script>

			提示:
				使用同样的方式,我们可以使用公共方法 reset() 来重置 provider 的验证状态。

		作用域和组
			验证组件 API 没有实现作用域,而且将来也不打算实现,我们可以使用 ValidationObserver,通过使用多个 observers 和 refs,将我们的字段进行分组,而没有作用域 API 的复杂性。

				<template>
				  	<div>
				    	<ValidationObserver ref="obs1">
				      		<div slot-scope="{ invalid }">
				       			<!-- Fields -->
				      		</div>
				    	</ValidationObserver>

				    	<ValidationObserver ref="obs2">
				      		<div slot-scope="{ invalid }">
				        		<!-- Fields -->
				      		</div>
				    	</ValidationObserver>
				  	</div>
				</template>

				<script>
					// 在一个方法的某处 ...
					// 验证第一个 observer.
					this.$refs.$obs1.validate();

					// 验证第二个 observer.
					this.$refs.$obs2.validate();
				</script>

			简单干净。

	参考
		下面是 ValidationObserver 公共 API 的参考

		Props
			validation observer 不接收任何的 props。

		Methods
			这些是公共使用的、仅有的方法,其他可能存在于 ValidationProvider 的方法,是严格内部的。

				Method - 参数 - 返回值 - 描述
				validate - void - Promise<boolean> - 验证所有子 providers,并改变它们的状态
				reset - void - void - 重置所有子 providers 的验证状态

		Events
			验证 observer 不会 emit 任何事件。
Copy the code