# Form 表单

此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。

# 平台兼容性

App(vue) App(nvue) H5 小程序 VUE2 VUE3

注意事项:

为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。

  1. 组件上的ref建议不要和组件重名,否则vue3的setup语法糖会报错无法正常显示,详情见常见问题-使用的ref与组件名重名-在vue3的setup语法糖中会报错
  2. 在实现查看密码等功能时,可能会子组件uv-form-item上使用v-if进行判断显示和隐藏,这时建议给uv-form-item加上key值,否则可能出现 type="password" 变成 type="text" 会失效
  3. 在app-nvue模式下,如果form-item节点下的input设置了disabled或readonly状态,会导致节点上的事件无效,所以这种情况下的解决方案:给input套一层view,再在view中用一个节点进行定位,目的就是把input给遮住,这样就可以解决问题。没办法,nvue太恶心了。

# 基本使用

此组件一般是用于表单验证使用,每一个表单域由一个uv-form-item组成,表单域中可以放置uv-inputuv-textareauv-checkboxuv-radiouv-switch等。

  • 在表单组中,通过model参数绑定一个对象,这个对象的属性为各个uv-form-item内组件的对应变量。
  • 由于表单验证和绑定表单规则时,需要通过ref操作,故这里需要给form组件声明ref="form"属性。
  • 关于uv-from-item内其他可能包含的诸如inputradio等组件,请见各自组件的相关文档说明。
<template>
	<view>
		<uv-form labelPosition="left" :model="model1" :rules="rules" ref="form">
			<uv-form-item label="姓名" prop="userInfo.name" borderBottom>
				<uv-input v-model="model1.userInfo.name" border="none">
				</uv-input>
			</uv-form-item>
			<uv-form-item label="性别" prop="userInfo.sex" borderBottom @click="showSexSelect">
				<uv-input v-model="model1.userInfo.sex" disabled disabledColor="#ffffff" placeholder="请选择性别" border="none">
				</uv-input>
				<template v-slot:right>
					<uv-icon name="arrow-right"></uv-icon>
				</template>
			</uv-form-item>
			<uv-button type="primary" text="提交" customStyle="margin-top: 10px" @click="submit"></uv-button>
			<uv-button type="error" text="重置" customStyle="margin-top: 10px" @click="reset"></uv-button>
		</uv-form>
		<uv-action-sheet ref="sexSelect" :actions="actions" title="请选择性别" description="如果选择保密会报错" @select="sexSelect">
		</uv-action-sheet>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				model1: {
					userInfo: {
						name: 'uv-ui',
						sex: '',
					},
				},
				actions: [{
					name: '男',
				}, {
					name: '女',
				}, {
					name: '保密',
				}, ],
				rules: {
					'userInfo.name': {
						type: 'string',
						required: true,
						message: '请填写姓名',
						trigger: ['blur', 'change']
					},
					'userInfo.sex': {
						type: 'string',
						max: 1,
						required: true,
						message: '请选择男或女',
						trigger: ['blur', 'change']
					},
				},
				radio: '',
				switchVal: false
			}
		},
		methods: {
			// 提交
			submit() {
				// 如果有错误,会在catch中返回报错信息数组,校验通过则在then中返回true
				this.$refs.form.validate().then(res => {
					uni.showToast({
						icon: 'success',
						title: '校验通过'
					})
				}).catch(errors => {
					uni.showToast({
						icon: 'error',
						title: '校验失败'
					})
				})
			},
			// 重置
			reset() {
				this.$refs.form.resetFields();
				this.$refs.form.clearValidate();
			},
			// 性别选择
			showSexSelect() {
				this.$refs.sexSelect.open();
				this.hideKeyboard();
			},
			// 性别选择返回结果
			sexSelect(e) {
				this.model1.userInfo.sex = e.name;
				// 对部分表单字段进行校验
				this.$refs.form.validateField('userInfo.sex',err=>{
					// 处理错误后的逻辑
				})
			},
			hideKeyboard() {
				uni.hideKeyboard()
			}
		}
	}
</script>

从上面的示例我们可以看到,rules中的属性名和form的属性名是一致的,同时传递给uv-form-itemprop参数绑定的也是相同的属性名,注意这里prop参数绑定的是 字符串(属性名),而不是一个变量。

# Tips

注意:

某些可能不支持props传递函数(如vue2编译微信小程序),为了需要兼容内置有方法,可以通过setRules方法设置规则。如下:

onReady() {
	//onReady 为uni-app支持的生命周期之一
	this.$refs.form.setRules(this.rules)
}

