Skip to content

Form 表单

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

平台差异说明

App(vue)App(nvue)H5微信小程序

基本使用

此组件一般是用于表单验证使用,每一个表单域由一个su-form-item组成,表单域中可以放置su-inputsu-checkboxsu-radiosu-switch等。

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

下方为一个经典表单的示例,包含inputtextarearadiocheckboxswitch的组合使用:

查看基础用法示例
html
<template>
  <su-form :model="form" ref="form1">
    <su-form-item label="姓名" prop="name"><su-input v-model="form.name" /></su-form-item>
    <su-form-item label="生日" prop="birthday">
      <su-input v-model="form.birthday" type="select" @click="calendar1.show=true" />
      <su-calendar v-model="calendar1.show" mode="date" @change="onCalendar1"></su-calendar>
    </su-form-item>
    <su-form-item label="简介" prop="intro"><su-input v-model="form.intro" /></su-form-item>
    <su-form-item label="性别" prop="sex"><su-input v-model="select1.current.label" type="select" @click="select1.show=true" /></su-form-item>
    <su-form-item label="水果" prop="checkbox">
      <su-checkbox-group v-model="form.checkbox">
        <su-checkbox v-model="item.checked" v-for="(item, index) in checkboxList1" :key="index" :name="item.name">{{ item.name }}</su-checkbox>
      </su-checkbox-group>
    </su-form-item>
    <su-form-item label="味道" prop="radio">
      <su-radio-group v-model="form.radio">
        <su-radio v-for="(item, index) in radioList1" :key="index" :name="item.name" :disabled="item.disabled">{{ item.name }}</su-radio>
      </su-radio-group>
    </su-form-item>
    <su-form-item label="开关" prop="switchVal">
      <template v-slot:right>
        <su-switch v-model="form.switchVal"></su-switch>
      </template>
    </su-form-item>
  </su-form>

  <su-select v-model:show="select1.show" :list="select1.list" @confirm="onSelect1"></su-select>

  <button @click="submit">提交</button>

  <text space="ensp">{{ JSON.stringify(form,null,2) }}</text>
</template>
typescript
<script lang="ts" setup>
import { reactive, ref } from 'vue'

const form1 = ref(null)

const form = reactive({
  name: '',
  birthday: '',
  intro: '',
  sex: '',
  checkbox: '',
  radio: '',
  switchVal: false
})

const checkboxList1 = reactive([
  {
    name: '苹果',
    checked: false,
    disabled: false
  },
  {
    name: '雪梨',
    checked: false,
    disabled: false
  },
  {
    name: '柠檬',
    checked: false,
    disabled: false
  }
])

const radioList1 = reactive([
  {
    name: '鲜甜',
    disabled: false
  },
  {
    name: '麻辣',
    disabled: false
  }
])

const select1 = reactive({
  show: false,
  current: {},
  list: [
    {
      value: 1,
      label: '男'
    },
    {
      value: 2,
      label: '女'
    }
  ]
})

const calendar1 = reactive({
  show: false
})

const rules = reactive({
  name: [{ required: true, message: '请输入姓名', trigger: ['change', 'blur'] }],
  birthday: [{ required: true, message: '请选择日历', trigger: ['change', 'blur'] }],
  checkbox: [{ type: 'array', required: true, message: '请选择水果', trigger: ['blur'] }]
})

function onSelect1(arr) {
  let current = arr[0]
  let value = current.value
  select1.current = current
 form.sex = value
}
function submit() {
  form1.value.validate().then(res => {
    uni.showToast({
      icon: 'none',
      title: '表单验证通过'
    })
  }).catch(err => {
    console.log(err)
  })
}
function onCalendar1(e) {
  form.birthday = e.result
}

nextTick(() => {
  form1.value.setRules(rules)
})
</script>

Su-form-item组件说明

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

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

表单验证

Sun-ui的表单组件具备完整的验证功能,在开始之前,需要了解如下几个注意事项,方面您快速上手:

Form组件绑定model参数

  • model参数为一个对象,对象属性为需要验证的变量名。
  • 通过ref,在nextTick生命周期调用组件的setRules方法绑定验证规则,无法通过props传递变量,是因为微信小程序会过滤掉对象中的方法,导致自定义验证规则无效。
查看表单验证示例
html
<template>
  <view class="">
    <su-form :model="form" ref="form1">
      <su-form-item label="姓名" prop="name">
        <su-input v-model="form.name" />
      </su-form-item>
      <su-form-item label="简介" prop="intro">
        <su-input v-model="form.intro" />
      </su-form-item>
    </su-form>
    <su-button @click="submit">提交</su-button>
  </view>
</template>
typescript
<script lang="ts" setup>
import { reactive, ref, nextTick } from 'vue'

const form1 = ref(null)

const form = reactive({
  name: '',
  intro: ''
})

