preface

I haven’t written an article for a long time, I have learned some basic components of Webpack, today I bring a tutorial on the form validation component (element.iviewui) (as a vegetables after all experienced many projects can give some novice tips

Github Technical Documentation the technical documentation will be updated continuously


Contents summary

  1. Principles of interpretation
  2. Distribution and broadcast // Parent-child interaction
  3. Async-validator // Form validation plugin introduced
  4. Form/and API design
  5. form-item
  6. input

rendering

1. Principle explanation

consider

So let’s see, we can use forms to trigger validation as a whole or we can use individual input to trigger form-Item validation and if you don’t understand this right now, it’s okay to keep reading.

Distribution and broadcasting

Why broadcast and distribute. In general we try not to use VUEX and BUS (event bus) for components that are not relevant to the business. I send you the code for broadcast and distribution. $emit is sent and broadcast by attaching this.$on(‘event’,res=>()) to the component we want to call.

  1. Dispatch is to look up and only call 1
  2. Broadcasts are called down multiple times
  3. Note that ⚠️ is used for all componentsname
  4. Through mixermixinsTo use the
Emitters. Js /** * This is called * @param componentName * @param eventName Broadcast (componentName, eventName, This.$children.map(Child =>{if (componentName===child.$options.name) {componentName=== component.$options.name) { child.$emit.apply(child,[eventName].concat(params)) }else { broadcast.apply(child,[componentName,eventName].concat(params)) } }) } export default { methods: @param eventName @param eventName @param Params @param eventName @param Params @param eventName @Param Params @param eventName dispatch(componentName, eventName, params) { let parent = this.$parent || this.$root; Let name = parent.$options.name; // Get the name of the current component instance // Find the current node if the current node has no name and the current name is equal to the name that needs to be passed in // loop out the same component instance of the current name while (parent && (! name||name! ==componentName)) { parent = parent.$parent; if (parent) { name = parent.$options.name; If (parent) {parent.$emit. Apply (parent,[eventName].concat(params))}}, @param eventName / @param eventName / @param Params // Parameters to pass */ broadcast(componentName, eventName, params) { broadcast.call(this,componentName, eventName, params) } } }Copy the code

3.async-validator

If you don’t understand Async-Validator, check out Github

Yarn add Async-validator // -d cannot be added because the plugin needs to be packaged into the projectCopy the code

4. API design

Take a look at the image on Element’s website below

  1. formThere are two injected fields:rulesThe rules, and:modelThe current form value passesmodelThe value of andrulesPerform a match to verify.
  2. form-itemThere are two injected fieldslableandprop(propCome andformMatches to get the currentform-itemThe value of the
  3. inputThere’s actually a current@inputMethods.v-modelI won’t explain it

form

  1. We are informStart by injecting all the current onesform-itemInstance (get)
  2. createdMethods that bind and delete the current instance at the beginning of the life cycle. Usually bindings are invoked before the page DOM startsdomAfter loading
  3. provideInject uses methods and data that allow child components to call the current parent
  4. The remarks below have been written, which can be safely eaten (it can be verified after testing).
form.vue <template> <form> <slot></slot> </form> </template> <script> export default { name: "AiForm dojo.provide () {/ / / don't understand can look at (https://cn.vuejs.org/v2/api/#provide-inject) return {form: this}}, props: Rules: {type: Object}}, data(){return{fields: Create (){// create (){// create (); this.$on('on-form-item-add',item=>{ if (item) { that.fields.push(item) } }); Some examples of this. / / delete the current $on (' on - form - item - remove 'item = > {the if (item. Prop) {/ / if the current do not prop said current don't delete, because there is no injection) that.fields.splice(that.fields.indexOf(item),1) } }) }, Methods :{/** * resetFields(){// resetFields(){// resetFields(){// resetFields(){// resetFields();  { field.resetField(); }); }, /** * check public method: Return new Promise(resolve=>{/** ** all form-item validates */ let valid = true; // Default is let count = 0; Validation ('',error=>{// Each instance will have validation methods If (error) {valid = false; } // If (++count === this.fields.length) {resolve(valid); if (++count === this.fields.length) {resolve(valid); Then if (typeof callback === 'function') {callback(valid); // Call the injected callback method directly}}}); }); }) } } } </script>Copy the code

5.form-item

  1. form-itemIt’s a little bit more complicated and we’ll do it one by one
  2. isRequiredTo determine whether it is currently required
  3. validateStateTo determine the status of the current checksum
  4. validateMessageCurrent incorrect value
  5. inject: ['form']We can passthis.from.xxxTo call the event and value of the parent component
  6. computedUnder thefieldValueMaybe it’s changing all the time so we use it by calculating the properties
  7. initialValueThe default values we have inmountedAnd is currently required to perform verification (propSometimes) will be assigned
  8. mixins: [Emitter]The mixer is the method that’s in there and the date that’s in there and the one that’s used frequently can be in there
  9. weform-itemWill be introduced toinputTwo methods ofblurandchangeInput used natively@input) byformIncoming checkrulesThe inside of thetriggerTo judge
form-item.vue <template> <div> <label :class="isRequired? 'ai-form-item-label-required':''">{{label}}</label> <div> <slot></slot> <div class="ai-form-item-message" v-if="validateState==='error'">{{validateMessage}}</div> </div> </div> </template> <script> import Emitter from '.. /.. /mixins/emitter'; import schema from 'async-validator'; export default { name: "aiFormItem", mixins: [Emitter], inject: ['form'], props: { label: { type: String, default: '' }, prop:{ type: String }, }, computed:{ fieldValue () { return this.form.model[this.prop]; },}, data(){return {initialValue: ", // Save default isRequired: false, // If there is a problem with the current validateState: }}, methods:{/** * binding events required */ setRules(){let that = this; let rules = this.getRules(); If (rules.length) {// every is used to check whether all elements of the array meet the specified criteria (provided by the function) // some returns true this.isrequired = if only one element meets the specified criteria Rules.some (rule=>{// If the current verification rule contains a mandatory item, return rule. })} / * * * * the blur event/enclosing $on (' on - form - the blur, that. OnFieldBlur); $on('on-form-change', that.onfieldchange)}, /** * from the rules attribute of the form, */ getRules () {let that = this; let rules = that.form.rules; rules = rules? rules[that.prop]:[]; Return [] concat (rules | | []) / / this method can make the rules must be}, in the form of an array to form validation * / / * * * the Blur onFieldBlur () {enclosing the validation (' Blur ')}, / / onFieldChange(){this.validation('change')}, */ getFilteredRule (trigger) {let rules = this.getrules (); / /! Return rules.filter(res=>! res.trigger || res.trigger.indexOf(trigger)! = = 1)}, Validation (trigger,callback=function () {}){// blur and change Let rules = this.getFilteredRule(trigger); // Check whether there is a rule if (! Rules | | rules. The length = = = 0) {return} / / set the status to check in / / async - use form of the validator enclosing validateState = 'validating'; var validator = new schema({[this.prop]: rules}); // firstFields: true validates only one validator. Validate ({[this.prop]: this.fieldValue}, {firstFields: true },(errors, fields) => { this.validateState = ! errors ? 'success' : 'error'; this.validateMessage = errors ? errors[0].message : ''; callback(this.validateMessage); }); }, /** * Empty the current form-item */ resetField(){this.form.model[this.prop] = this.initialValue; // Mounted (){// If a prop is not passed, no validation is required. If (this.prop) {this.dispatch('aiForm','on-form-item-add', this); if (this.prop) {this.dispatch('aiForm','on-form-item-add', this); // set the initialValue so that the default value this.initialValue = this.fieldValue is restored on reset; // add forms to validate this.setrules ()}}, // before component destruction, Remove instance from Form cache beforeDestroy(){this.dispatch('iForm', 'on-form-item-remove', this); }, } </script> <style scoped> <! Ai-form-item-label-required :before{content: '*'; color: red; } .ai-form-item-message { color: red; } </style>Copy the code

5.input

  1. valueOne input parameter is supported
  2. Because the current is oneinputInjected parameters cannot be placed directlyinputIt’s used inside so it’s assigned todefaultValueAnd then usewatchTo keep todefaultValueAssignment reaches a binding modified by a parent component
<template> <input type="text" @input="handleInput" // change @blur="handleBlur" :value="defaultValue" > </template> <script> import Emitter from '.. /.. /mixins/emitter.js' export default { name: "aiInput", mixins: [Emitter], props: { value: { type: String, default: '' } }, data(){ return { defaultValue: this.value } }, watch:{ value (val) { this.defaultValue = val; }}, Methods :{/** * change event * @param event */ handleInput(event){// Current model assignment this.defaultValue = event.target.value; $emit('input',event.target.value); $emit('input',event.target.value); This. dispatch('aiFormItem','on-form-change',event.target.value)}, $emit('blur',event.target.value); $emit('blur',event.target.value); This. dispatch('aiFormItem','on-form-blur',event.target.value)}}} </script>Copy the code

The last

Finally, give a current available mode of use

<template> <div class="home"> <button @click="changeButton"> </button> <ai-form ref="formItems" :model="formValidate" :rules="ruleValidate"> <ai-form-item label=" user name" prop="name"> < AI-input v-model=" formvalidate. name"/> </ai-form-item> </ai-form> </div> </template> <script> import AiForm from ".. /components/form/form"; import AiFormItem from ".. /components/form/form-item"; import AiInput from ".. /components/input/ai-input"; export default { name: 'home', components: {AiInput, AiFormItem, AiForm},], data(){ return{ formValidate: { name: '123z', mail: "}, ruleValidate: {name: [{required: true, message: 'user name cannot be empty ', trigger: 'blur' }, ], } } }, Methods: {changeButton () {this. $refs. FormItems. ResetFields method () / / clear this. $refs. FormItems. The validate () / / verification method .then(res=>{ console.log(res) }) } }, } </script>Copy the code

summary

May now small partners still do not understand. As the saying goes. Master led the door, practice in the individual. There are enough notes in the code. If you still don’t know, you can ask your friends,

Seek to rely on the spectrum push (Beijing area) can leave a message I +. =