# Form-item组件说明

此组件一般需要搭配Form组件使用,也可以单独搭配Input等组件使用,由于此组件参数较多,这里只对其中参数最简要介绍,其余请见底部的Form-item Props说明:

  • prop为传入Form组件的model中的属性字段,如果需要表单验证,此属性是必填的。
  • labelPosition可以配置左侧"label"的对齐方式,可选为lefttop
  • borderBottom是否显示表单域的下划线,如果给Input组件配置了边框,可以将此属性设置为false,从而隐藏默认的下划线。
  • 如果想在表单域配置左右的图标或小图片,可以通过leftIconrightIcon参数实现。

# 验证规则 - rules属性示例[1]

组件验证部分采用了async-validator (opens new window),一个字段可以设置多个内置规则,以及自定义规则,触发方式等, 每个字段的验证规则为一个数组,数组的每一个元素对象为其中一条规则(一个字段的验证可以配置多个规则),如下:

rules: {
	'userInfo.name': {
		type: 'string',
		required: true,
		message: '请填写姓名',
		trigger: ['blur', 'change']
	},
	code: {
		type: 'string',
		required: true,
		len: 4,
		message: '请填写4位验证码',
		trigger: ['blur']
	},
	'userInfo.sex': {
		type: 'string',
		max: 1,
		required: true,
		message: '请选择男或女',
		trigger: ['blur', 'change']
	},
	radiovalue1: {
		type: 'string',
		min: 1,
		max: 2,
		message: '生命是美好的,弃治疗',
		trigger: ['change']
	},
	checkboxValue1: {
		type: 'array',
		min: 2,
		required: true,
		message: '不能太宅,至少选两项',
		trigger: ['change']
	},
	intro: {
		type: 'string',
		min: 3,
		required: true,
		message: '不低于3个字',
		trigger: ['change']
	},
	hotel: {
		type: 'string',
		min: 2,
		required: true,
		message: '请选择住店时间',
		trigger: ['change']
	},
	'userInfo.birthday': {
		type: 'string',
		required: true,
		message: '请选择生日',
		trigger: ['change']
	}
}

# 验证规则 - rules属性说明[2]

每一个验证规则中,可以配置多个属性,下面对常用的属性进行讲解,更具体的可以查看async-validator (opens new window)的文档说明:

  • trigger{String | Array}:触发校验的方式有2种:

    • change:字段值发生变化时校验
    • blur:输入框失去焦点时触发
    • 如果同时监听两种方式,需要写成数组形式:['change', 'blur']
  • type{String}
    内置校验规则,如这些规则无法满足需求,可以使用正则匹配、或者使用validator自定义方法并结合uv-ui自带验证规则

    • string:必须是 string 类型,默认类型
    • number:必须是 number 类型
    • boolean:必须是 boolean 类型
    • method:必须是 function 类型
    • regexp:必须是 regexp 类型,这里的正则,指的是判断字段的内容是否一个正则表达式,而不是用这个正则去匹配字段值
    • integer:必须是整数类型
    • float:必须是浮点数类型
    • array:必须是 array 类型
    • object:必须是 object 类型
    • enum:必须出现在 enmu 指定的值中
    • date:必须是 date 类型
    • url:必须是 url 类型
    • hex:必须是 16 进制类型
    • email:必须是 email 类型
    • any:任意类型
  • required
    布尔值,是否必填,配置此参数不会显示输入框左边的必填星号,如需要,请配置uv-form-itemrequiredtrue,注意:如需在uv-form-item标签内显示星号,需要给予swiper-item第一个根节点一定的margin样式

  • pattern
    要求此参数值为一个正则表达式,如: /\d+/,不能带引号,如:"/\d+/",组件会对字段进行正则判断,返回结果。

  • min
    最小值,如果字段类型为字符串和数组,会取字符串长度与数组长度(length)与min比较,如果字段是数值,则直接与min比较。

  • max
    最大值,规则同min参数

  • len
    指定长度,规则同min,优先级高于minmax

  • enum{Array} 指定的值,配合 type: 'enum' 使用

  • whitespace{Boolean}
    设置该值为true,如果字段值内容都为空格,默认无法通过required: true校验

  • transform{Function},校验前对值进行转换,函数的参数为当前值,返回值为改变后的值,参数如如下:

    • value:当前校验字段的值
  • message
    校验不通过时的提示信息

  • validator{Function}:自定义同步校验函数,参数如下:

    • rule:当前校验字段在 rules 中所对应的校验规则
    • value:当前校验字段的值
    • callback:校验完成时的回调,一般无需执行callback,返回true(校验通过)或者false(校验失败)即可
  • asyncValidator{Function}:自定义异步校验函数,参数如下:

    • rule:当前校验字段在 rules 中所对应的校验规则
    • value:当前校验字段的值
    • callback:校验完成时的回调,执行完异步操作(比如向后端请求数据验证),如果不通过,需要callback(new Error('提示错误信息')),如果校验通过,执行callback()即可

