需求:根据用户的选择的运输方式,动态改变输入框的输入条件,并且整个表单是可以循环添加多项,实现对数据批量校验。
效果图如下:
首先,表单可以新增加,则是一个循环表单;给 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>