在使用element-ui开发中,经常会用到对动态创建的表单进行字段验证,比如新增多个类似卡片的表单,里面的字段需要做验证,此时就要使用到动态表单验证,官方文档写的有示例,但是不够清晰。除了官方示例,还可以使用循环生成多个form实现该需求。

第一种官方示例:一个Form多项

下面以实际项目中的代码为例:

<el-form ref="form" :model="form" :rules="rules" label-width="110px" size="small" style="width: 90%;">
      <div v-for="(item, index) in form.list" :key="item.id" class="box-card">
            <el-form-item :prop=" 'list.' + index + '.maintUnit'" :rules="rules.maintUnit" label="运维单位">
              <SearchOpsDepartment :value.sync="item.maintUnit"></SearchOpsDepartment>
            </el-form-item>
            <el-form-item :prop=" 'list.' + index + '.userId'" :rules="rules.userId" label="运维人员">
              <SearchUsers :value.sync="item.userId"></SearchUsers>
            </el-form-item>
            <div>
              <el-button type="text" @click="handleAdd">添加</el-button>
              <el-button v-if="index !== 0" type="text" @click="handleDelete(index)">删除</el-button>
            </div>
      </div>
</el-form>
<script>
	data() {
        return {
            form: {
                list: [{ id: Date.now() }] // 这里添加了一个当前时间戳作为循环使用的key,如果使用index作为key,虽然避免的报错,但是对性能没有什么帮助,而且可能增加新能问题。
            },
            rules: {
                maintUnit: [
                    {
                        required: true,
                        message: '运维单位不能为空!',
                        trigger: ['change', 'blur']
                    }
                ],
                userId: [
                    {
                        required: true,
                        message: '运维人员不能为空!',
                        trigger: ['change', 'blur']
                    }
                ]
            }
        }
    }
</script>

注意重点

第二种:多个form

<CardBox v-for="(item, index) in list" :key="index" :title="item.itemName">
    <el-form ref="form" :model="item" class="size-auto width-100" :rules="rules" :inline="true" size="medium" label-width="120px">
                <el-form-item label="计划工程量" prop="workAmount">
                    <el-input v-model.trim="item.workAmount" maxlength="15" clearable placeholder="支持小数点后2位" @change="handleComputed(item, index)" />
                </el-form-item>
                <el-form-item label="单价" prop="unitPrice">
                    <el-input v-model.trim="item.unitPrice" maxlength="50" show-word-limit clearable placeholder="请输入" @change="handleComputed(item, index)" />
                </el-form-item>
                <el-form-item label="计划完成金额" prop="prepareCompletionMoney" :rules="moneyRules(item.budgetContent.budgetMoney)">
                    <el-input v-model.trim="item.prepareCompletionMoney" disabled maxlength="15" clearable placeholder="支持小数点后2位">
                        <i slot="suffix" class="el-input__icon input-unit">元</i>
                    </el-input>
                </el-form-item>
                <el-form-item label="工作内容及标准">
                    <el-input v-model.trim="item.content" type="textarea" maxlength="200" show-word-limit clearable placeholder="请输入" />
                </el-form-item>
                <el-form-item label="备注">
                    <el-input v-model.trim="item.remark" type="textarea" maxlength="200" show-word-limit clearable placeholder="请输入" />
                </el-form-item>
    </el-form>
</CardBox>
<script>
	data() {
        return {
            list: [],
            rules: {
                workAmount: [{ validator: this.validNum, trigger: 'blur' }],
                unitPrice: [{ validator: this.validNum, trigger: 'blur' }],
                adjustmentFactor: [{ validator: this.validNum, trigger: 'blur' }]
            }
        }
    },
    methods: {
        validNum(rule, value, callback) {
            if (value && !isNumber2(value)) {
                callback(new Error('填写格式错误'))
            } else {
                callback()
            }
        },
        moneyRules(budgetMoney) {
            return [{
                validator: (rule, value, callback) => this.validMoney(rule, value, callback, budgetMoney),
                trigger: 'change'
            }]
        },
        validMoney(rule, value, callback, budgetMoney) {
            if (value) {
                if (value > budgetMoney) {
                    callback(new Error('不能大于预算金额'))
                } else {
                    callback()
                }
            } else {
                callback()
            }
        },
        // 获取多个form验证结果
        handleValidate() {
            const list = []
            const validas = []
            this.$refs['form'].forEach((item, index) => {
                list.push(new Promise(resolve => {
                    item.validate(valida => {
                        validas.push(valida)
                        resolve()
                    })
                })
                )
            })
            Promise.all([...list]).then(() => {
                const res = !validas.some(item => item === false)
                return res
            }).catch(() => {
                return false
            })
        }
    }
</script>

复杂表单的验证

很多时候会遇到其中一个值,需要当前项的某个值做验证,如上第二种表单中,要求计划完成金额不能大于预算量,这里有两种实现方式

1、通过 rule.field获取到当前项下标,只适用第一种动态表单;

validEverydayBudgetAmount(rule, value, callback) {
    if (value) {
        if (!isNumber2(value)) {
            callback(new Error('填写格式错误'))
            return
        }
        // rule.field转为数组后第二个就是下标
        const index = rule.field.split('.')[1]
        const budgetAmount = this.everydayCost[index].budgetAmount
        if (value > budgetAmount) {
            callback(new Error(`不能大于总预算量${budgetAmount}`))
        } else {
            callback()
        }
    } else {
        callback()
    }
},

2、把验证规则写在item行内,这样就可以通过传参获取当前项值;

<el-form-item label="计划完成金额" prop="prepareCompletionMoney" :rules="moneyRules(item.budgetContent.budgetMoney)">
// 验证规则见第二种表单的示例代码

获取验证结果

第二种多个form的,验证结果获取较为麻烦,因为每个验证都是异步,这里使用promise方式获取。父组件获取验证结果时,调用子组件内handleValidate方法,通过then或者await获取结果即可。

// 获取多个form验证结果,具体参考第二种form代码
handleValidate() {
    const list = []
    const validas = []
    this.$refs['form'].forEach((item, index) => {
        // 把单个验证结果处理为promise函数,然后添加到list中
        list.push(new Promise(resolve => {
            item.validate(valida => {
                validas.push(valida)
                resolve()
            })
        })
        )
    })
    // 通过Promise.all等待几个验证都完成再处理
    return Promise.all([...list]).then(() => {
        const res = !validas.some(item => item === false)
        return res
    }).catch(() => {
        return false
    })
}

发表回复