const rules = reactive({
  name: [{ required: true, message: '请输入姓名', trigger: ['change', 'blur'] }],
  intro: [{ min: 5, message: '简介不能少于5个字', trigger: 'change' }]
})


function submit() {
  form1.vue.validate((valid) => {
    if (valid) {
      console.log('验证通过')
    } else {
      console.log('验证失败')
    }
  })
}

nextTick(() => {
  form1.value.setRules(rules)
})
</script>

Su-form-item绑定labelprop

此组件最大的作用是与su-formsu-input等组件进行交互,在表单验证时,需要绑定prop参数,此参数为su-form组件的model对象中的属性名, 目的是在验证时,通过这个prop属性名将父组件su-formmodelrules规则关联起来。

注意点:

  • 通过prop绑定对应的属性名,这里是字符串,而不是一个变量。
  • 通过label参数设置左边显示的提示文字,另外通过label-position可以配置label在左边还是上方。
查看su-form-item绑定label和prop示例
html
<template>
  <su-form :model="form">
    <su-form-item label="姓名" prop="name">
      <su-input v-model="form.name" />
    </su-form-item>
    <su-form-item label="简介" prop="intro">
      <su-input v-model="form.intro" />
    </su-form-item>
  </su-form>
</template>
typescript
<script lang="ts" setup>
import { reactive, ref, nextTick } from 'vue'

const form1 = ref(null)

const form = reactive({
  name: '',
  intro: ''
})

const rules = reactive({
  name: [{ required: true, message: '请输入姓名', trigger: ['change', 'blur'] }],
  intro: [{ min: 5, message: '简介不能少于5个字', trigger: 'change' }]
})

nextTick(() => {
  form1.value.setRules(rules)
})
</script>

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

验证规则

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

js
rules: {
  name: [
    // 对name字段进行长度验证
    {
      min: 5,
      message: '简介不能少于5个字',
      trigger: 'change'
    },
    // 对name字段进行必填验证
    {
      required: true,
      message: '请填写姓名',
      trigger: ['change', 'blur']
    }
  ]
}

验证规则属性

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

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

    • change:字段值发生变化时校验
    • blur:输入框失去焦点时触发
    • 如果同时监听两种方式,需要写成数组形式:['change', 'blur']
  • type 内置校验规则,如这些规则无法满足需求,可以使用正则匹配、或者使用validator自定义方法并结合uView自带验证规则。- 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 布尔值,是否必填,配置此参数不会显示输入框左边的必填星号,如需要,请配置u-form-itemrequiredtrue

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

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

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

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

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

  • whitespace 如果字段值内容都为空格,默认无法通过required: true校验,如果要允许通过,需要将此参数设置为true

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

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

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

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

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

Sun-ui自带验证规则

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

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

js
rules: {
  // 字段名称
  mobile: [
    {
      required: true,
      message: '请输入手机号',
      trigger: ['change', 'blur']
    },
    {
      // 自定义验证函数,见上说明
      validator: (rule, value, callback) => {
        // 上面有说,返回true表示校验通过,返回false表示不通过
        // this.$u.test.mobile()就是返回true或者false的
        return uni.$u.test.mobile(value)
      },
      message: '手机号码不正确',
      // 触发器可以同时用blur和change
      trigger: ['change', 'blur']
    }
  ]
}

综合实战

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

  1. 必填,同时可接受changeblur触发校验:配置required参数为true,同时配置trigger[change, bulr]
  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异步函数进行验证。

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

js
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.post('/xxx/xxx', {name: value}).then(res => {
					// 如果验证不通过,需要在callback()抛出new Error('错误提示信息')
					if(res.error) {
						callback(new Error('姓名重复'));
					} else {
						// 如果校验通过,也要执行callback()回调
						callback();
					}
				})
			},
			// 如果是异步校验,无需写message属性,错误的信息通过Error抛出即可
			// message: 'xxx'
		}
	]
}

校验错误提示方式

Sun-uni提供了多种校验的错误提示方式,这些值需要包含在数组(可以填写多个值,同时进行多种提示)中,传递给Form组件的errory-type参数:

  • message:默认为输入框下方用文字进行提示
  • none:只要包含此值,将不会进行任何提示
  • border-bottom:配置作用域底部的下划线显示为红色
  • toast:以"toast"提示的方式弹出错误信息,每次只弹出最前面的那个表单域的错误信息
html
<template>
  <su-form :error-type="errorType">......</u-form>
</template>

<script lang="ts" setup>
  import { ref } from 'vue'

  // 不提示
  // errorType: ['none']
  // 文字和下划线提示
  // errorType: ['message', 'border-bottom']
  const errorType = ref(['message'])
</script>

校验

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

html
<template>
  <view class="">
    <su-form :model="form" ref="form1">
      <su-form-item label="姓名" prop="name">
        <su-input v-model="form.name" />
      </u-form-item>
    </u-form>
    <u-button @click="submit">提交</u-button>
  </view>
