美文网首页Flutter圈子让前端飞饥人谷技术博客
ElementUI多个子组件表单的校验管理

ElementUI多个子组件表单的校验管理

作者: 熠辉web3 | 来源:发表于2019-03-25 19:11 被阅读84次

    背景

    公司项目中所用到的前端框架是Vue.js + ElementUI,因为项目的业务场景中有很多的大表单,但是ElementUI的表单写法对于表单的拆分和校验其实并不是很友好。最初的项目为了方便,常常把多个表单写在一个.vue组件中,这导致单文件的代码量巨大,逻辑十分复杂。目前为了维护方便,表单的拆分就变得十分重要。

    现在做了以下的Demo说明我们的业务场景,父组件是App.vue,该组件中包含了PersonForm.vueAdsForm.vue这两个子组件(在实际的业务场景中,可能多达10+表单)。【提交】按钮在父组件App.vue中,当点击【提交】按钮后,应该分别校验各个子组件,如果每个子组件都校验成功后再进行提交。

    DemoDemo

    PersonForm.vue文件

    下面的代码是PersonForm.vue组件,该表单包括姓名、年龄、性别。我们使用了PersonForm这个类去实例化组件中的personForm的值。在PersonForm中有个static方法getRule去获取校验方法去获取校验对象,该校验对象是ElementUI要求的写法,会在<el-form>rules中定义。

    <template>
      <div class="person-form">
        <h2>PersonForm.vue</h2>
        <el-form :model="personForm" ref="personForm" :rules="personFormRules">
          <!-- 姓名 -->
          <el-form-item label="姓名" prop="name">
            <el-input v-model="personForm.name"></el-input>
          </el-form-item>
          <!-- 年龄 -->
          <el-form-item label="年龄" prop="age">
            <el-input v-model="personForm.age"></el-input>
          </el-form-item>
          <!-- 性别 -->
          <el-form-item label="性别" prop="sex">
            <el-radio-group v-model="personForm.sex">
              <el-radio label="0">男</el-radio>
              <el-radio label="1">女</el-radio>
            </el-radio-group>
          </el-form-item>
        </el-form>
      </div>
    </template>
    
    <script>
    import {validateName, validateAge, validateSex } from '@/lib/validator.js';
    
    // PersonForm的类
    class PersonForm {
      constructor() {
        this.name = '';
        this.age = null;
        this.sex = null;
      }
    
      static getRule() {
        return {
          name: [{ validator: validateName, trigger: 'blur' }],
          age: [{ validator: validateAge, trigger: 'blur' }],
          sex: [{validator: validateSex, trigger: 'blur'}],
        }
      }
    }
    
    export default {
      data() {
        return {
          personForm: new PersonForm(),
          personFormRules: PersonForm.getRule()
        }
      }
    }
    </script>
    
    <style>
      .person-form {
        width: 400px;
        height: 350px;
        padding: 20px;
        border: 1px solid #ccc;
      }
    </style>
    

    AdsForm.vue文件

    下面的代码是AdsForm.vue组件,该表单包括广告名和广告位置。我们使用了AdsForm这个类去实例化组件中的adsForm的值。在AdsForm中有个static方法getRule去获取校验方法去获取校验对象。

    <template>
      <div class="ads-form">
          <h2>AdsForm.vue</h2>
          <el-form :model="adsForm" ref="adsForm" :rules="adsFormRules">
          <!-- 广告名 -->
          <el-form-item label="广告名" prop="name">
            <el-input v-model="adsForm.name"></el-input>
          </el-form-item>
          <!-- 广告位置 -->
          <el-form-item label="广告位置" prop="position">
            <el-select v-model="adsForm.position">
              <el-option value="1" label="左上"></el-option>
              <el-option value="2" label="右上"></el-option>
              <el-option value="3" label="左下"></el-option>
              <el-option value="4" label="右下"></el-option>
            </el-select>
          </el-form-item>
        </el-form>
      </div>
    </template>
    
    <script>
    import { notEmpty, validateName } from '@/lib/validator.js';
    
    class AdsForm {
      constructor() {
        this.name = '';
        this.position = null;
      }
    
      static getRule() {
        return {
          name: [{ validator: validateName, trigger: 'blur' }],
          position: [{ validator: notEmpty, trigger: 'blur' }],
        }
      }
    }
    
    export default {
      data() {
        return {
          adsForm: new AdsForm(),
          adsFormRules: AdsForm.getRule()
        }
      }
    }
    </script>
    
    <style>
      .ads-form {
        width: 400px;
        height: 350px;
        padding: 20px;
        border: 1px solid #ccc;
        margin-left: 30px;
      }
    </style>
    

    validator.js文件

    PersonForm.vueAdsForm.vue中我们导入了validator.js中的校验方法,这些校验方法中封装了对表单属性值的校验规则。该文件中的方法在实际项目中,应该使用策略模式再封装一下。Demo中只有4个方法,就没有再封装来干扰读者理解代码。

    // 验证名字
    var validateName = (rule, value, callback) => {
      if(!value) {
        callback(new Error('名字不能为空'));
      } else if(/[a-zA-Z]/.test(value)) {
        callback(new Error('请填写中文名字!'));
      } else {
        callback();
      }
    };
    
    // 验证年龄
    var validateAge = (rule, value, callback) => {
      const toNumberVal = Number(value);
      if ((typeof value === 'string' && value === '') || (value === null)) {
        callback(new Error('年龄不允许为空'));
      } else if (isNaN(toNumberVal)) {
        callback(new Error('年龄为数值类型'));
      } else if(!(toNumberVal > 0 && toNumberVal <= 120)) {
        callback(new Error('年龄范围应该大于一岁且小于等于120岁'));
      } else {
        callback();
      }
    }
    
    // 验证性别
    var validateSex = (rule, value, callback) => {
      if (value === null) {
        callback(new Error('性别不允许为空'));
      } {
        callback();
      }
    }
    
    // 验证不为空
    var notEmpty = (rule, value, callback) => {
      if (value === '' || value === null || value === undefined) {
        callback(new Error('不允许为空'));
      } else {
        callback();
      }
    }
    
    export { 
        validateName, 
        validateAge, 
        validateSex,
        notEmpty,
    }
    

    App.vue

    App.vue是父组件,当点击【提交】按钮时,应该调用其ElmentUI的this.$refs[formName].validate方法去验证各个子组件中的表单。但是需要注意的是,该方法是一个异步方法。
    所以这里封装了一个getFormPromise去生成Promise对象,并使用Promise.all去并行调用返回最终的校验结果数组。

    <template>
      <div class="app">
        <h1>App.vue</h1>
    
        <div class="forms-container">
          <!-- PersonForm.vue -->
          <person-form ref="personFormComp"/>
          <!-- AdsForm.vue -->
          <ads-form ref="adsFormComp"/>
        </div>
    
        <el-button 
          class="submit-btn" 
          @click="submitForm"
          type="primary">
          提交
        </el-button>
      </div>
    </template>
    
    
    <script>
    import PersonForm from '@/components/PersonForm';
    import AdsForm from '@/components/AdsForm.vue';
    
    export default {
      components: {
        'person-form': PersonForm,
        'ads-form': AdsForm,
      },
      methods: {
        submitForm() {
          // 获取到组件中的form
          const personForm = this.$refs.personFormComp.$refs.personForm;
          const adsForm = this.$refs.adsFormComp.$refs.adsForm;
          // 使用Promise.all去校验结果
          Promise.all([personForm, adsForm].map(this.getFormPromise)).then(res => {
            const validateResult = res.every(item => !!item);
            if (validateResult) {
              console.log('两个表单都校验通过');
            } else {
              console.log('两个表单未校验通过');
            }
          })
        },
        getFormPromise(form) {
          return new Promise(resolve => {
            form.validate(res => {
              resolve(res);
            })
          })
        }
      }
    }
    </script>
    
    <style>
    .app {
      border: 1px solid #ccc;
      padding: 20px;
      width: 900px;
    }
    .app .submit-btn {
      margin-top: 40px;
    }
    .forms-container {
      display: flex;
    }
    </style>
    

    如果大家有更好的关于ElementUI的表单封装方法,请不吝赐教。

    相关文章

      网友评论

        本文标题:ElementUI多个子组件表单的校验管理

        本文链接:https://www.haomeiwen.com/subject/dcobvqtx.html