vue表单验证你真的会了吗?vue表单验证(form)validate


Posted in Javascript onApril 07, 2019

前言

很久没有写文章了,学习了一下webpack,基础的一些组件,今天带来form表单验证组件(element.iviewui)的一期教程(作为一个菜鸡毕竟经历众多项目可以给一些新手一点提示 (QQ群技术讨论)838293023备注(github进来的

github 技术文档 技术文档会持续更新

效果图

vue表单验证你真的会了吗?vue表单验证(form)validate 

1.原理解释

vue表单验证你真的会了吗?vue表单验证(form)validate

考虑

我们看一下我们可以用form去整体触发校验也可以单个input来触发form-item 进行校验 童鞋们现在可能感觉还是没懂,没关系继续往下看。

2.派发和广播

为什么要用广播和派发呢。通常我们和业务没有关系的组件尽量不要使用vuex和bus(事件总线)。 下面我送上广播和派发的代码。我们在需要调用组件绑上 this.$on('event',res=>()) ,通过派发和广播进行调用 $emit

  • 派发是向上查找且只调用1个
  • 广播是向下查找调用多个
  • 注意⚠️所有的组件都要写上name
  • 通过混合器 mixins 来使用
emitter.js
/**
 * 递归使用 call 方式this指向
 * @param componentName // 需要找的组件的名称
 * @param eventName // 事件名称
 * @param params // 需要传递的参数
 */
function broadcast(componentName, eventName, params) {
 // 循环子节点找到名称一样的子节点 否则 递归 当前子节点
 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: {
  /**
   * 派发 (向上查找) (一个)
   * @param componentName // 需要找的组件的名称
   * @param eventName // 事件名称
   * @param params // 需要传递的参数
   */
  dispatch(componentName, eventName, params) {
   let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点
   let name = parent.$options.name; // 获取当前组件实例的name
   // 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
   // 循环出当前名称的一样的组件实例
   while (parent && (!name||name!==componentName)) {
    parent = parent.$parent;
    if (parent) {
     name = parent.$options.name;
    }
   }
   // 有节点表示当前找到了name一样的实例
   if (parent) {
    parent.$emit.apply(parent,[eventName].concat(params))
   }
  },
  /**
   * 广播 (向下查找) (广播多个)
   * @param componentName // 需要找的组件的名称
   * @param eventName // 事件名称
   * @param params // 需要传递的参数
   */
  broadcast(componentName, eventName, params) {
   broadcast.call(this,componentName, eventName, params)
  }
 }
}

3.async-validator

不懂 async-validator 可以去官网看看 github

yarn add async-validator // 因为当前这个插件是需要打包到项目里的所以不能加-D

4.api设计

我们看一下下面 element 官网的图`

form 有2个注入的字段 :rules 规则,和 :model 当前form的值会通过 model 的值和 rules 进行匹配来进行校验.

form-item 有2个注入的字段 lableprop ( prop )是来和 form 进行匹配来获取当前的 form-item 的值的

input 其实有当前的 @input 的方法。 v-model 就不解释了

vue表单验证你真的会了吗?vue表单验证(form)validate 

form

我们在 form 先开始注入当前所有的 form-item 实例(获取)

created 会在生命周期开始的时候绑定和删除当前实例的方法。通常绑定都在页面dom开始前调用需要在 dom 加载完

provide 配合inject 使用让子组件可以调用当前父组件的方法以及data

下面都写了备注可以放心食用(经过测试当前是可以进行校验的)

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: {
   // 当前 form 的model
   model: {
    type: Object
   },
   // 验证
   rules: {
    type: Object
   }
  },
  data(){
   return{
    fields: [] // 储存当前的 form-item的实例
   }
  },
  created(){
   // 存当前实例
   let that =this;
   this.$on('on-form-item-add',item=>{
    if (item) {
     that.fields.push(item)
    }
   });
   // 删除当前有的实例
   this.$on('on-form-item-remove',item=>{
    if (item.prop) {// 如果当前没有prop的话表示当前不要进行删除(因为没有注入)
     that.fields.splice(that.fields.indexOf(item),1)
    }
   })
  },
  methods:{
   /**
    * 清空
    */
   resetFields(){//添加resetFields方法使用的时候调用即可
    /**
     * 当前所有当form-item 进行赋值
     */
    this.fields.forEach(field => {
     field.resetField();
    });
   },
   /**
    * 校验 公开方法:全部校验数据,支持 Promise
    */
   validate(callback){
    return new Promise(resolve=>{
     /**
      * 当前所有当form-item 进行校验
      */
     let valid = true; // 默认是通过
     let count = 0; // 来匹配当前是否是全部检查完
     this.fields.forEach(field => {
      // 每个实例都会有 validation 的校验的方法
      field.validation('',error=>{
       // 只要有一个不符合那么当前的校验就是未通过的
       if (error) { 
        valid = false;
       }
       // 通过当前检查完所有的form-item的时候才会调用
       if (++count === this.fields.length) {
        resolve(valid);// 方法使用then
        if (typeof callback === 'function') {
         callback(valid);// 直接调用注入的回调方法
        }
       }
      });
     });
    })
   }
  }
 }
</script>

5.form-item

  •  form-item比较复杂我们一个一个讲
  • isRequired来判断当前是否需要必填
  • validateState来判断当前校验的状态
  • validateMessage当前的错误的值
  • inject: ['form'] 我们就可以通过this.from.xxx来调用父组件的事件以及值了
  • computed下的fieldValue可能在不停的变化所以我们通过计算属性来使用
  • initialValue 默认的值我们在mounted的时候且当前需要进行校验的时候(prop有的时候)会赋值
  • mixins: [Emitter]混合器就是里面的方法以及date都可以在当前调用使用频繁的都可以放在混合器里面
  • 我们form-item 会传入input的两个方法blur和change(input原生使用的@input)通过form传入的校验rules里面的trigger来判断
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: '', // 储存默认值
    isRequired: false, // 当前的是否有问题
    validateState: '', // 是否校验成功
    validateMessage: '', // 校验失败文案
   }
  },
  methods:{
   /**
    * 绑定事件 进行是否 required 校验
    */
   setRules(){
    let that = this;
    let rules = this.getRules();//拿到父组件过滤后当前需要使用的规则
    if (rules.length) {
     // every 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)
     // some 只要有一个符合就返回true
     this.isRequired = rules.some(rule=>{
      // 如果当前校验规则中有必填项,则标记出来
      return rule.required;
     })
    }
    /**
     * blur 事件
     */
    this.$on('on-form-blur',that.onFieldBlur);
    /**
     * change 事件
     */
    this.$on('on-form-change',that.onFieldChange)
   },
   /**
    * 从 Form 的 rules 属性中,获取当前 FormItem 的校验规则
    */
   getRules () {
    let that = this;
    let rules = that.form.rules;
    rules = rules?rules[that.prop]:[];
    return [].concat(rules||[])//这种写法可以让规则肯定是一个数组的形式
   },
   /**
    * Blur 进行表单验证
    */
   onFieldBlur(){
    this.validation('blur')
   },
   /**
    * change 进行表单验证
    */
   onFieldChange(){
    this.validation('change')
   },
   /**
    * 只支持 blur 和 change,所以过滤出符合要求的 rule 规则
    */
   getFilteredRule (trigger) {
    let rules = this.getRules();
    // !res.trigger 没有调用方式的时候默认就校验的
    // filter 过滤出当前需要的规则
    return rules.filter(res=>!res.trigger || res.trigger.indexOf(trigger)!==-1)
   },
   /**
    * 校验数据
    * @param trigger 校验类型
    * @param callback 回调函数
    */
   validation(trigger,callback=function () {}){
    // blur 和 change 是否有当前方式的规则
    let rules = this.getFilteredRule(trigger);
    // 判断当前是否有规则
    if (!rules || rules.length === 0) {
     return
    }
    // 设置状态为校验中
    // async-validator的使用形式
    this.validateState = 'validating';
    var validator = new schema({[this.prop]: rules});
    // firstFields: true 只会校验一个
    validator.validate({[this.prop]: this.fieldValue}, { firstFields: true },(errors, fields) => {
     this.validateState = !errors ? 'success' : 'error';
     this.validateMessage = errors ? errors[0].message : '';
     callback(this.validateMessage);
    });
   },
   /**
    * 清空当前的 form-item
    */
   resetField(){
    this.form.model[this.prop] = this.initialValue;
   }
  },
  // 组件渲染时,将实例缓存在 Form 中
  mounted(){
   // 如果没有传入 prop,则无需校验,也就无需缓存
   if (this.prop) {
    this.dispatch('aiForm','on-form-item-add', this);
    // 设置初始值,以便在重置时恢复默认值
    this.initialValue = this.fieldValue;
    // 添加表单校验
    this.setRules()
   }
  },
  // 组件销毁前,将实例从 Form 的缓存中移除
  beforeDestroy(){
   this.dispatch('iForm', 'on-form-item-remove', this);
  },
 }
</script>

<style scoped>
 <!--当前css-->
 .ai-form-item-label-required:before{
  content: '*';
  color: red;
 }
 .ai-form-item-message {
  color: red;
 }
</style>

5.input

  •  value 支持一个入参
  • 因为当前是一个 input 注入的参数是不能直接放到 input 里面使用的所以先赋值给了 defaultValue 然后用 watch 来不停给 defaultValue 赋值达到一个父组件修改后的一个绑定
<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){
    // 当前model 赋值
    this.defaultValue = event.target.value;
    // vue 原生的方法 return 出去
    this.$emit('input',event.target.value);
    // 将当前的值发送到 aiFormItem 进行校验
    this.dispatch('aiFormItem','on-form-change',event.target.value)
   },
   /**
   * blur 事件
   * @param event
   */
   handleBlur(event){
    // vue 原生的方法 return 出去
    this.$emit('blur',event.target.value);
    // 将当前的值发送到 aiFormItem 进行校验
    this.dispatch('aiFormItem','on-form-blur',event.target.value)
   }
  }
 }
</script>

最后

最后给上一个当前可以的使用方式

<template>
 <div class="home">
 <button @click="changeButton">测试</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() // 验证方法
    .then(res=>{
     console.log(res)
    })
  }
 },
}
</script>

小结

可能现在小伙伴还是不懂。。俗话说;师傅领进门,修行在个人。代码上的备注写的也够多了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 技巧大全(新手入门篇)
May 12 Javascript
基于jquery实现的一个选择中国大学的弹框 (数据、步骤、代码)
Jul 26 Javascript
通过隐藏iframe实现无刷新上传文件操作
Mar 16 Javascript
JS判断指定dom元素是否在屏幕内的方法实例
Jan 23 Javascript
json的结构与遍历方法实例分析
Apr 25 Javascript
Vue中计算属性computed的示例解读
Jul 26 Javascript
原生javascript实现的全屏滚动功能示例
Sep 19 Javascript
Angular4 组件通讯方法大全(推荐)
Jul 12 Javascript
VsCode与Node.js知识点详解
Sep 05 Javascript
JavaScript中如何对多维数组(矩阵)去重的实现
Dec 04 Javascript
JavaScript实现简单计算器功能
Dec 19 Javascript
vue实现按钮切换图片
Jan 20 Vue.js
js中Generator函数的深入讲解
Apr 07 #Javascript
巧妙运用v-model实现父子组件传值的方法示例
Apr 07 #Javascript
vue路由导航守卫和请求拦截以及基于node的token认证的方法
Apr 07 #Javascript
vue自定义指令directive的使用方法
Apr 07 #Javascript
浅谈express.js框架中间件(middleware)
Apr 07 #Javascript
详解vue中this.$emit()的返回值是什么
Apr 07 #Javascript
浅谈javascript中的prototype和__proto__的理解
Apr 07 #Javascript
You might like
国王的咖啡这么大来头,名字的由来是什么
2021/03/03 咖啡文化
WindowsXP中快速配置Apache+PHP5+Mysql
2008/06/05 PHP
PHP CLI模式下的多进程应用分析
2013/06/03 PHP
PHP编码规范的深入探讨
2013/06/06 PHP
php设计模式之迭代器模式实例分析【星际争霸游戏案例】
2020/04/07 PHP
用jQuery实现检测浏览器及版本的脚本代码
2008/01/22 Javascript
javascript 通用简单的table选项卡实现
2010/05/07 Javascript
根据json字符串生成Html的一种方式
2013/01/09 Javascript
使用javascript实现ListBox左右全选,单选,多选,全请
2013/11/07 Javascript
innerHTML,outerHTML,innerText,outerText的用法及区别解析
2013/12/16 Javascript
使用GruntJS构建Web程序之合并压缩篇
2014/06/06 Javascript
Nodejs学习笔记之Global Objects全局对象
2015/01/13 NodeJs
JS实现在网页中弹出一个输入框的方法
2015/03/03 Javascript
JS面向对象(3)之Object类,静态属性,闭包,私有属性, call和apply的使用,继承的三种实现方法
2016/02/25 Javascript
element-ui带输入建议的input框踩坑(输入建议空白以及会闪出上一次的输入建议问题)
2019/01/15 Javascript
vue搜索和vue模糊搜索代码实例
2019/05/07 Javascript
我要点爆”微信小程序云开发之项目建立与我的页面功能实现
2019/05/26 Javascript
在LayUI图片上传中,解决由跨域问题引起的请求接口错误的方法
2019/09/24 Javascript
前端使用crypto.js进行加密的函数代码
2020/08/16 Javascript
ant design vue嵌套表格及表格内部编辑的用法说明
2020/10/28 Javascript
[42:20]Secret vs Liquid 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
深入理解Python中的元类(metaclass)
2015/02/14 Python
python如何修改装饰器中参数
2018/03/20 Python
Python图像处理模块ndimage用法实例分析
2019/09/05 Python
装上这 14 个插件后,PyCharm 真的是无敌的存在
2021/01/11 Python
浅谈Python xlwings 读取Excel文件的正确姿势
2021/02/26 Python
解析HTML5中的新功能本地存储localStorage
2016/03/01 HTML / CSS
彪马英国官网:PUMA英国
2019/02/11 全球购物
Boolean b = new Boolean(“abcde”); 会编译错误码
2013/11/27 面试题
二年级体育教学反思
2014/01/15 职场文书
员工入职担保书范文
2014/04/01 职场文书
保证金退回承诺函格式
2015/01/21 职场文书
小学五一劳动节活动总结
2015/02/09 职场文书
帝企鹅日记观后感
2015/06/10 职场文书
试了下Golang实现try catch的方法
2021/07/01 Golang
如何利用opencv判断两张图片是否相同详解
2021/07/07 Python