简单封装elementui中的表单

557 阅读3分钟

根据数据自动生成表单

我们只需要给组件传递一个数组formDataArr,
这个数组formDataArr中包含key,label 显示的值,type 组件类型,
keyName绑定的key名,defaultValue 绑定keyName的默认值, 
placeholder 提示语等

在组件中,我们会遍历传递过来的数组formDataArr,
使用<el-row> 组件作为行,<el-col>作为列(子项)
为啥要使用这2个组件,因为后面我们需要实现响应式
根据type类型,根绝v-if生成我们需要的组件。
<el-form>组件中的 model 我们会在formDataArr拿到它里面的keyName,
然后组成一下新的对象。
<template>
  <div class="art-page">
    <fromChild :formDataArr="formDataArr"></fromChild>
  </div>
</template>
<script>
import fromChild from '@/components/fromChild'
export default {
  components:{
    fromChild
  },
  data() {
    return {
      /**
        *  id 必须值,
        *  label 显示的值
        *  type 组件类型
        *  keyName 绑定的key
        *  defaultValue 绑定的key的默认值
        *  placeholder 提示语
        * */ 
      formDataArr: [
        { 
          key: '1',
          label: '姓名',
          type: 'el-input',
          keyName: 'name',
          defaultValue: '李四',
          placeholder: '用户大老爷请输入',
        },
        {  
          key: '2',
          label: '爱好',
          type: 'el-select',
          defaultValue: '01',// 回填的值
          placeholder: '用户大老爷请选择',
          keyName:'className',
          options: [
            { value: '01', label: '旅游' },
            { value: '02', label: '打游戏' },
            { value: '03', label: '写代码' }
          ]
        },
        {
          key: '3',
          label: '经历',
          type: 'el-date-picker',
          placeholder: '请选择',
          keyName:'experienceTime',
        }
      ],
    }
  }
}
</script>
<template>
  <div>
    <el-form ref="form" :model="exposeOutFormData" label-width="80px">
      <el-row :gutter="20" class="set-el-row">
        <el-col :span="8"  v-for="item in formDataArr" :key="item.id">
          <!-- 输入框 -->
          <el-form-item :label="item.label" v-if="item.type==='el-input'">
            <el-input v-model="exposeOutFormData[item.keyName]"></el-input>
          </el-form-item>
          <!-- 下拉框 -->
          <el-form-item :label="item.label" v-if="item.type==='el-select'">
            <el-select v-model="exposeOutFormData[item.keyName]" :placeholder="item.placeholder">
              <el-option :label="itemOption.label" :value="itemOption.value" v-for="(itemOption,itemIndex) in item.options" :key="itemIndex"></el-option>
            </el-select>
          </el-form-item>

          <el-form-item :label="item.label" v-if="item.type==='el-date-picker'">
            <el-date-picker
              v-model="exposeOutFormData[item.keyName]"
              type="daterange"
              range-separator="至"
              start-placeholder="开始日期"
              end-placeholder="结束日期">
            </el-date-picker>
          </el-form-item>
       
        </el-col>
      </el-row>
    </el-form>
  </div>
</template>

<script>
export default {
  props:{
    // 传递过来的值
    formDataArr:{
      type:Array,
      default:()=>{
        return []
      }
    }
  },
  data() {
    return {
      exposeOutFormData:{}
    }
  },
  created(){
    let obj ={}
    // 会遍历传递过来的数组formDataArr,拿到它里面的keyName生成一个新对象,作为model的值
    this.exposeOutFormData = this.formDataArr.forEach(element => {
      if(element.keyName){
        obj[element.keyName] = element.defaultValue
      }
    })
    this.exposeOutFormData = obj
  }
}
</script>

<style lang="scss" scoped>
.set-el-row{
  margin-left: 0px !important;
   margin-right: 0px !important;
}
</style>

响应式布局

由于用户的设备分辨率不同,
我们需要你动态去设置每一行的显示列。
这个时候我们可以借助 element-ui中的下面几个属性
xs	<768px    
sm	≥768px 	 
md	≥992px 	 
lg	≥1200px 
xl	≥1920px  
<el-form ref="form" :model="exposeOutFormData" label-width="80px">
  <el-row :gutter="32" class="set-el-row">
    <el-col :xl="6" :lg="8" :md="12" :sm="12" :xs="24" v-for="item in formDataArr" :key="item.id">
     <!-- 其他代码不动 -->
    /el-col>
  </el-row>
