# Form 表单

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

# 基本使用

此组件一般是用于表单验证使用,每一个表单域由一个un-form-item组成,表单域中可以放置un-inputun-checkboxun-radioun-switch等。

  • 在表单组中,通过model参数绑定一个对象,这个对象的属性为各个un-form-item内组件的对应变量。
  • 由于表单验证和绑定表单规则时,需要通过ref操作,故这里需要给form组件声明ref="formRef"属性。
  • 关于un-from-item内其他可能包含的诸如inputradio等组件,请见各自组件的相关文档说明。

注意

model 属性的数据类型是 UTSJSONObject 中响应式数据的绑定,需要使用 reactive 函数创建。不支持多级嵌套的响应式数据绑定。

v-model="formData.userInfo.name" 这种使用是错误的

<template>
    <view class="u-page">
        <view class="u-demo-block">
            <text class="u-demo-block__title">基础使用</text>
            <view class="u-demo-block__content">
                <un-form
                    labelPosition="left"
                    :model="formData"
                    :rules="formRules"
                    ref="formRef"
                >
                    <un-form-item
                        label="姓名"
                        prop="name"
                        borderBottom
                    >
                        <un-input
                            v-model="formData['name']"
                            border="none"
                            placeholder="请输入姓名"
                        ></un-input>
                    </un-form-item>
                    <un-form-item
                        label="性别"
                        prop="sex"
                        borderBottom
                        @click="handleSexClick"
                    >
                        <un-input
                            v-model="formData['sex']"
                            disabled
                            disabledColor="#ffffff"
                            placeholder="请选择性别"
                            border="none"
                        ></un-input>
                        <un-icon
                            slot="right"
                            name="arrow-right"
                        ></un-icon>
                    </un-form-item>
                    <un-form-item
                        label="水果"
                        prop="radiovalue1"
                        borderBottom
                    >
                        <un-radio-group v-model="formData['radiovalue1']"> 
                            <un-radio 
                                v-for="(item, index) in radiolist1"
                                :key="index" 
                                :label="item.name" 
                                :name="item.name"
                            ></un-radio>
                        </un-radio-group>
                    </un-form-item>
                    <un-form-item
                        label="兴趣爱好"
                        prop="checkboxValue1"
                        borderBottom
                        labelWidth="80"
                    >
                         <un-checkbox-group
                            v-model="formData['checkboxValue1']"
                            shape="square"
                        >
                            <un-checkbox
                                v-for="(item, index) in checkboxList1"
                                :key="index"
                                :label="item.name"
                                :name="item.name"
                            ></un-checkbox>
                        </un-checkbox-group> 
                    </un-form-item>
                    <un-form-item
                        label="简介"
                        prop="intro"
                        borderBottom
                    >
                        <un-textarea
                            placeholder="不低于3个字"
                            v-model="formData['intro']"
                            count
                        ></un-textarea>
                    </un-form-item>
                </un-form>
                
                <!-- 提交和重置按钮 -->
                <un-button
                    type="primary"
                    text="提交"
                    customStyle="margin-top: 50px"
                    @click="submit"
                ></un-button>
                <un-button
                    type="error"
                    text="重置"
                    customStyle="margin-top: 10px"
                    @click="reset"
                ></un-button>
                
                <un-action-sheet
                    :show="showSex"
                    :actions="actions"
                    title="请选择性别"
                    description="如果选择保密会报错"
                    @close="showSex = false"
                    @select="sexSelect"
                ></un-action-sheet>
            </view>
        </view>
    </view>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { UnValidateResult } from '@/uni_modules/uview-unix/components/un-form'
import type { UnActionSheetAction, UnActionSheetSelectEvent } from '@/uni_modules/uview-unix/components/un-action-sheet'

type RadioItem = {
    name: string;
    disabled: boolean;
};

type CheckboxItem = {
    name: string;
    disabled: boolean;
};

// 响应式数据定义
const showSex = ref<boolean>(false)

// 表单模型
const formData = reactive({
    name: 'uView UI',
    sex: '',
    radiovalue1: '苹果',
    checkboxValue1: [] as string[],
    intro: '',
})

// 表单选项数据
const actions = ref<UnActionSheetAction[]>([
    { name: '男' },
    { name: '女' },
    { name: '保密' },
])

const radiolist1 = ref<RadioItem[]>([
    { name: '苹果', disabled: false },
    { name: '香蕉', disabled: false },
    { name: '毒橙子', disabled: false },
])

