uniapp开发微信小程序时,动态表单验证validateFunction的正确姿势

背景

大家一定在官网中看到了下图这一段内容,而且99%的同学应该都能正确使用
uniapp开发微信小程序时,动态表单验证validateFunction的正确姿势_第1张图片
总结一下就是说,因为微信小程序的表单验证机制(实际上是它的元素加载机制导致以及微信小程序对元素中动态函数的限制问题),所以uniapp在实现的时候,让大家在onReady里面去主动的设置rules,以达到元素渲染以后能够加载rules的自定函数的能力。

但是,有50%+的同学,一定遇到了,当rules中存在动态表单字段的validateFunction时,这个validateFunction没有执行的问题。

因为官网没有在说清楚应该怎么做,大部分同学只能看到,需要在onReady里面给uni-forms设置一个rules,但是仅仅给uni-forms设置整体的rules,其中的动态字段的validateFunction是一定不会执行的

分析过程

主要是跟踪了一下源码,基本上略过吧。。。。

结论说一下,实际上还是因为前面说的,微信小程序元素加载机制导致以及微信小程序对元素中动态函数的限制问题。一个动态组件渲染出来以后,如果不主动给它设置rules,那么他就只能绑定rules中不含动态函数的部分,这也就是无论你怎么给uni-forms设置setRules,动态增加出来的uni-forms-item只能绑定静态rules。

处理方法

直接说答案吧,其实就是要想办法给动态增加出来的uni-forms-item也setRules


1、原始例子

假设有如下动态表单(就以官网的例子为例),在这个例子中,rules有两个静态规则,用于验证新增加的email不能为空、必须符合email形式。

HTML

<uni-forms ref="dynamicForm" :rules="dynamicRules" :model="dynamicFormData">
	<uni-forms-item label="邮箱" required name="email">
		<uni-easyinput v-model="dynamicFormData.email" placeholder="请输入邮箱" />
	uni-forms-item>
	<template v-for="(item,index) in dynamicFormData.domains">
		<uni-forms-item :label="item.label+' '+index" required
			:rules="[{'required': true,errorMessage: '域名项必填'}]" :key="item.id"
			:name="['domains',index,'value']">
			<view class="form-item">
				<uni-easyinput v-model="dynamicFormData.domains[index].value" placeholder="请输入域名" />
				<button class="button" size="mini" type="default" @click="del(item.id)">删除button>
			view>
		uni-forms-item>
	template>

uni-forms>
<view class="button-group">
	<button type="primary" size="mini" @click="add">新增域名button>
	<button type="primary" size="mini" @click="submit('dynamicForm')">提交button>
view>

JavaScript

export default {
	data() {
		return {
			// 数据源
			dynamicFormData: {
				email: '',
				domains: []
			},
			// 规则
			dynamicRules: {
				email: {
					rules: [{
						required: true,
						errorMessage: '域名不能为空'
					}, {
						format: 'email',
						errorMessage: '域名格式错误'
					}]
				}
			}
		}
	},
	methods: {
		// 新增表单域
		add() {
			this.dynamicFormData.domains.push({
				label: '域名',
				value:'',
				id: Date.now()
			})
		},
		// 删除表单域
		del(id) {
			let index = this.dynamicLists.findIndex(v => v.id === id)
			this.dynamicLists.splice(index, 1)
		},
		// 提交
		submit(ref) {
			this.$refs[ref].validate((err,value)=>{
				console.log(err,value);
			})
		},
	}
}

以上内容不多解释了,其中uni-forms-item的name、key应该怎么处理,官网说的很清楚了。

2、增加自定义验证

我们希望在增加email以后,提交的时候验证有没有重复的email,这个时候需要增加一个自定义规则

修改javascript如下(注意注释):