</template>

<script lang="ts" setup>
  import { ref } from 'vue'
  const form1 = ref(null)

  const form = reactive({
    name: ''
  })

  const rules = reactive({
    name: [
      {
        required: true,
        message: '请输入姓名',
        trigger: ['blur', 'change']
      }
    ]
  })


  function submit() {
    form1.value.validate().then(() => {
      console.log('验证通过')
    }).catch((error) => {
      console.log(error)
    })
  }

  nextTick(() => {
    form1.value.setRules(rules)
  })
</script>

动态表单

  • su-form-item 设置rules,不需要setRules设置规则
  • prop 为传入model的数据key。如:model={ list: [{ label: '' }] }, 那么写list.${index}.name, index为循环索引
html
<template>
  <su-form :model="formModel3.model" ref="form3" labelPosition="top" labelWidth="100%">
    <su-form-item label="姓名" prop="name" borderBottom>
      <su-input v-model="formModel3.model.name" border="none" placeholder="姓名,只能为中文"></su-input>
    </su-form-item>
    <template v-for="(item, index) in formModel3.model.list" :key="item.key">
      <su-form-item
        label="model姓名"
        :prop="`list.${index}.name`"
        borderBottom
        labelPosition="top"
        labelWidth="100%"
        required
        :rules="[
          {
            type: 'string',
            required: true,
            message: '请填写model姓名',
            trigger: ['blur', 'change']
          }
        ]"
      >
        <su-input v-model="item.name" border="none" placeholder="请填写model姓名"></su-input>
      </su-form-item>
      <su-form-item
        label="model标签"
        :prop="`list.${index}.label`"
        borderBottom
        labelPosition="top"
        labelWidth="100%"
        required
        :rules="[
          {
            type: 'string',
            required: true,
            message: '请填写model标签',
            trigger: ['blur', 'change']
          }
        ]"
      >
        <su-input v-model="item.label" border="none" placeholder="请填写model标签"></su-input>
      </su-form-item>
    </template>
  </su-form>
  <su-button type="primary" text="添加表单" customStyle="margin-top: 50px" @click="addFormItem"></su-button>
  <su-button type="primary" text="验证" customStyle="margin-top: 50px" @click="submitForm3"></su-button>
</template>

<script lang="ts" setup>
  const form3 = ref<UniFormRef | null>(null)

  const formModel3 = reactive({
    model: {
      name: '',
      list: [
        {
          label: '',
          name: '',
          key: Date.now()
        }
      ]
    }
  })

  function addFormItem() {
    formModel3.model.list.push({
      label: '',
      name: '',
      key: Date.now()
    })
  }

  function submitForm3() {
    form3.value
      .validate()
      .then((res) => {
        uni.$u.toast('校验通过')
      })
      .catch((errors) => {
        console.log(errors)
        uni.$u.toast('校验失败')
      })
  }
</script>

示例源码

点击可以查看 右侧演示页面的源码

API

Form Props

参数说明类型默认值可选值
model表单数据对象Object--
rules通过ref设置,见上方说明Object--
error-type错误的提示方式,数组形式,见上方说明Array['message']-
border-bottom是否显示表单域的下划线边框Booleantrue-
label-position表单域提示文字的位置,left-左侧,top-上方Stringlefttop
label-width提示文字的宽度,单位rpxString | Number90数值 / auto
label-stylelabel的样式,对象形式Object--
label-alignlabel的对齐方式Stringleftcenter / right

Form Methods

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

名称说明参数
setRules调用此方法,设置校验规则Function(rules)
resetFields对整个表单进行重置,将所有字段值重置为初始值并移除校验结果-
validate对整个表单进行校验的方法Function(callback: Function(boolean))

Form-item Props

参数说明类型默认值可选值
label左侧提示文字String--
prop表单域model对象的属性名,在使用 validate、resetFields 方法的情况下,该属性是必填的String--
border-bottom是否显示下边框,如不需要下边框,需同时将su-form的同名参数设置为falseBooleantruetrue / false
label-position表单域提示文字的位置,left-左侧,top-上方,如设置,将覆盖su-form的同名参数String-left / top
label-width提示文字的宽度,单位rpx,如设置,将覆盖su-form的同名参数String | Number--
label-stylelabel的样式,对象形式,如设置,将覆盖su-form的同名参数Object--
label-alignlabel的对齐方式,如设置,将覆盖su-form的同名参数String--
right-icon右侧自定义字体图标(限uView内置图标)或图片地址String-
left-icon左侧自定义字体图标(限uView内置图标)或图片地址String-
left-icon-style左侧图标的样式,对象形式Object--
right-icon-style右侧图标的样式,对象形式Object--
required是否显示左边的"*"号,这里仅起展示作用,如需校验必填,请通过rules配置必填规则Booleanfalsetrue

Form-item Slot

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

Released under the MIT License.

Released under the MIT License.