一.使用v-for渲染时
前端由于某些需求场景需要,部分表单的渲染是通过 v-for循环渲染显示,此时如何实现表单验证呢?如下,点击第一行的+号可以动态的增加更多行表单,不同于单一固定的表单行[参见下文一般情况下],我们可以通过固定的prop绑定来验证,多行动态时,则无法使用原有方案进行验证!!!
页面代码实现如下:
注意:此处的el-form-item管理着三个表单元件!!提示时只使用一个el-form-item携带的提示框!!!
<div class="card-item flex-col"
style="width:auto;position:relative;padding-left: 0px;padding-top: 0px;">
<el-checkbox v-model="adverseEventChecked">不良事件提醒</el-checkbox>
<slot v-for="(item, index) in adverseEventList">
<el-form-item label="" prop="formValidator" class="flexview" :rules="[
{ required: true, validator: (rule, value, callback) => {
if (!item.adverseEventCrf || item.adverseEventCrf.length === 0)
{
callback('请选择CRF模板')
}
else if (!item.adverseEventTopic || item.adverseEventTopic.length === 0)
{
callback('请选择CRF模板中的题目')
}
else{
callback()
}
}, trigger: 'blur' }]">
<div :key="index" class="card-item flexview" v-if="adverseEventChecked"
style="width:auto;position:relative;padding-left: 0px;padding-top: 10px;">
<el-select v-model="item.adverseEventCrf" size="medium"
style="width: 240px;" placeholder="选择CRF">
<el-option v-for="item in followCrfOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
<span
style="width: 76px;font-size:15px;color:#333333;padding:0px 6px;">CRF中的</span>
<el-select v-model="item.adverseEventTopic" size="medium"
style="width: 240px;" placeholder="选择题目">
<el-option v-for="item in followTopicOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
<span style="width: 14px;"></span>
<el-select size="medium" v-model="item.adverseEventRelation"
style="width: 100px;" placeholder="关系">
<el-option v-for="item in adverseEventRelationOptions"
:key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
<i v-if="index === 0" class="el-icon-circle-plus-outline"
style="color:rgb(0, 139, 255);padding-left:10px"
@click="addEventAction"></i>
<i v-else class="el-icon-delete"
style="color:rgb(226,115,112);padding-left:10px"
@click="delEventAction(index)"></i>
</div>
</el-form-item>
</slot>
</div>
填写相关的下拉数据,测试效果如下,可以看到正确的检验并进行了提示信息。
其核心代码块则为:指定prop="formValidator",此时不需要去data里面定义formValidator,但是View上必须指定prop否则无法触发检验规则,内部直接使用遍历的item访问其值做出判断给出反馈信息即可!给出反馈信息的callback写法有所不同:
一般写法为:
callback(new Error('请选择CRF模板'));
而此处写法为:
callback('请选择CRF模板');
item即为动态遍历的V-FOR对象!!!
<el-form-item label="" class="flexview" :rules="[
{ required: true, validator: (rule, value, callback) => {
if (!item.adverseEventCrf || item.adverseEventCrf.length === 0)
{
callback('请选择CRF模板')
}
else if (!item.adverseEventTopic || item.adverseEventTopic.length === 0)
{
callback('请选择CRF模板中的题目')
}
else{
callback()
}
}, trigger: 'blur' }]">
二.一般情况下
1、规则校验直接写在data里面
<el-form :model="productParam" ref="productSaleForm" :rules="saleRules" label-width="90px" size="small">
<el-form-item label="赠送积分" prop="gift.giftPoint" class="stargod-form-row__flex">
<el-input v-model="productParam.gift.giftPoint" maxlength="5" placeholder="必填">
<template slot="append">小星星</template>
</el-input>
</el-form-item>
</el-form>
data () {
saleRules: {
gift: {
giftPoint: [
{ required: true, message: '请填写积分', trigger: 'blur' },
{ pattern: /^[0-9]+$/, message: '积分需为数值类型', trigger: 'blur' }
]
}
}
}
2、规则校验虽然写在data里面,自定义校验规则
<div class="card-item flexview" :class="[(index > 0) ? 'ml-20' : '']" style="width:460px;position:relative;padding-left: 0px;padding-top: 0px;">
<el-form-item label="" prop="followDayValue" class="flexview">
<span
style="font-size:15px;color:#333333;padding-right:6px;width: 50px;">每</span>
<el-input size="medium" placeholder="请输入" v-model="ruleForm.followDayValue">
<template slot="append">
<el-select v-model="followUnits" size="small" style="width: 60px;">
<el-option v-for="item in followUnitsOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
</template>
</el-input>
<span
style="width: 150px;font-size:15px;color:#333333;padding-left:6px;">随访一次</span>
</el-form-item>
</div>
</div>
<div v-if="followFrequency === '3'" class="flexview"
style="background-color: #fafafa;padding-left: 20px;">
<div class="card-item flexview" :class="[(index > 0) ? 'ml-20' : '']"
style="width:460px;position:relative;padding-left: 0px;padding-top: 0px;">
<el-form-item label="" prop="followDayValue" class="flexview">
<span
style="font-size:15px;color:#333333;padding-right:6px;width: 50px;">间隔</span>
<el-input size="medium" placeholder="以逗号分隔,如1,2,3"
v-model="ruleForm.followDayValue">
<template slot="append">
<el-select v-model="followUnits" size="small" style="width: 60px;">
<el-option v-for="item in followUnitsOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
</template>
</el-input>
<span
style="width: 150px;font-size:15px;color:#333333;padding-left:6px;">随访一次</span>
</el-form-item>
</div>
注意这里:必须是箭头函数,否则this指向是函数指向而不是页面this指向无法取出对应的变量值!!!
validator: (rule, value, callback) => {}
ruleForm: {
followDayValue: '',
followCrf: null,
followTopic: null,
afterTimeValue: null,
afterTimeValueUnits: 1,
},
rules: {
followDayValue: [
{
validator: (rule, value, callback) => {
if ((!this.ruleForm.followDayValue || this.ruleForm.followDayValue.length === 0) && parseInt(this.followFrequency) > 1) {
callback(new Error('请填写随访频率'));
}
else if (this.followRadio === '1' && parseInt(this.followFrequency) === 3) {
if (this.ruleForm.followDayValue.split(',').length > this.followCount) {
callback(new Error('随访频率间隔数不能大于随访次数'));
}
else {
callback();
}
}
}, trigger: 'blur'
}
],
followDateTree: [{
validator: (rule, value, callback) => {
debugger
if (this.followDate === 3) {
if (!this.ruleForm.followCrf || this.ruleForm.followCrf.length === 0) {
callback(new Error('请选择入组阶段时间题目触发开始时间CRF模板'));
}
else if (!this.ruleForm.followTopic || this.ruleForm.followTopic.length === 0) {
callback(new Error('请选择入组阶段时间题目触发开始时间题目'));
}
else if (!this.ruleForm.afterTimeValue || this.ruleForm.afterTimeValue.length === 0) {
callback(new Error('入组阶段时间题目触发开始时间数值应为正整数或0'));
}
else {
callback();
}
}
else {
callback();
}
}, trigger: 'blur'
}],
},
3、固定对象,校验规则直接写在dom上
注意:此时直接使用变量名XXX或其定义的对象a.xxx,而非this.XXX或者this.a.xxx
<el-form-item label="" prop="formAutoStopCrfValidator" class="flexview"
:rules="[{ required: true, validator: (rule, value, callback) => {
if (!autoStopCrf || autoStopCrf.length === 0)
{
callback('请选择CRF模板')
}
else if (!autoStopTopic || autoStopTopic.length === 0)
{
callback('请选择CRF模板中的题目')
}
else{
callback()
}
}, trigger: 'blur' }]">
<div class="card-item flexview" v-if="autoStopChecked"
style="width:auto;position:relative;padding-left: 0px;padding-top: 10px;">
<el-select v-model="autoStopCrf" size="medium" style="width: 240px;"
placeholder="选择CRF">
<el-option v-for="item in followCrfOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
<span
style="width: 76px;font-size:15px;color:#333333;padding:0px 6px;">CRF中的</span>
<el-select v-model="autoStopTopic" size="medium" style="width: 240px;"
placeholder="选择题目">
<el-option v-for="item in followTopicOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
<span style="width: 14px;"></span>
<el-select size="medium" v-model="autoStopRelation" style="width: 100px;"
placeholder="关系">
<el-option v-for="item in adverseEventRelationOptions" :key="item.value"
:label="item.label" :value="item.value">
</el-option>
</el-select>
</div>
</el-form-item>