├── App.vue
├── components
│   ├── Form.vue
│   ├── FormItem.vue
│   └── Input.vue
└── package.json
<template>
    <el-form :model="form" :rules="rules">
        <el-form-item label="用户名" prop="username">
            <el-input v-model="form.username" ></el-input>
        </el-form-item>
        <el-form-item label="密码" prop="password">
            <el-input v-model="form.password" ></el-input>
        </el-form-item>
        <el-form-item>
        <el-form-item>
            <button>确认提交</button>
        </el-form-item>
    </el-form>
</template>
<script>
import Form from './components/Form';
import FormItem from './components/FormItem';
import Input from './components/Input.vue';
export default {
    components:{
        'el-form':Form,
        'el-form-item':FormItem,
        'el-input':Input
    },
    data(){
        return {
            form:{
                username:'',
                password:''
            },
            rules:{
                username:[
                    {required:true,message:'请输入用户名'}
                ],
                password:[
                    {required:true,message:'请输入密码'}
                ]
            }
        }
    }
}
</script>
<template>
    <form onsubmit="return false">
        <slot></slot>
    </form>
</template>
<script>
export default {
    props:{
        model:{
            type:Object
        },
        rules:{
            type:Object
        }
    }
}
</script>
<template>
    <div>
        <label v-if="label">{{label}}</label>
        <slot></slot>
        <div>校验文字</div>
    </div>
</template>
<script>
export default {
    props:{
        label:String,
        prop:String
    }
}
</script>
<template>
    <input type="text" :value="inputValue">
</template>
<script>
export default {
    props:{
        value:String
    },
    data(){
        return {inputValue:this.value}
    }
}
</script>
provide(){
  return {
      form:this
  }
},
我们在form组件中直接将当前实例暴露出去
import Vue from 'vue';
Vue.prototype.$bus = new Vue();
export default {
  props:{
      label:String,
      prop:String
  },
  mounted(){
      this.$bus.$on('input',(value)=>{
          console.log(value)
      });
  }
}
我们在formItem组件中,通过eventsBus订阅input事件
<input type="text" :value="inputValue" @input="handleInput">
handleInput(e){
  // 更新数据
  this.inputValue = e.target.value;
  this.$bus.$emit('input',{
      id:this.$parent && this.$parent._uid,// 为了标识是哪个输入框
      value:this.inputValue
  }); // 发射输入事件
}
<template>
  <div>
      <label v-if="label">{{label}}</label>
      <slot></slot>
      <!-- 有错误 显示错误提示信息 -->
      <div v-if="validateStatus === 'error'">
          {{validateContent}}
      </div>
  </div>
</template>
<script>
import Vue from 'vue';
Vue.prototype.$bus = new Vue();
export default {
  props:{
      label:String,
      prop:String
  },
  inject:['form'], // 注入父级的实例
  data(){ 
      return {
          validateStatus:'', // 当前表单是否通过校验
          validateContent:'' // 当前校验后的信息
      }
  },  
  methods:{
      validate(value){
         let rules = this.form.rules[this.prop]; // 获取当前对应的规则
         rules.forEach(rule=>{
             // 如果必填 并且没有值,那就出错
             if(rule.required && !value){
                 this.validateStatus = 'error';
                 this.validateContent = rule.message
             }else{
                 this.validateStatus = '';
                 this.validateContent = '';
             }
         })
      }
  },
  mounted(){
      this.$bus.$on('input',(data)=>{
         if(this._uid === data.id){ // 说明更改的是当前自己的输入框
              this.validate(data.value);
         }
      });
  }
}
</script>
到目前为止基本的校验功能已经实现啦
<el-form :model="form" :rules="rules" ref="form">
<button @click="validate">确认提交</button>
validate(){ // form组件中校验是通过
    this.$refs.form.validate((valid)=>{
        if(valid){
            alert('校验通过')
        }else{
            alert('校验不通过')
        }
    });
}
// 在form组件中检查所有的formItem是否全部通过校验
validate(cb){
    cb(this.$children.every(child=>child.validateStatus!='error'))
}