# 验证规则 - 配合uvui内置自定义效验规则[3]

uv-ui在JS板块的Test 规则校验中有大量内置的验证规则,这些规则对表单验证来说,属于自定义规则,故需要用到上方规则属性的 validator自定义验证函数,这里做一个详细说明。

我们知道uv-ui有自带的判断手机号的验证方法uni.$uv.test.mobile(value),但是async-validator (opens new window)没有 内置判断手机号的规则,所以将二者结合使用:

温馨提示

  1. 使用uni上挂载的uv-ui内置方法,需要根据扩展配置 - JS工具库进行相应的配置,否则直接会报错!
  2. 某些平台可能不支持props传递函数(如vue2编译微信小程序),可以通过调用方法解决,请注意上面的Tips
  3. 再次说明:自定义效验未生效,请在onReady中添加 this.$refs.form.setRules(this.rules)
<template>
	<view>
		<uv-form :model="form" :rules="rules" ref="form">
			<uv-form-item label="电话" prop="mobile">
				<uv-input v-model="form.mobile" placeholder="请输入电话" />
			</uv-form-item>
		</uv-form>
		<uv-button @click="submit">提交</uv-button>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				form: {
					mobile: ''
				},
				rules: {
					mobile: [{
						required: true,
						message: '此为必填字段',
						// blur和change事件触发检验
						trigger: ['blur', 'change']
					}, {
						// 自定义验证函数,见上说明,注意这里面的逻辑不能出现语法报错,否则可能导致不验证
						validator: (rule, value, callback) => {
							// 此处业务逻辑省略
							// 返回true表校验通过,返回false表示不通过
							return true;
						},
						message: '电话号码格式错误',
						trigger: ['blur']
					}]
				}
			};
		},
		onReady() {
			this.$refs.form.setRules(this.rules);
		},
		methods: {
			submit() {
				this.$refs.form.validate().then(res => {
					uni.showToast({
						icon: 'success',
						title: '校验通过'
					})
				}).catch(errors => {
					uni.showToast({
						icon: 'error',
						title: '校验失败'
					})
				})
			}
		},
	};
</script>

# 实战案例 - 配合uv-upload上传进行验证[4]

该案例说明理论上可以验证任何形式的数据,与上传组件一起验证就是一个很常见的案例,其实只需要将rules中的值定义好即可,验证的过程就是判断有没有值。

如下示例:删除图片后要做验证,则需要配置 validateField 进行单独验证,这样体验更佳。

<template>
	<view style="padding: 30rpx;">
		<uv-form :model="form" :rules="rules" ref="form">
			<uv-form-item label="姓名" prop="username">
				<uv-input v-model="form.username" placeholder="请输入姓名" />
			</uv-form-item>
			<uv-form-item label="照片" prop="pics">
				<uv-upload 
					:fileList="fileList" 
					name="1" 
					multiple 
					:maxCount="9" 
					@afterRead="afterRead" 
					@delete="deletePic" 
					:previewFullImage="true"
				></uv-upload>
			</uv-form-item>
		</uv-form>
		<uv-button @click="submit">提交</uv-button>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				fileList: [],
				form: {
					username: '',
					pics: []
				},
				rules: {
					username: [{
						required: true,
						message: '此为必填字段',
						trigger: ['blur', 'change']
					}],
					pics: {
						type: 'array',
						required: true,
						message: '请上传照片',
						trigger: ['blur', 'change']
					}
				}
			};
		},
		methods: {
			submit() {
				this.$refs.form.validate().then(res => {
					uni.showToast({
						icon: 'success',
						title: '校验通过'
					})
				}).catch(errors => {
					uni.showToast({
						icon: 'error',
						title: '校验失败'
					})
				})
			},
			afterRead(e) {
				// 这里直接模拟上传成功,这里的真实逻辑参考uv-upload组件示例
				setTimeout(() => {
					this.fileList = [{
						url: 'https://via.placeholder.com/100x100.png/3c9cff'
					}, {
						url: 'https://via.placeholder.com/100x100.png/ff0000'
					}]
					this.form.pics = this.fileList;
					this.$refs.form.validateField('pics', err => {
						// 处理错误后的逻辑
					})
				})
			},
			deletePic(e) {
				this.fileList.splice(e.index, 1);
				this.$refs.form.validateField('pics', err => {
					// 处理错误后的逻辑
				})
			}
		}
	}
