仿el-form中的表单验证

164 阅读1分钟

记录 模拟el-form实现过程

  <form @submit.prevent>
    <slot></slot>
  </form>
</template>
<script>

export default {
  name: "elForm",
  provide() {
    return { elForm: this };
  },
  props: {
    model: {
      type: Object,
      default: () => ({}),
    },
    rules: {
      type: Object,
      default: () => ({}),
    },
  },
  methods: {
    //el-form 看下内部el-form-item 是否都通过了校验
    async validate(cb) {
      let children = this.$broadcast("elFormItem");
      try {
        await Promise.all(
          children.map((child) => {
            return child.validate();
          })
        );
        cb(true);
      } catch {
        cb(false);
      }
    },
  },
};
</script>

`

}, }; `

    <input type="text" :value="value" @input="handleInput">
</template>
<script>
    export default {
        name:"elInput",
        props:{
            value:{
                type:String
            }
        },
        methods:{
            handleInput(e){
                this.$emit('input',e.target.value)
                 //触发el-form-item的validate 
                 //$dispatch拿到最外层的父组件   $parent
                 //$broadcast 拿到所有的子组件
                 this.$dispatch("elFormItem","validate")
            }
        }
    }
</script>
  <div id="app">
    <!-- ruleForm 数据源 rules规则 -->
    <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>
         <button @click="submitForm">提交表单</button>
        </el-form-item>
    </el-form>
  </div>
</template>
<script>
//1.掌握插槽的应用  2.props,$emit  $parent $children provide inject的使用
//2.组件的双向数据绑定
  import elForm from "@/components/el-form";
  import elFormItem from "@/components/el-form-item";
  import elInput from "@/components/el-input";
  export default {
    data(){
      return {
        ruleForm:{
          username:"",
          password:""
        },
        rules:{
          username:[
            {required:true,message:'请输入用户名'},
            {min:3,max:5,message:'长度在3到5个字符'}
          ],
          password:[
            {required:true,message:"请输入密码"}
          ]
        }
      }
    },
    components:{
      "el-form":elForm,
      "el-form-item":elFormItem,
      "el-input":elInput
    },
    methods:{
      submitForm(){
          this.$refs.ruleForm.validate(valid=>{
            if(valid){
              alert('submit')
            }else{
              console.log('error submit')
              return false;
            }
          })
      }
    }
  }
</script>
    let parent = this.$parent
    while(parent){
      let name = parent.$options.name;
      if(name === componentName ){
          break;
      }else{
        parent = parent.$parent
      } 
    }
    if(parent){
      if(eventName){
        parent.$emit(eventName)
      }
      return parent //返回父组件
    }
}
//拿到componentName所有的子组件并触发对应的事件
Vue.prototype.$broadcast = function(componentName,eventName){
    let children = this.$children;
    let arr = []
    function findChildren(children){
      children.forEach(child=>{
        if(child.$options.name === componentName){
          if(eventName){
            child.$emit(eventName)
          }else{
            arr.push(child)
          }
        }
        if(child.$children){
          findChildren(child.$children)
        }
      })
    }
    findChildren(children)
    return arr;
}