My Little World

结合VeeValidate实现对select校验

1.对校验项进行手动触发校验

配置 VeeValidate 时,触发事件event设置为‘blur’,而表单在点击提交按钮时,没有对整个表单进行校验,用户如果点开配置表单,不做任何操作就提交的话,会导致页面上不会有任何反应,因此调用 VeeValidate手动触发函数this.$validator.validate(),进行整体校验

this.$validator.validate()会返回promise, resolve的回调函数的参数result 为false时校验不通过,true时校验通过

2.添加select 验证

因为 VeeValidate 只对 input 进行,所以当表单配置项以select呈现时,就算在标签上添加v-validate,也不会对其进行校验,反而还会导致之前配置的blur触发事件失效,所以手动添加对select的校验

之前调用this.$validator.validate()进行手动触发校验input ,返回的是promise,因此在校验完input之后先不管input的校验结果,直接对select 进行校验

select 出现在配置项中有两种情况,一种是通过配置表单时,配置过来的,另外一种是通过slot套嵌进来的,slot也属于配置对象config里面的一种type

之所以会出现需要通过slot 来添加select的情况,是因为这类的select一般需要绑定change事件,与其他配置项形成关联关系,如果以配置项的方式给select添加绑定change事件,会导致infinity loop错误,

导致出现这个错误的原因是渲染配置项的时候用的是一个v-for,一项一项把配置的input,select根据type渲染出来,这时,如果给select绑上change事件,而且change事件的内容是对v-for的对象的属性进行修改vue的机制就会认为触发了无限循环,开始死循环,因此不为配置的项添加change事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
父组件配置对象
modelConfig: {
title: '授权',
modalId: 'modelConfig',
isAdd: true,
config: [
{label: '策略', value: 'v_policy_selected', option: 'v_policy_option', placeholder: '', disabled: false, type: 'select',v_validate: 'required:true',isError: false},
{name: 'selectAz', type: 'slot', v_validate:[
{label: '租户', value: 'v_tenant_selected', isError: 'v_tenant_isError', type: 'select'},
{label: '项目', value: 'v_project_selected', isError: 'v_project_isError', type: 'select'}
]}],
addRow: { // 其他配置项绑定的数据

},
v_select_configs: {
v_policy_selected: null, // 选中数据
v_policy_option: [], // 选择数据
v_project_selected: null, // 选中数据
v_project_option: [], // 选择数据
v_project_isError: false,
v_tenant_selected: null, // 选中数据
v_tenant_option: [], // 选择数据
v_tenant_isError: false
},
saveFunc: 'authSave'
}

主要验证逻辑如下:

校验之前设置flag = true,标志select的校验结果,最后用于与input校验结果result共同决定校验结果

先判断该配置项是否显示在表单中,因为有时新增和编辑的配置项不同,如果不在就不对该项进行校验,continue

对通过配置项展示的select,进行校验,如配置了校验规则v_validate,而且值为未选状态,则显示校验错误提示,同时设置flag = false,否则,不显示校验错误提示

这种错误提示同input,其显示通过配置项对象里面的一个属性决定,因此效果就是,显示提示该属性就设为true,否则设为false

1
2
<label v-show="errors.has(item.value) && isHide(item.hide)" class="col-md-7 help is-danger">{{item.label}} {{errors.first(item.value)}}</label>
<label v-if="item.type === 'select' && item.isError" class="col-md-7 help is-danger">{{item.label}} 不能为空</label>

对通过slot展示的select, 进行校验, 所有需要校验的配置放在v_validate属性中,遍历v_validate,判断select的值是否为未选,未选则显示提示,已选则不显示

错误提示放在slot的代码中,每一项配置自己的错误提示label,label的显示通过v_validate里面每一项配置的对应的错误提示属性的绑定值决定

