溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

vue怎么表單驗(yàn)證validate

發(fā)布時(shí)間:2021-09-10 18:29:50 來(lái)源:億速云 閱讀:1867 作者:柒染 欄目:web開(kāi)發(fā)

vue怎么表單驗(yàn)證(form)validate,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

vue怎么表單驗(yàn)證validate 

1.原理解釋

vue怎么表單驗(yàn)證validate

考慮

我們看一下我們可以用form去整體觸發(fā)校驗(yàn)也可以單個(gè)input來(lái)觸發(fā)form-item 進(jìn)行校驗(yàn) 童鞋們現(xiàn)在可能感覺(jué)還是沒(méi)懂,沒(méi)關(guān)系繼續(xù)往下看。

2.派發(fā)和廣播

為什么要用廣播和派發(fā)呢。通常我們和業(yè)務(wù)沒(méi)有關(guān)系的組件盡量不要使用vuex和bus(事件總線)。 下面我送上廣播和派發(fā)的代碼。我們?cè)谛枰{(diào)用組件綁上 this.$on('event',res=>()) ,通過(guò)派發(fā)和廣播進(jìn)行調(diào)用 $emit 。

  • 派發(fā)是向上查找且只調(diào)用1個(gè)

  • 廣播是向下查找調(diào)用多個(gè)

  • 注意??所有的組件都要寫(xiě)上name

  • 通過(guò)混合器 mixins 來(lái)使用

emitter.js
/**
 * 遞歸使用 call 方式this指向
 * @param componentName // 需要找的組件的名稱(chēng)
 * @param eventName // 事件名稱(chēng)
 * @param params // 需要傳遞的參數(shù)
 */
function broadcast(componentName, eventName, params) {
 // 循環(huán)子節(jié)點(diǎn)找到名稱(chēng)一樣的子節(jié)點(diǎn) 否則 遞歸 當(dāng)前子節(jié)點(diǎn)
 this.$children.map(child=>{
  if (componentName===child.$options.name) {
   child.$emit.apply(child,[eventName].concat(params))
  }else {
   broadcast.apply(child,[componentName,eventName].concat(params))
  }
 })
}
export default {
 methods: {
  /**
   * 派發(fā) (向上查找) (一個(gè))
   * @param componentName // 需要找的組件的名稱(chēng)
   * @param eventName // 事件名稱(chēng)
   * @param params // 需要傳遞的參數(shù)
   */
  dispatch(componentName, eventName, params) {
   let parent = this.$parent || this.$root;//$parent 找到最近的父節(jié)點(diǎn) $root 根節(jié)點(diǎn)
   let name = parent.$options.name; // 獲取當(dāng)前組件實(shí)例的name
   // 如果當(dāng)前有節(jié)點(diǎn) && 當(dāng)前沒(méi)名稱(chēng) 且 當(dāng)前名稱(chēng)等于需要傳進(jìn)來(lái)的名稱(chēng)的時(shí)候就去查找當(dāng)前的節(jié)點(diǎn)
   // 循環(huán)出當(dāng)前名稱(chēng)的一樣的組件實(shí)例
   while (parent && (!name||name!==componentName)) {
    parent = parent.$parent;
    if (parent) {
     name = parent.$options.name;
    }
   }
   // 有節(jié)點(diǎn)表示當(dāng)前找到了name一樣的實(shí)例
   if (parent) {
    parent.$emit.apply(parent,[eventName].concat(params))
   }
  },
  /**
   * 廣播 (向下查找) (廣播多個(gè))
   * @param componentName // 需要找的組件的名稱(chēng)
   * @param eventName // 事件名稱(chēng)
   * @param params // 需要傳遞的參數(shù)
   */
  broadcast(componentName, eventName, params) {
   broadcast.call(this,componentName, eventName, params)
  }
 }
}

3.async-validator

不懂 async-validator 可以去官網(wǎng)看看 github

yarn add async-validator // 因?yàn)楫?dāng)前這個(gè)插件是需要打包到項(xiàng)目里的所以不能加-D

4.api設(shè)計(jì)

我們看一下下面 element 官網(wǎng)的圖`

form 有2個(gè)注入的字段 :rules 規(guī)則,和 :model 當(dāng)前form的值會(huì)通過(guò) model 的值和 rules 進(jìn)行匹配來(lái)進(jìn)行校驗(yàn).

form-item 有2個(gè)注入的字段 lableprop ( prop )是來(lái)和 form 進(jìn)行匹配來(lái)獲取當(dāng)前的 form-item 的值的

input 其實(shí)有當(dāng)前的 @input 的方法。 v-model 就不解釋了

vue怎么表單驗(yàn)證validate 

form

我們?cè)?form 先開(kāi)始注入當(dāng)前所有的 form-item 實(shí)例(獲?。?/p>

created 會(huì)在生命周期開(kāi)始的時(shí)候綁定和刪除當(dāng)前實(shí)例的方法。通常綁定都在頁(yè)面dom開(kāi)始前調(diào)用需要在 dom 加載完

provide 配合inject 使用讓子組件可以調(diào)用當(dāng)前父組件的方法以及data

下面都寫(xiě)了備注可以放心食用(經(jīng)過(guò)測(cè)試當(dāng)前是可以進(jìn)行校驗(yàn)的)

form.vue
<template>
 <form>
  <slot></slot>
 </form>
</template>

<script>
 export default {
  name: "aiForm",
  provide(){ // [不懂的可以看看](https://cn.vuejs.org/v2/api/#provide-inject)
   return {
    form: this
   }
  },
  props: {
   // 當(dāng)前 form 的model
   model: {
    type: Object
   },
   // 驗(yàn)證
   rules: {
    type: Object
   }
  },
  data(){
   return{
    fields: [] // 儲(chǔ)存當(dāng)前的 form-item的實(shí)例
   }
  },
  created(){
   // 存當(dāng)前實(shí)例
   let that =this;
   this.$on('on-form-item-add',item=>{
    if (item) {
     that.fields.push(item)
    }
   });
   // 刪除當(dāng)前有的實(shí)例
   this.$on('on-form-item-remove',item=>{
    if (item.prop) {// 如果當(dāng)前沒(méi)有prop的話表示當(dāng)前不要進(jìn)行刪除(因?yàn)闆](méi)有注入)
     that.fields.splice(that.fields.indexOf(item),1)
    }
   })
  },
  methods:{
   /**
    * 清空
    */
   resetFields(){//添加resetFields方法使用的時(shí)候調(diào)用即可
    /**
     * 當(dāng)前所有當(dāng)form-item 進(jìn)行賦值
     */
    this.fields.forEach(field => {
     field.resetField();
    });
   },
   /**
    * 校驗(yàn) 公開(kāi)方法:全部校驗(yàn)數(shù)據(jù),支持 Promise
    */
   validate(callback){
    return new Promise(resolve=>{
     /**
      * 當(dāng)前所有當(dāng)form-item 進(jìn)行校驗(yàn)
      */
     let valid = true; // 默認(rèn)是通過(guò)
     let count = 0; // 來(lái)匹配當(dāng)前是否是全部檢查完
     this.fields.forEach(field => {
      // 每個(gè)實(shí)例都會(huì)有 validation 的校驗(yàn)的方法
      field.validation('',error=>{
       // 只要有一個(gè)不符合那么當(dāng)前的校驗(yàn)就是未通過(guò)的
       if (error) { 
        valid = false;
       }
       // 通過(guò)當(dāng)前檢查完所有的form-item的時(shí)候才會(huì)調(diào)用
       if (++count === this.fields.length) {
        resolve(valid);// 方法使用then
        if (typeof callback === 'function') {
         callback(valid);// 直接調(diào)用注入的回調(diào)方法
        }
       }
      });
     });
    })
   }
  }
 }
</script>

5.form-item

  •  form-item比較復(fù)雜我們一個(gè)一個(gè)講

  • isRequired來(lái)判斷當(dāng)前是否需要必填

  • validateState來(lái)判斷當(dāng)前校驗(yàn)的狀態(tài)

  • validateMessage當(dāng)前的錯(cuò)誤的值

  • inject: ['form'] 我們就可以通過(guò)this.from.xxx來(lái)調(diào)用父組件的事件以及值了

  • computed下的fieldValue可能在不停的變化所以我們通過(guò)計(jì)算屬性來(lái)使用

  • initialValue 默認(rèn)的值我們?cè)趍ounted的時(shí)候且當(dāng)前需要進(jìn)行校驗(yàn)的時(shí)候(prop有的時(shí)候)會(huì)賦值

  • mixins: [Emitter]混合器就是里面的方法以及date都可以在當(dāng)前調(diào)用使用頻繁的都可以放在混合器里面

  • 我們form-item 會(huì)傳入input的兩個(gè)方法blur和change(input原生使用的@input)通過(guò)form傳入的校驗(yàn)rules里面的trigger來(lái)判斷

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: '', // 儲(chǔ)存默認(rèn)值
    isRequired: false, // 當(dāng)前的是否有問(wèn)題
    validateState: '', // 是否校驗(yàn)成功
    validateMessage: '', // 校驗(yàn)失敗文案
   }
  },
  methods:{
   /**
    * 綁定事件 進(jìn)行是否 required 校驗(yàn)
    */
   setRules(){
    let that = this;
    let rules = this.getRules();//拿到父組件過(guò)濾后當(dāng)前需要使用的規(guī)則
    if (rules.length) {
     // every 方法用于檢測(cè)數(shù)組所有元素是否都符合指定條件(通過(guò)函數(shù)提供)
     // some 只要有一個(gè)符合就返回true
     this.isRequired = rules.some(rule=>{
      // 如果當(dāng)前校驗(yàn)規(guī)則中有必填項(xiàng),則標(biāo)記出來(lái)
      return rule.required;
     })
    }
    /**
     * blur 事件
     */
    this.$on('on-form-blur',that.onFieldBlur);
    /**
     * change 事件
     */
    this.$on('on-form-change',that.onFieldChange)
   },
   /**
    * 從 Form 的 rules 屬性中,獲取當(dāng)前 FormItem 的校驗(yàn)規(guī)則
    */
   getRules () {
    let that = this;
    let rules = that.form.rules;
    rules = rules?rules[that.prop]:[];
    return [].concat(rules||[])//這種寫(xiě)法可以讓規(guī)則肯定是一個(gè)數(shù)組的形式
   },
   /**
    * Blur 進(jìn)行表單驗(yàn)證
    */
   onFieldBlur(){
    this.validation('blur')
   },
   /**
    * change 進(jìn)行表單驗(yàn)證
    */
   onFieldChange(){
    this.validation('change')
   },
   /**
    * 只支持 blur 和 change,所以過(guò)濾出符合要求的 rule 規(guī)則
    */
   getFilteredRule (trigger) {
    let rules = this.getRules();
    // !res.trigger 沒(méi)有調(diào)用方式的時(shí)候默認(rèn)就校驗(yàn)的
    // filter 過(guò)濾出當(dāng)前需要的規(guī)則
    return rules.filter(res=>!res.trigger || res.trigger.indexOf(trigger)!==-1)
   },
   /**
    * 校驗(yàn)數(shù)據(jù)
    * @param trigger 校驗(yàn)類(lèi)型
    * @param callback 回調(diào)函數(shù)
    */
   validation(trigger,callback=function () {}){
    // blur 和 change 是否有當(dāng)前方式的規(guī)則
    let rules = this.getFilteredRule(trigger);
    // 判斷當(dāng)前是否有規(guī)則
    if (!rules || rules.length === 0) {
     return
    }
    // 設(shè)置狀態(tài)為校驗(yàn)中
    // async-validator的使用形式
    this.validateState = 'validating';
    var validator = new schema({[this.prop]: rules});
    // firstFields: true 只會(huì)校驗(yàn)一個(gè)
    validator.validate({[this.prop]: this.fieldValue}, { firstFields: true },(errors, fields) => {
     this.validateState = !errors ? 'success' : 'error';
     this.validateMessage = errors ? errors[0].message : '';
     callback(this.validateMessage);
    });
   },
   /**
    * 清空當(dāng)前的 form-item
    */
   resetField(){
    this.form.model[this.prop] = this.initialValue;
   }
  },
  // 組件渲染時(shí),將實(shí)例緩存在 Form 中
  mounted(){
   // 如果沒(méi)有傳入 prop,則無(wú)需校驗(yàn),也就無(wú)需緩存
   if (this.prop) {
    this.dispatch('aiForm','on-form-item-add', this);
    // 設(shè)置初始值,以便在重置時(shí)恢復(fù)默認(rèn)值
    this.initialValue = this.fieldValue;
    // 添加表單校驗(yàn)
    this.setRules()
   }
  },
  // 組件銷(xiāo)毀前,將實(shí)例從 Form 的緩存中移除
  beforeDestroy(){
   this.dispatch('iForm', 'on-form-item-remove', this);
  },
 }
</script>

<style scoped>
 <!--當(dāng)前css-->
 .ai-form-item-label-required:before{
  content: '*';
  color: red;
 }
 .ai-form-item-message {
  color: red;
 }
</style>

5.input

  •  value 支持一個(gè)入?yún)?/p>

  • 因?yàn)楫?dāng)前是一個(gè) input 注入的參數(shù)是不能直接放到 input 里面使用的所以先賦值給了 defaultValue 然后用 watch 來(lái)不停給 defaultValue 賦值達(dá)到一個(gè)父組件修改后的一個(gè)綁定

<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 事件
   * @param event
   */
   handleInput(event){
    // 當(dāng)前model 賦值
    this.defaultValue = event.target.value;
    // vue 原生的方法 return 出去
    this.$emit('input',event.target.value);
    // 將當(dāng)前的值發(fā)送到 aiFormItem 進(jìn)行校驗(yàn)
    this.dispatch('aiFormItem','on-form-change',event.target.value)
   },
   /**
   * blur 事件
   * @param event
   */
   handleBlur(event){
    // vue 原生的方法 return 出去
    this.$emit('blur',event.target.value);
    // 將當(dāng)前的值發(fā)送到 aiFormItem 進(jìn)行校驗(yàn)
    this.dispatch('aiFormItem','on-form-blur',event.target.value)
   }
  }
 }
</script>

最后

最后給上一個(gè)當(dāng)前可以的使用方式

<template>
 <div class="home">
 <button @click="changeButton">測(cè)試</button>
 <ai-form ref="formItems" :model="formValidate" :rules="ruleValidate">
  <ai-form-item label="用戶名" 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: '用戶名不能為空', trigger: 'blur' },
    ],
   }
  }
 },
 methods:{
  changeButton(){
   this.$refs.formItems.resetFields() // 清空方法
   this.$refs.formItems.validate() // 驗(yàn)證方法
    .then(res=>{
     console.log(res)
    })
  }
 },
}
</script>

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI