vue-form组件

1,172 阅读2分钟

form组件旨在统一控制表单组件的输入值、获取值、校验值,提升开发效率。

核心逻辑:在父元素加载时订阅xx方法,在子元素的合适位置进行触发

el-form组件

  • 用于包裹所有的表单元素,和传递校验规则;
  • 通过slot容纳子组件
  • 定义validate方法:找到所有的表单子元素,通过Promise.all遍历执行表单子元素的校验方法,校验完成后执行相应的回调
<template>
  <form @submit.prevent>
    <slot></slot>
  </form>
</template>
--------------------------------
<script>
export default {
  name: 'el-form',
  provide() { // 通过provide和inject方式进行组件间通信
    return {elForm: Object}
  },
  props: {
    model: {
      type: Object,
      default: () => ({}),
    },
    rules: Object
  },
  methods: {
    async validate(cb) {
      let children = this.$children;
      let arr = [];
      function findFormItem(children) {
        children.forEach(child => {
          if (child.$options.name === 'el-form-item') {
            arr.push(child);
          }
          if (child.$children) {
            findFormItem(child.$children)
          }
        })
      }
      findFormItem(children)
      try {
        await Promise.all(arr.map(item => item.validate()))
        cb(true)
      }catch{
        cb(false)
      }
    }
  }
}
</script>

el-form-item组件

  • 用于包裹表单子元素,传递表单子元素的label和属性名;
  • 通过slot容纳子组件
  • 在mounted时,订阅validate事件
  • 定义validate方法:通过inject和provide从表单form中获取本表单元素的校验规则rule、表单key和value,通过async-validator插件进行校验
<template>
  <div>
    <label v-if='label'></label>
    <slot></slot>{{errMsg}}
  </div>
</template>
---------------------------------
<script>
import Schema from 'async-validator'
export default {
  name: 'el-form-item',
  inject: ['elForm'], // 通过provide和inject方式进行组件间通信
  props: {
    label: {
      type: String,
      default: ''
    },
    prop: String
  },
  data() {
    return {
      errMsg: ""
    }
  },
  mounted() {
    this.$on('validate', this.validate)
  },
  methods: {
   validate() {
     if(this.prop) { // 需要时进行校验
      let rule = this.elForm.rules[this.prop];
      let newVal = this.elForm.model[this.prop];
      let descriptor = {
        [this.prop]: rule,
      }
      let schema = new Schema(descriptor);// 通过描述信息创建骨架
      schema.validate({[this.prop]: newVal}, (err) => {
        if (err) {
          this.errMsg = err[0].message;
        } else {
          this.errMsg = ''
        }
      })
     }
   }
  },
}
</script>

el-input组件

  • 输入时,通过this.$emit("input", e.target.value)同步输入的内容
  • 输入时,找到name为el-form-item的组件,触发validate方法进行校验
<template>
  <input type="text" :value='value' @input='handleInput'>
</template>
--------------------------------------
<script>
export default {
  name: 'el-input',
  props: {
    value: {
      type: String,
      default: ''
    },
  },
  methods: {
   handleInput(e){
      this.$emit("input", e.target.value);
      let parent = this.$parent;
      while(parent) {
        let name = parent.$options.name
        if (name === 'el-form-item') {
          break
        }else {
          parent = parent.$parent
        }
        
      }
      if(parent) {
        parent.$emit('validate')
      }
   }
  }
}
</script>

使用

<template>
  <div>
  {{ruleForm}}
    <el-form
      :model='ruleForm'
      :rules='rules'
      ref='ruleForm'
    >
      <el-form-item label='用户名' prop='username'>
        <el-input v-model='ruleForm.username'></el-input>
      </el-form-item>
      <el-form-item label='密码' prop='password'>
        <el-input v-model='ruleForm.password'></el-input>
      </el-form-item>
      <el-form-item label='密码' prop='password'>
        <button @click='submitForm'>提交</button>
      </el-form-item>
    </el-form>
  </div>
</template>
----------------------------------------
<script>
import elForm from './components/el-form'
import elFormItem from './components/el-form-item'
import elInput from './components/el-input'
  export default {
    components: {
      'el-form': elForm,
      'el-form-item': elFormItem,
      'el-input': elInput,
    },
    data() {
      return {
        ruleForm: {
          username: "hihi",
          password: 'xx',
        },
        rules: {
          username: [
            {required: true, message: "请输入用户名"},
            {min: 3, max: 5, message: "长度在3-5个字符"}
          ],
          password: [
            {required: true, message: "请输入用户名"}
          ]
        },
      }
    },
    
    methods: {
      submitForm() {
        this.$refs['ruleForm'].validate(valid => {
          if (valid) {
            console.log('提交')
          }else{
            console.log('error');
            return false
          }
        })
      }
    }
  }
</script>