1
2
3
4
5
6
7
8
9
10
11
<div slot="selectAz">
<v-select
v-model="modelConfig.v_select_configs.v_region_selected"
label="name"
class="col-md-7 v-selectss "
:on-change="changeRegion"
:options="modelConfig.v_select_configs.v_region_option">
</v-select>
<label class="required-tip">*</label>
<label v-if="modelConfig.v_select_configs.v_region_isError" class="col-md-7 help is-danger">xxx 不能为空</label>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
具体代码
formValidate () {
return this.$validator.validate().then(result => {
//result 为false插件验证input没有填写完整,true为验证填写完整
/** 验证 select是否进行了选填 实例可参照 [manage][authorizations]user-authorized.vue **/
let flag = true
for(let i=0; i< this.modelConfig.config.length; i++){
if(!this.isHide (this.modelConfig.config[i].hide)){
continue
}
/* ****** 配置里面的select ***** */
//配置规则为:在配置type:selcet时,如需校验则添加v_validate: 'required:true',isError: false==>控制错误提示label显示
//如果无需校验,则不添加
if(this.modelConfig.config[i].type === 'select' && this.modelConfig.config[i].v_validate) {
let obj = this.modelConfig.config[i]
if(!this.modelConfig.v_select_configs[obj.value]){
this.modelConfig.config[i].isError = true
flag = false
}else{
this.modelConfig.config[i].isError = false
}
}
/* ****** slot里面的select ****** */
//配置规则为:在配置type:slot 时,添加 v_validate:[],数组里面存放需要校验的select的配置信息
//value:绑定值,isError:错误标签显示绑定值,type:select ===> 如果以后再校验其他类型,再增加判断逻辑
//{name:'xxxx',type:'slot',v_validate:[{value: 'v_xxx_selected', isError: 'v_xxx_isError', type: 'select'}]}
//同时在this.modelConfig.v_select_configs里面定义v_xxx_isError:false
//slot里面错误提示label显示用 v-if="modelConfig.v_select_configs.v_xxx_isError" 搭配其他具体规则进行组合
if(this.modelConfig.config[i].type === 'slot') {
let arr = this.modelConfig.config[i].v_validate ? this.modelConfig.config[i].v_validate :[]
for(let j =0;j<arr.length;j++){
let key = arr[j].isError
let value = arr[j].value
if(arr[j].type === 'select' && !this.modelConfig.v_select_configs[value]) {
this.modelConfig.v_select_configs[key] = true
flag = false
}else{
this.modelConfig.v_select_configs[key] = false
}
}
}
}
return result && flag
})
},

3.勾选选项后错误消失

在公共组件里面为prop添加watch方法,当对象属性发生变化时就检查select是否有值了,有的话,就将提示隐藏掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
data () {
return {
configCopy:this.modelConfig,
FLAG:false
}
},
props: ['modelConfig'],
watch:{
configCopy: {
handler(){
//select选择完将提示隐藏,如果日后保留'X'删除功能,如需要,再增加显示处理逻辑
for(let key in this.modelConfig.v_select_configs) { //slot select
if(key.endsWith('isError')){
let prefix = key.slice(0,-7)
if(this.modelConfig.v_select_configs[key] && this.modelConfig.v_select_configs[prefix+'selected']){
this.modelConfig.v_select_configs[key] = false
}
}
}
for(let i=0; i< this.modelConfig.config.length; i++){ //config select
if(this.modelConfig.config[i].type === 'select' && this.modelConfig.config[i].v_validate) {
let obj = this.modelConfig.config[i]
if(this.modelConfig.v_select_configs[obj.value]){
this.modelConfig.config[i].isError = false
}
}
}
},
deep:true
}
},

4.关闭配置页面的清空

检查配置项对象里面所有的select配置项,将其负责错误提示显示的项设置为false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 清除表单selected
for(let i=0; i<this.modelConfig.config.length; i++){
if(this.modelConfig.config[i].type === 'select' && this.modelConfig.config[i].v_validate) {
this.modelConfig.config[i].isError = false
}
if(this.modelConfig.config[i].type === 'slot') {
let arr = this.modelConfig.config[i].v_validate ? this.modelConfig.config[i].v_validate :[]
for(let j =0;j<arr.length;j++){
let key = arr[j].isError
let value = arr[j].value
if(arr[j].type === 'select' && !this.modelConfig.v_select_configs[value]) {
this.modelConfig.v_select_configs[key] = false
}
}
}
}