</script>

# 实战案例 - 动态表单的基本用法[5]

在实际开发中,有需求动态表单,实际上也是可以通过js去实现的,核心思路是将data部分的值进行动态添加。如下示例:

<template>
	<view>
		<uv-form labelPosition="left" :model="model" :rules="rules" ref="form">
			<template v-for="(item,index) in list">
				<uv-form-item :label="item.label" :prop="item.name" borderBottom>
					<uv-input v-model="model[item.name]" border="none">
					</uv-input>
				</uv-form-item>
			</template>
			<uv-button type="info" text="添加字段" customStyle="margin-top: 10px" @click="add"></uv-button>
			<uv-button type="primary" text="提交" customStyle="margin-top: 10px" @click="submit"></uv-button>
			<uv-button type="error" text="重置" customStyle="margin-top: 10px" @click="reset"></uv-button>
		</uv-form>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				model: {},
				list: [],
				rules: {}
			}
		},
		onLoad() {
			const data = this.getData();
			data.forEach(item => {
				this.model[item.name] = '';
				this.rules[item.name] = item.rules;
			})
			this.list = data;
		},
		methods: {
			add() {
				const addData = {
					name: 'demo',
					label: '添加的项',
					rules: {
						type: 'string',
						required: true,
						message: '请填写添加项',
						trigger: ['blur', 'change']
					}
				}
				this.model[addData.name] = '';
				this.rules[addData.name] = addData.rules;
				this.list.push(addData);
			},
			// 模拟请求后端的数据
			getData() {
				return [{
					name: 'name',
					label: '姓名',
					rules: {
						type: 'string',
						required: true,
						message: '请填写姓名',
						trigger: ['blur', 'change']
					}
				}, {
					name: 'age',
					label: '年龄',
					rules: {
						type: 'string',
						required: true,
						message: '请填写年龄',
						trigger: ['blur', 'change']
					}
				}, {
					name: 'like',
					label: '爱好',
					rules: {
						type: 'string',
						required: true,
						message: '请填写兴趣爱好',
						trigger: ['blur', 'change']
					}
				}]
			},
			// 提交
			submit() {
				this.$refs.form.validate().then(res => {
					uni.showToast({
						icon: 'success',
						title: '校验通过'
					})
				}).catch(errors => {
					uni.showToast({
						icon: 'error',
						title: '校验失败'
					})
				})
			},
			// 重置
			reset() {
				this.$refs.form.resetFields();
				this.$refs.form.clearValidate();
			},
			hideKeyboard() {
				uni.hideKeyboard()
			}
		}
	}
</script>

# 验证规则 - 综合实战[6]

上面讲述了async-validator (opens new window)的规则和配置,以及uv-ui内置规则的结合使用,下面我们进行一个综合 实战示例,要入对某一个字段进行如下验证(验证实现有多种方法,下方仅为引导示例,非唯一,或最优做法):

  1. 必填,同时可接受changeblur触发校验:配置required参数为true,同时配置trigger[change, blur]
  2. 必须为字母或字符串,校验前先将字段值转为字符串类型:通过pattern参数配置正则:/^[0-9a-zA-Z]*$/g,通过transform参数在校验前对字段值转换为字符串
  3. 长度6-8个字符之间:通过 配置min为6,max为8
  4. 需要包含字母"A":使用uv-ui的uni.$uv.test.contains()方法,并结合validator自定义函数实现
  5. 异步校验,输入完账号,输入框失去焦点时,向后端请求该账号是否已存在:通过上方的asyncValidator异步函数进行验证。

综上,我们可以得出如下的一个配置规则(仅为综合演示,非最优做法):

rules: {
	name: [
		// 必填规则
		{
			required: true,
			message: '此为必填字段',
			// blur和change事件触发检验
			trigger: ['blur', 'change'],
		},
		// 正则判断为字母或数字
		{
			pattern: /^[0-9a-zA-Z]*$/g,
			// 正则检验前先将值转为字符串
			transform(value) {
				return String(value);
			},
			message: '只能包含字母或数字'
		},
		// 6-8个字符之间的判断
		{
			min: 6,
			max: 8,
			message: '长度在6-8个字符之间'
		},
		// 自定义规则判断是否包含字母"A"
		{
			validator: (rule, value, callback) => {
				return uni.$uv.test.contains(value, "A");
			},
			message: '必须包含字母"A"'
		},
		// 校验用户是否已存在
		{
			asyncValidator: (rule, value, callback) => {
				uni.$uv.http.post('/xxx/xxx', {name: value}).then(res => {
					// 如果验证不通过,需要在callback()抛出new Error('错误提示信息')
					if(res.error) {
						callback(new Error('姓名重复'));
					} else {
						// 如果校验通过,也要执行callback()回调
						callback();
					}
				})
			},
			// 如果是异步校验,无需写message属性,错误的信息通过Error抛出即可
			// message: 'xxx'
		}
	]
}