const checkboxList1 = ref<CheckboxItem[]>([
    { name: '羽毛球', disabled: false },
    { name: '跑步', disabled: false },
    { name: '爬山', disabled: false },
])

// 表单校验规则
const formRules = {
    name: [
        {
            type: 'string',
            required: true,
            message: '请填写姓名',
            trigger: ['blur', 'change'],
        },
        {
            // 同步验证示例
            validator: (rule: any, value: string, callback: (message?: string) => void) => {
                if (value.length > 5) {
                    return false // 返回false,验证不通过
                }
                return true // 返回true,验证通过
            },
            message: '名字不能大于5个字符',
            trigger: ['change', 'blur'],
        },
        {
            // 异步验证示例
            validator: (rule: any, value: any, callback: (message?: string) => void) => {
                setTimeout(() => {
                    if (!/^[\u4e00-\u9fa5]+$/.test(value.toString())) {
                        callback('姓名必须为中文')
                    }
                    callback(null) //必须返回null
                }, 200)
            },
            trigger: ['change', 'blur'],
        },
    ],
    sex: {
        type: 'string',
        max: 1,
        required: true,
        message: () => {
            return '请选择性别'
        },
        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'],
    },
}

const formRef = ref<UnFormComponentPublicInstance | null>(null)

/**
 * 处理性别点击事件
 */
const handleSexClick = () => {
    showSex.value = true
    uni.hideKeyboard()
}

/**
 * 性别选择
 */
const sexSelect = (action: UnActionSheetSelectEvent) => {
    formData['sex'] = action.item.name!
    showSex.value = false
}

/**
 * 表单提交 - 包含完整校验
 */
const submit = () => {
    formRef.value?.validate().then((result: UnValidateResult) => {
        if (result.valid) {
            uni.showToast({
                title: '校验通过',
            })
        } else {
            uni.showToast({
                title: result.errors[0].message,
                icon: 'none'
            })
        }
    })
}

/**
 * 表单重置
 */
const reset = () => {
    formRef.value?.resetFields()
}
</script>

<style lang="scss">
.u-page {
    background-color: #fff;
}

.u-demo-block__content {
    padding: 20rpx;
}
</style>
✅ Copy success!

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

# Form-item组件说明

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

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

# 验证规则

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

const rules = ref({
	name: {
		type: 'string',
				required: true,
				message: '请填写姓名',
				trigger: ['blur', 'change']
	},
	code: {
		type: 'string',
				required: true,
				len: 4,
				message: '请填写4位验证码',
				trigger: ['blur']
	},
	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']
	},
	birthday: {
		type: 'string',
				required: true,
				message: '请选择生日',
				trigger: ['change']
	}
})
✅ Copy success!

# 验证规则属性

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

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

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

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

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

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

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

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

  • message
    校验不通过时的提示信息

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

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

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

# 综合实战

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

  1. 必填,同时可接受changeblur触发校验:配置required参数为true,同时配置trigger[change, blur]
  2. 必须为字母或字符串,校验前先将字段值转为字符串类型:通过pattern参数配置正则:/^[0-9a-zA-Z]*$/g,通过transform参数在校验前对字段值转换为字符串
  3. 长度6-8个字符之间:通过 配置min为6,max为8
  4. 需要包含字母"A":使用uView的uni.$u.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.$u.test.contains(value, "A");
			},
			message: '必须包含字母"A"'
		},
		// 校验用户是否已存在
		{
			asyncValidator: (rule, value, callback) => {
				uni.$u.http.post('/xxx/xxx', {name: value}).then(res => {
					// 如果验证不通过,需要在callback()抛出new Error('错误提示信息')
					if(res.error) {
						callback(new Error('姓名重复'));
					} else {
						// 如果校验通过,也要执行callback()回调
						callback();
					}
				})
			},
			// 如果是异步校验,无需写message属性,错误的信息通过Error抛出即可
			// message: 'xxx'
		}
	]
}
✅ Copy success!

# 校验错误提示方式

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

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

✅ Copy success!

# 校验

进行了上方的配置和讲解后,进入到最后一步,执行验证:
需要通过ref调用Form组件的validate方法,该方法返回一个Promise对象,包含校验结果。