</el-form>
设备分辨率 ≥1920px  一行显示4列
设备分辨率 ≥1200px 一行显示3列
设备分辨率 ≥992px  一行显示2列
设备分辨率 ≥768px 一行显示2列
设备分辨率 <768px  一行显示2列

规则校验

现在我们想实现表单的校验。
我们需要给组件传递一个ruleObj对象,
这个对象包含的验证规则,触发方式,是否是必须验证。
子组件会接收这对象中的属性。
下面来实现一个<el-input>不能够为空的校验规则。
<el-date-picker> 选择的日期不能超过当前日期。

子组件绑定验证相关属性

<el-form ref="form" :model="exposeOutFormData" label-width="80px">
  <el-row :gutter="32" class="set-el-row">
    <el-col :span="6"  v-for="item in formDataArr" :key="item.id">
      <!-- 输入框的规则 -->
      <el-form-item :prop="item.keyName" :rules="{ 
          required:item.ruleObj && item.ruleObj.required, 
          trigger: item.ruleObj && item.ruleObj.trigger,
          validator: item.ruleObj && item.ruleObj.validatorHandler
        }" 
      :label="item.label" v-if="item.type==='el-input'">
        <el-input v-model="exposeOutFormData[item.keyName]"></el-input>
      </el-form-item>
    </el-col>
    <!-- 日期的 -->
    <el-form-item :prop="item.keyName"  :rules="{ 
        required:item.ruleObj && item.ruleObj.required, 
          trigger: item.ruleObj && item.ruleObj.trigger,
          validator: item.ruleObj && item.ruleObj.validatorHandler
        }" 
        :label="item.label" v-if="item.type==='el-date-picker'">
        <el-date-picker
          v-model="exposeOutFormData[item.keyName]"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期">
        </el-date-picker>
    </el-form-item>
  </el-row>
</el-form>

父组件的规则验证

formDataArr: [
  { 
    key: '1',
    label: '姓名',
    type: 'el-input',
    keyName: 'name',
    defaultValue: '李四',
    placeholder: '用户大老爷请输入',
    ruleObj:{
      required: true,
      trigger: 'blur',
      validatorHandler(rule, value, callback) {
        if (!value) {
          return callback(new Error('高贵的用户,姓名不能够为空'))
        }
        callback()
      }
    }
  },
  {
    key: '3',
    label: '经历',
    type: 'el-date-picker',
    placeholder: '请选择',
    keyName:'experienceTime',
    ruleObj:{
      required: true,
      trigger: 'blur',
      validatorHandler(rule, value, callback) {
        if (value &&value.length) {
          let entTime = value[1].getTime()
          let nowTime = new Date().getTime()
          console.log(entTime, nowTime)
          if(entTime>nowTime){
            return callback(new Error('高贵的用户,选择的时间不能大于当前时间'))
          }else{
            callback()
          }
        }else{
          return callback(new Error('高贵的用户,请选择时间'))
        }
      }
    }
  },
]

获取表单数据

我们在子组件中提供获取表单数据的按钮。
通过 this.$emit 向外暴露方法和数据。
在点击按钮之前,如果有规则则会校验。
可以通过  this.$refs.form.validate这个方法来进行验证。
下面我们就来简单实现一下

子组件提供获取数据的方法

<el-form ref="form" :model="exposeOutFormData" label-width="80px">
  <!--  -->
   .....这里是组件相关的代码,保持不变...
  <!--  -->
  <el-row :gutter="32" class="set-el-row">
    <el-col :xl="6" :lg="8" :md="12"  :sm="12" :xs="24" >
      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button>
        <el-button @click="resetForm('ruleForm')">重置</el-button>
      </el-form-item>
    </el-col>
  </el-row>
</el-form>

methods:{
  submitForm(){
    // 进行规则相关的验证
    this.$refs.form.validate((valid) => {
      if (valid) {
        // 向父组件暴露方法和提供数据
        this.$emit('submitForm', this.exposeOutFormData)
      } else {
        return false;
      }
    });
  }
}

父组件得到表单相关数据

<fromChild  ref="fromChild" :formDataArr="formDataArr" @submitForm="submitForm"></fromChild>
methods: {
    submitForm(formData){
      console.log('表单中的值', formData)
    }
  }