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编辑器KindEditor4.1.4代码高亮显示设置教程
Mar 01 Javascript
js转义字符介绍
Nov 05 Javascript
js实现div闪烁原理及实现代码
Jun 24 Javascript
jqueryUI里拖拽排序示例分析
Feb 26 Javascript
js兼容pc端浏览器并有多种弹出小提示的手机端浮层控件实例
Apr 29 Javascript
javascript实现根据iphone屏幕方向调用不同样式表的方法
Jul 13 Javascript
微信小程序 scroll-view组件实现列表页实例代码
Dec 14 Javascript
javascript学习之json入门
Dec 22 Javascript
基于jQuery实现无缝轮播与左右点击效果
May 13 jQuery
js实现列表向上无限滚动
Jan 13 Javascript
微信小程序canvas动态时钟
Oct 22 Javascript
解决antd 下拉框 input [defaultValue] 的值的问题
Oct 31 Javascript
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
用Php编写注册后Email激活验证的实例代码
2013/03/11 PHP
PHP制作登录异常ip检测功能的实例代码
2016/11/16 PHP
PHP实现网页内容html标签补全和过滤的方法小结【2种方法】
2017/04/27 PHP
深入理解javascript变量声明
2014/11/20 Javascript
javascript实现别踩白块儿小游戏程序
2015/11/22 Javascript
基于JavaScript实现移除(删除)数组中指定元素
2016/01/04 Javascript
使用jQuery ajaxupload插件实现无刷新上传文件
2017/04/23 jQuery
关于定制FileField中的上传文件名称问题
2017/08/22 Javascript
vue-cli2.9.3 详细教程
2018/04/23 Javascript
使用electron将vue-cli项目打包成exe的方法
2018/09/29 Javascript
jQuery点击页面其他部分隐藏下拉菜单功能
2018/11/27 jQuery
Vue 开发必须知道的36个技巧(小结)
2019/10/09 Javascript
elementui更改el-dialog关闭按钮的图标d的示例代码
2020/08/04 Javascript
js实现详情页放大镜效果
2020/10/28 Javascript
[01:52]PWL S2开团时刻第四期——DOTA2成语故事
2020/12/03 DOTA
python定时检查启动某个exe程序适合检测exe是否挂了
2013/01/21 Python
最基础的Python的socket编程入门教程
2015/04/23 Python
在Python中使用HTML模版的教程
2015/04/29 Python
Python基于pygame实现的弹力球效果(附源码)
2015/11/11 Python
Python装饰器入门学习教程(九步学习)
2016/01/28 Python
python实现下载文件的三种方法
2017/02/09 Python
Python 利用scrapy爬虫通过短短50行代码下载整站短视频
2018/10/29 Python
Python使用scipy模块实现一维卷积运算示例
2019/09/05 Python
opencv python图像梯度实例详解
2020/02/04 Python
Matplotlib animation模块实现动态图
2021/02/25 Python
京东港澳售:京东直邮港澳台
2018/01/31 全球购物
linux面试相关问题
2012/08/11 面试题
求职简历推荐信范文
2013/12/02 职场文书
金融专业大学生职业生涯规划范文
2014/01/16 职场文书
2014年国庆晚会主持词
2014/09/19 职场文书
考察邀请函范文
2015/01/31 职场文书
年会主持人开场白台词
2015/05/29 职场文书
刑事法律意见书
2015/06/04 职场文书
学前教育见习总结
2015/06/23 职场文书
文艺有韵味的诗句(生命类、亲情类...)
2019/07/11 职场文书
在Python中如何使用yield
2021/06/07 Python