<template>
    <view class="u-page">
        <view class="u-demo-block">
            <text class="u-demo-block__title">表单校验示例</text>
            <view class="u-demo-block__content">
                <un-form :model="formData" ref="formRef" :rules="formRules">
                    <un-form-item label="姓名" prop="name" borderBottom>
                        <un-input v-model="formData['name']" border="none" placeholder="请输入姓名"></un-input>
                    </un-form-item>
                </un-form>
                <un-button type="primary" text="提交" customStyle="margin-top: 20px" @click="submit"></un-button>
            </view>
        </view>
    </view>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import type { UnValidateResult } from '@/uni_modules/uview-unix/components/un-form'

// 表单模型
const formData = reactive({
    name: '',
})

// 表单校验规则
const formRules = {
    name: [
        {
            type: 'string',
            required: true,
            message: '请输入姓名',
            trigger: ['blur', 'change']
        }
    ]
}

const formRef = ref<UnFormComponentPublicInstance | null>(null)

/**
 * 表单提交
 */
const submit = () => {
    formRef.value?.validate().then((result: UnValidateResult) => {
        if (result.valid) {
            uni.showToast({
                title: '校验通过',
            })
        } else {
            uni.showToast({
                title: result.errors[0].message,
                icon: 'none'
            })
        }
    })
}
</script>

<style lang="scss">
.u-page {
    background-color: #fff;
}

.u-demo-block__content {
    padding: 20rpx;
}
</style>
✅ Copy success!

# API

# Form Props

参数 说明 类型 默认值 可选值
model 表单数据对象 UTSJSONObject - -
rules 表单校验规则 UTSJSONObject - -
errorType 错误的提示方式,见上方说明 string message none | toast | border-bottom | none
borderBottom 是否显示表单域的下划线边框 Boolean true -
labelPosition 表单域提示文字的位置,left-左侧,top-上方 string left top
labelWidth 提示文字的宽度,单位px string | number 45 数值 / auto
labelAlign lable字体的对齐方式 string left center / right
labelStyle lable的样式,对象形式 UTSJSONObject | string - -

# Form Methods

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

名称 说明 参数
validate 对整个表单进行校验的方法 -
validateField 对部分表单字段进行校验 Function(value, Function(errorsRes))
resetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 -

# Form-item Props

参数 说明 类型 默认值 可选值
label 左侧提示文字 string - -
prop 表单域model对象的属性名,在使用 validate、resetFields 方法的情况下,该属性是必填的 string - -
rules 表单校验规则 UTSJSONObject - -
borderBottom 是否显示下边框,如不需要下边框,需同时将un-form的同名参数设置为false string | Boolean true true / false
labelWidth 提示文字的宽度,单位rpx,如设置,将覆盖un-form的同名参数 string | number - -
labelPosition label的位置 string - left / top
rightIcon 右侧自定义字体图标(限uView内置图标)或图片地址 string - -
leftIcon 左侧自定义字体图标(限uView内置图标)或图片地址 string - -
leftIconStyle 左侧自定义字体图标的样式 string | Object - -
required 是否显示左边的"*"号,这里仅起展示作用,如需校验必填,请通过rules配置必填规则,如需在swiper标签内显示星号,需要给予swiper-item内第一个根节点一定的margin样式 Boolean false true

# Form-item Slot

名称 说明
- Form Item 的内容
right 右侧自定义内容,可以在此传入一个按钮,用于获取验证码等场景
error 自定义传入校验错误时显示的信息,通过作用域插槽暴露了内部当前message错误信息

# Form-item Events

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

# 数据类型

Form组件导出了以下数据类型,用于表单校验结果的类型安全处理:

类型名称 说明 属性 类型 描述
UnValidateError 校验错误信息类型 field string 字段名称
message string 错误提示信息
UnValidateResult 表单校验结果类型 valid boolean 校验是否通过
errors UnValidateError[] 错误信息列表
/**
 * 校验错误信息类型
 * 用于表示单个字段的校验错误
 */
type UnValidateError = {
	field: string;      // 字段名
	message: string;    // 错误消息
}

/**
 * 表单校验结果类型
 * 用于表示整个表单的校验结果
 */
type UnValidateResult = {
	valid: boolean;            // 校验是否通过
	errors: UnValidateError[]; // 错误信息列表
}
✅ Copy success!
上次更新时间: 2025/10/28 21:19:58
当前文档拷贝至3.x版本,尚不完善,我们正在努力完善中,欢迎您的反馈和参与改进。
×