export default {
	data() {
		return {
			。。。其他内容省略。。。没有变化。。。。
			dynamicRules: {
				email: {
					rules: [{
						required: true,
						errorMessage: '域名不能为空'
					}, {
						format: 'email',
						errorMessage: '域名格式错误'
					},
					/* 增加的自定义规则内容 */
					{
						validateFunction: (rule, value, data, callback) => {
							for(let i=0; i<this.domains.length; i++){
								for(let j=i+1; j<this.domains.length; j++){
									if(this.domains.[i]===this.domains[j]) return callback('不能输入重复的域名');
								}
							}
							callback();
						}
					}]
				}
			}
		}
	},
	methods: {
		。。。其他内容省略。。。没有变化。。。。
	}
}

好了,因为使用自定义规则,所以按照官网所述,也就是“背景”中截图中的内容,我们需要在onReady中设置rules

HTML中,我们去掉了rules的绑定


<uni-forms ref="dynamicForm" :model="dynamicFormData">
	。。。。。其他内容省略。。。。。
uni-forms>
<view class="button-group">
	。。。。。省略。。。。。。
view>

javascript中,我们增加了onReady,并设置rules

export default {
	data() {
		return {
			。。。其他内容省略。。。没有变化。。。。
			dynamicRules: {
				。。。其他内容省略。。。
			}
		}
	},
	onReady() {
		// 需要在onReady中设置规则
		this.$refs.dynamicForm.setRules(this.dynamicRules)
	},
	。。。省略其他内容。。。
}

结果呢,我们会发现,新增加的域名,只能验证静态规则,也即是域名不能为空和符合email格式,验证重复性的valudateFunction没有执行

3、给动态表单字段也增加setRules

如果我们去跟踪一下内存对象,以及去看看官网内容,就会发现,uni-forms-item也有setRules方法,那么思考一下就可以知道,我们在适当的地方给它setRules,是不是也就能达到效果呢,本质上都是因为前面讲的,微信小程序中动态渲染内容不支持动态函数的问题。

接下来:

1)HTML中,我们需要给动态组件增加一个ref,让他可以被获取到(看代码中注释部分)


<uni-forms ref="dynamicForm" :model="dynamicFormData">
	。。。。。其他内容省略。。。。。
	<template v-for="(item,index) in dynamicFormData.domains">
		<uni-forms-item :label="item.label+' '+index" required
			:rules="[{'required': true,errorMessage: '域名项必填'}]" :key="item.id"
			:name="['domains',index,'value']" 
			:ref="'domain-'+index"> 
			。。。。。其他内容省略。。。。。
		uni-forms-item>
	template>
	。。。。。其他内容省略。。。。。
uni-forms>
<view class="button-group">
	。。。。。省略。。。。。。
view>

2)javascript中,在适当的地方,setRules(注意注释内容,我们设置的是具体字段的rules,而不是整个表单的rules)

javascript中,我们增加了onReady,并设置rules

```javascript
export default {
	data() {
		return {
			。。。其他内容省略。。。
			dynamicRules: {
				。。。其他内容省略。。。
			}
		}
	},
	onReady() {
		// 需要在onReady中设置规则
		this.$refs.dynamicForm.setRules(this.dynamicRules)
	},
	methods: {
		。。。省略其他内容。。。
		add() {
			this.dynamicFormData.domains.push({
				label: '域名',
				value:'',
				id: Date.now()
			})
			/* 这里,我们通过refs拿到增加的内容,然后setRules */
			this.$nextTick(()=>{/* 用nextTick是让界面先渲染 */
				/* 根据html中的ref规则,获取到uni-forms-item */
				let $refsItem = this.$refs['domain-'+(this.dynamicFormData.domains.length-1)];
				/* 对这个uni-forms-item主动setRules */
				/* 这里直接设置的是对应字段的rules */
				$refsItem [0].setRules(this.dynamicRules.email.rules);
			});
		},
		。。。省略其他内容。。。
	}
	
}

==================================================

好了,至此,动态字段的自定义验证就可以生效了。

你可能感兴趣的:(随笔,uni-app,微信小程序)