需求:根据用户的选择的运输方式,动态改变输入框的输入条件,并且整个表单是可以循环添加多项,实现对数据批量校验。

效果图如下:

element ui动态添加工作流 element ui动态表单_element ui动态添加工作流

首先,表单可以新增加,则是一个循环表单;给 el-form-item 加上 prop 属性,对每一组中的这一项都进行校验。

<div v-for="(k,index) in formData.lists">
  <template>
    <el-form-item
      label="运输方式"
      :prop="'lists.' + index +'.assignTransportType'"
      :ref="index+'assignTransportType'"
      :rules=" { required: true, message: '请选择运输方式', trigger: 'change' }"
    >
      ......
    </el-form-item>
  </template>
  <hr>
</div>

其次,根据选择不同的运输方式,动态改变校验规则。当选择不同的运输方式时,使用 :rules=k.rules 添加动态对应的规则。

这是公共的字段校验:

const baseRule = [
  { required: true, message: '请选择运输方式', trigger: 'change' },
  { required: true, message: '请选择出库费', trigger: 'change' }
]

这个是根据选择不同的类型,校验不同规则:

inputRules: {
  'HIGHWAY':  [
    { required: true, message: '请选择车长', trigger: 'change' },
  ],
  'RAILWAY': [
    { required: true, message: '请选择到站卸装费', trigger: 'change' },
  ],
  'RAILWAY-CONTAINER': [
    { required: true, message: '请选择箱型', trigger: 'change' },
    { required: true, message: '请选择到站卸装费', trigger: 'change' },
  ],
  'SEA-CONTAINER': [
    { required: true, message: '请选择箱型', trigger: 'change' },
  ],
  'SEA-RAILWAY': [
    { required: true, message: '请选择箱型', trigger: 'change' },
  ],
},

在选择运输类型时,添加 change 事件。将动态添加的校验规则和原有的校验规则合并起来。

this.formData.lists[index].rules = this.inputRules[data].concat(baseRule)

进阶版:

由于个人的粗心,发现上面的图片中,第三行的文字标红提示信息都是一样的,因此对上述代码做了更改,以至于能达到自己想要的效果。

首先这是一个批量上传的表单。我们用 form 组件提交信息,同时这是一个批量上传的,可能你会想到使用 v-for 循环遍历一下,但是我们可以使用 table 组件进行展示。其他 table 组件中使用 slot-scope 插槽,使用 scope.$index 对该行进行动态定义规则。

<el-form
  ref="form"
  :model="baseForm"
  size="mini"
>
  <el-table
    border
    size="mini"
    :data="baseForm.tableData"
    style="width: 100%"
  >
    <el-table-column
      label="运输方式"
      width="130px"
    >
      <template slot-scope="scope">
        <el-form-item 
          :prop="'tableData.' + scope.$index + '.assignTransportType'"
          :rules="scope.row.rules.assignTransportType"
        >
          .....
        </el-form-item>
      </template>
    </el-table-column>
  </el-table>
</el-form>

同样,我们将公共需要校验的字段定义在一个地方:

const baseRules = {
  transportTerms: { required: true, message: '请选择运输条款', trigger: 'change' },
  ......
}

那么我们如何动态添加校验规则呢?由于添加动态规则,与运输方式这个字段有关,因此我们在选择运输方式的 change 事件时,传入 scope.$index,明确知道修改的是哪行的运输方式。

<el-select
  v-model="scope.row.assignTransportType"
  placeholder="请选择"
  size="mini"
  @change="changeAssignTransportType($event, scope.$index)"
>
  <el-option
    v-for="item in transactionData.transportType"
    :key="item.value"
    :label="item.label"
    :value="item.value"
  />
</el-select>

修改运输方式的 change 事件。

changeAssignTransportType(value, index) {
  this.clearHistoryValidate(index)
  this.$forceUpdate()
  this.baseForm.tableData[index].assignTransportType = value // 修改运输方式
  this.baseForm.tableData = this.handleData(this.baseForm.tableData, index)
}

在修改运输方式的同时,清除历史提示消息,代码如下:

clearHistoryValidate (index) {
  let data = ['carModel', 'carHeight', 'assignContainerType', 'includeUnloadCharge']
  data.forEach(item => {
    let key = index + item 
    this.$nextTick(() => {
      this.$refs[key].clearValidate()
    })        
  })      
},

最关键的知识点来了,如何动态添加校验规则呢?由于不同的运输类型,必填项是不一样的,因此才去给每一行的数据,都添加自己独有的校验规则。

handleData (data, num) {
  data.forEach((item, index) => {  
    item.rules = { ...baseRules, ...this.inputRules[item.assignTransportType] }
  })
  return data
},

上述中 baseRules 表示公共的校验规则字段,而 inputRules 中的则是动态添加的校验规则。通过展开运算符,实现浅拷贝的方式,将一行的校验规则,放入到 rules 字段中。

inputRules 中则是根据运输类型,进行划分需要添加的验证规则。

inputRules: {
  'HIGHWAY':  {
    'carModel': { required: true, message: '请选择车型', trigger: 'change' },
    'carHeight': { required: true, message: '请选择车长', trigger: 'change' },
  },
  ......
},

那么 Table 组件中又是如何与校验规则绑定在一起的呢?

使用 Table 组件中的插槽,同时绑定该行下面的 rules 对应的校验规则即可。

<el-table-column
  label="运输方式"
  width="130px"
>
  <template slot-scope="scope">
    <el-form-item 
      :prop="'tableData.' + scope.$index + '.assignTransportType'"
      :rules="scope.row.rules.assignTransportType"
    >
      ......
    </el-form-item>
  </template>
</el-table-column>