# 校验错误提示方式

uv-ui提供了多种校验的错误提示方式,传递给Form组件的errorType参数:

  • message:默认为输入框下方用文字进行提示
  • none:不会进行任何提示
  • border-bottom:配置作用域底部的下划线显示为红色,要求给form-item设置了borderBottom=true才有效
  • toast:以"toast"提示的方式弹出错误信息,每次只弹出最前面的那个表单域的错误信息
<template>
	<uv-form :errorType="errorType">
		......
	</uv-form>
</template>

<script>
export default {
	data() {
		return {
			// 文字提示
			errorType: 'message',
			// 不提示
			// errorType: 'none',
			// 下划线提示,要求给form-item设置了borderBottom=true才有效
			// errorType: 'border-bottom'
		}
	}
}
</script>

# 最终目的 - 进行校验

进行了上方的配置和讲解后,进入到最后一步,执行验证:
需要通过ref调用Form组件的validate方法,该方法回调函数的参数为一个布尔值,true为校验通过,否则反之。

// 使用 Promise
// 对整个表单进行校验,返回一个 Promise
this.$refs.form.validate().then(res => {
	// 成功返回,res 为表单数据
	// 其他逻辑处理 
	// ...
}).catch(error => {
	// 表单校验验失败,error 为具体错误信息
	// 其他逻辑处理
	// ...
})

# 完整示例

# API


# Form Props

参数 说明 类型 默认值 可选值
model 表单数据对象 Object - -
rules 通过ref设置,如果rules中有自定义方法等,需要使用setRules方法设置规则,见上方Tips说明。具体参数请参考上面的 验证规则 - rules属性示例[1]验证规则 - rules属性说明[2] Object | Function | Array - -
errorType 错误的提示方式,见上方校验错误提示方式说明 String message message | toast | border-bottom | none
borderBottom 是否显示表单域的下划线边框 Boolean true -
labelPosition 表单域提示文字的位置,left-左侧,top-上方 String left top | left
labelWidth 提示文字的宽度,单位px(rpx)。注意:在 uv-form 设置此值可能会变化抖动,可以将此值设置到 uv-form-item 节点上,效果会有所改善。 String | Number 45 数值 | auto
labelAlign lable字体的对齐方式 String left left | center | right
labelStyle lable的样式,对象形式 Object - -

# Form Methods

此方法如要通过ref手动调用

名称 说明 参数
validate 对整个表单进行校验的方法 -
setRules 如果rules中有自定义方法等,需要用此方法设置rules规则,详情参考上面的Tips Function(rules)
validateField 对部分表单字段进行校验,回调返回错误,需要自定义后续逻辑 Function(value, Function(errorsRes))
resetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 -
clearValidate 清空校验结果 Function(props)

# FormItem Props

参数 说明 类型 默认值 可选值
label 左侧提示文字 String - -
prop 表单域model对象的属性名,在使用 validate、resetFields 方法的情况下,该属性是必填的 String - -
borderBottom 是否显示下边框,如不需要下边框,需同时将uv-form的同名参数设置为false String | Boolean true true | false
labelWidth 提示文字的宽度,单位px(rpx),如设置,将覆盖uv-form的同名参数 String | Number - -
labelPosition label的位置 String - left | top
rightIcon 右侧自定义字体图标(限uv-ui内置图标)或图片地址 String - -
leftIcon 左侧自定义字体图标(限uv-ui内置图标)或图片地址 String - -
leftIconStyle 左侧自定义字体图标的样式 String | Object - -
required 是否显示左边的 * 号,这里仅起展示作用,如需校验必填,请通过rules配置必填规则。注意:如果页面没有左右边距,星号可能被遮挡,请根据情况设置样式 Boolean false true | false
customStyle 自定义样式 Object - -

# FormItem Slots

名称 说明
default form-item 的内容
right 右侧自定义内容,可以在此传入一个按钮,用于获取验证码等场景

# FormItem Events

事件名 说明 回调参数
@click 点击时触发 -