先来看看我这个变态而又复杂的需求!
目前自定义表单的前端开发越来越热,开发人员封装好成熟的组件,用户直接拖动生成自己的页面!这样的特点就是:
页面中显示的东西,完全是自定义组合的而不是固定的,所以此时的elform的普通prop验证已经不能满足于我们的开发要求,那如何处理呢?
以下为页面代码:form-item-layout是一个封装的组件!内部会根据会传入不同的数据model渲染出来不同的页面!如下参考!
我们来重点看看针对这种自定义表单的验证代码如何实现。
关于更多验证实现可以参考以下文章:
elform 动态 rules_el-form动态rules-CSDN博客
<el-form ref="formRefs" :model="formModel">
<div v-for="item in itemList" :key="item.id">
<el-form-item label="" label-width="0" :prop="i.prop" v-for="(i, index) in item.components"
:key="i.renderKey" :rules="[
{
required: true, validator: (rule, value, callback) => {
}, trigger: 'blur'
}]">
<form-item-layout :current-item="i" :drawing-list="drawingList"
:form-conf="formConf" :index="index + 1" :form-style="formStyle"
:item-group="item" :type="true" :showPreview="true" />
</el-form-item>
</div>
</el-form?
可以看到,对于el-from的使用仍然是能用的规则,给他定义ref,给他定义动态的model!
<el-form ref="formRefs" :model="formModel">
data() {
return {
formModel:{}
};
},
而针对el-from-item的prop指定就显示的尤其特别,prop为空,则意味着不需要验证,不为空则意味着需要验证!
<el-form-item label="" label-width="0" :prop="i.prop" v-for="(i, index) in item.components"
:prop=i.prop,这句是精华,重中之重。
然后向原始数据中渗入prop属性,这里为什么要调用replaceAll()函数呢?因为我们后端给我返回的
p.component.vModel值为"v.model.242342342"这样的字符串,在strict模式下,这被认为是一个对象的深入节点访问!当然你可以直接p的某一个属性,如id或者是不包括点号的属性保持唯一即可。但一定要与数据对应因为后面的验证规则中需要通过这个唯一值来访问动态数据中的提示语言文字!而最后this.$set(this.formModel,p.prop,'')更是不能替换为this.formModel = p.prop,否则是不生效的。
p.prop = p.component.vModel.replaceAll('.','')
this.$set(this.formModel,p.prop,'')
最后一步则简单多了,实现rules方法进行验证即可,我们是行间实现验证规则,你也可以参考下面的函数中验证规则,均可。
一、行间验证
:rules="[
{
required: true, validator: (rule, value, callback) => {
debugger
}, trigger: 'blur'
}]"
根据回调中field遍历我们的数据源,找到相应的数据,根据规则进行验证提示即可。
最终行间验证完整代码如下:
<el-form-item label="" label-width="0" :prop="i.prop" v-for="(i, index) in item.components"
:key="i.renderKey" :rules="[
{
required: true, validator: (rule, value, callback) => {
if (!value && value.length === 0)
{
callback(i.component.placeholder)
}
else
{
callback()
}
}, trigger: 'blur'
}]">
<form-item-layout :current-item="i" :drawing-list="drawingList"
:form-conf="formConf" :index="index + 1" :form-style="formStyle"
:item-group="item" :type="true" :showPreview="true" />
</el-form-item>
一般函数内写法为:
callback(new Error('请选择CRF模板'));
而此处行间验证写法为:
callback('请选择CRF模板');
二、动态绑定验证函数
this.itemList.map((item)=>{
let rulesList = []
const validator = (rule,value,callback)=>{
//实现你的验证逻辑
if (!value && value.length === 0)
{
return callback(
new Error(item.component.placeholder)
);
}
}
rulesList.push({validator:validator,trigger: "blur"})
this.rules[item.prop]=rulesList
})
我最终实现验证的同时配合self.$nextTick滚动到未输入的表单处!体验更好。采用函数式验证!因为行间验证无法调用document.getElementsByClassName('el-form-item__error')
完整代码为:
data() {
return {
formModel:{},
formRules:{}
};
},
<el-form ref="formRefs" :model="formModel" :rules="formRules">
<div v-for="item in itemList" :key="item.id">
<el-form-item label="" label-width="0" :prop="i.prop" v-for="(i, index) in item.components"
:key="i.renderKey">
<form-item-layout :current-item="i" :drawing-list="drawingList"
:form-conf="formConf" :index="index + 1" :form-style="formStyle"
:item-group="item" :type="true" :showPreview="true" />
</el-form-item>
</div>
</el-form?
p.prop = p.component.vModel.replaceAll('.','')
self.$set(self.formModel,p.prop,'')
let rulesList = []
const validator = (rule,value,callback)=>{
if (!value && value.length === 0)
{
let text = p.component.placeholder?p.component.placeholder:'数据不能为空'
self.$nextTick(function(){
let errList = document.getElementsByClassName('el-form-item__error')
if (errList && errList.length > 0)
{
errList[0].scrollIntoView({
// 滚动到指定节点
// 值有start,center,end,nearest,当前显示在视图区域中间
block: 'center',
// 值有auto、instant,smooth,缓动动画(当前是慢速的)
behavior: 'smooth',
})
}
})
return callback(
new Error(text)
);
}
}
rulesList.push({validator:validator,trigger: "blur"})
self.formRules[p.prop]=rulesList
页面验证效果: