Skip to content

Form 表单 1.0.13

手机扫码预览
23:59

组件名:rice-form

表单组件用于数据校验,支持异步校验。1.0.13 版本开始支持。

平台兼容性

uni-app x

AndroidiOS鸿蒙Next微信小程序h5

验证规则

Form 组件提供了表单验证规则,只需为 rules 属性传入约定的验证规则,并将 FormItemname 属性设置为需要验证的特殊键值即可。

  • Form 组件上通过 rules 定义表单校验规则,注意rules为 Map<string, FormRules[]> 类型; FormRules数据结构见下
  • FormItem 组件上通过 rules 定义表单项校验规则,注意rules为 FormRules[] 类型;
  • rules 可统一配置在 Form 上,也可单独定义在 FormItem 上,最终所有规则会自动合并;
  • Form 组件上的 model 为表单数据对象,可以是 UTSJSONObject 类型,也可以是自定义type类型,如
ts
//UTSJSONObject <rice-form :model="form1"/>
const form1=ref({
  username: '',
  password: '',
})
//自定义type  <rice-form :model="form2"/>
type Form2 = {
  username : string,
  password : string
}
const form2 = ref<Form2>({
  username: '',
  password: '',
})

是否必填

  • 可以在 FormItem 上 设置 requiredtrue,此时默认的错误提示message 为 必填项,如果需要自定义 message,请通过 rules 设置必填。
ts
// 在 Form 上使用,注意写在Form上面的为 Map 类型; 也可以使用 ref 响应式数据进行定义 ref<Map<string,FormRules[]>>(...)
const rules = new Map<string, FormRules[]>([
  [
    "username",
    [{ required: true, message: '请输入用户名',trigger: 'blur' }]
  ],
  [
    "password",
    [{required: true, message: '请输入密码'}]
  ]
])
// 在 FormItem 上使用,注意写在Form上面的为 FormRules[] 类型
const usernameRules = ref<FormRules[]>([{ required: true, message: '请输入用户名',trigger: 'blur'}])

最大值和最小值/长度

当值为数字类型时,比较的是数字的大小;当值为字符串/数组时,比较的是字符串/数组的长度

ts
// 在 Form 上使用,注意写在Form上面的为 Map 类型
const rules = new Map<string, FormRules[]>([
  [
    "username",
    [{ min: 3, max: 10, message: '字数需为 3 至 10 位'}]
  ]
])
// 在 FormItem 上使用,注意写在Form上面的为 FormRules[] 类型
const usernameRules = ref<FormRules[]>([{ min: 3, max: 10, message: '字数需为 3 至 10 位'}])

通过 pattern 进行正则校验

通过正则表达式进行校验,正则无法匹配表示校验不通过

ts
// 在 Form 上使用,注意写在Form上面的为 Map 类型
const rules = new Map<string, FormRules[]>([
  [
    "phone",
    [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'all' }]
  ],
])

通过 validator 进行函数校验

通过函数进行校验,返回true表示校验通过,返回false或字符串表示校验不通过,其中字符串即为错误提示。
注意:value 的类型为 any,如需使用特定数据类型的方法,需要使用 as 进行类型断言

ts
	//密码的校验函数
const passwordValidator = (value : any | null) => {
  const val = value as string
  if (val.length < 6) return '密码的长度不能小于6位'
  if (val.startsWith('123456')) return '密码开头不能为连续的123456'
  //只有返回 true 才表示校验通过
  return true
}
// 在 Form 上使用,注意写在Form上面的为 Map 类型
const rules = new Map<string, FormRules[]>([
  [
   "password",
    [{ validator: passwordValidator }]
  ]
])

通过 validator 进行异步函数校验

可以返回一个 Promise 来进行异步校验

ts
//异步校验函数,直接返回一个 Promise 对象 示例
const usernameAsyncValidator = (value : any | null) => {
  return new Promise<boolean | string>((resolve) => {
    setTimeout(() => {
      //只有返回 true 才表示校验通过
      resolve(value == '123' ? true : '请输入123')
    }, 500)
  })
}
// 模拟网络请求
const sleep = (value : string) => {
  return new Promise<boolean>((resolve) => {
    setTimeout(() => {
      resolve(value == '123456')
    }, 1500)
  })
}
//异步校验函数 使用 async/await 示例
const passwordAsyncValidator = async (value : any | null) => {
  const res = await sleep(value as string)
  return res
}
//异步校验函数
const rules = new Map<string, FormRules[]>([
  [
    "username",
    [{ validator: usernameAsyncValidator, trigger: 'blur' }]
  ],
  [
    "password",
    [{ validator: passwordAsyncValidator, trigger: 'blur', message: '请输入123456' }]
  ],
])

基础用法

vue
<template>
  <rice-form :model="form1" :rules="rules1" ref="formRef1" label-width="100px" class="demo-form">
    <rice-form-item name="username" label="用户名">
      <rice-input v-model="form1['username']" placeholder="请输入用户名" border="none" :custom-style="inputStyle" />
    </rice-form-item>
    <rice-form-item name="phone" label="手机号" show-required>
      <rice-input v-model="form1['phone']" placeholder="请输入手机号" border="none" type="number"
        :custom-style="inputStyle" />
    </rice-form-item>
    <rice-form-item name="password" label="密码" required :rules="passwordRules">
      <rice-input v-model="form1['password']" placeholder="请输入密码" border="none" type="password"
        :custom-style="inputStyle" />
    </rice-form-item>
  </rice-form>
  <view class="flex">
    <rice-button type="primary" text="提 交" class="btn" shape="round" @click="submit1" />
    <rice-button type="success" text="只校验密码" class="btn" shape="round" :custom-style="{marginLeft:'12px'}"
      @click="checkPassword" />
  </view>
  <text class="reset-text" @click="clearAllValidate">点我清除校验结果</text>
</template>
ts
import { FormRules, FormValidateErrors } from "@/uni_modules/rice-ui"
const form1 = ref({
  username: '',
  phone: '',
  password: '',
})
//密码的校验函数
const passwordValidator = (value : any | null) => {
  const val = value as string
  if (val.length < 6) return '密码的长度不能小于6位'
  if (val.startsWith('123456')) return '密码开头不能为连续的123456'
  //只有返回 true 才表示校验通过
  return true
}
//rules 校验规则,注意写在Form上面的为 Map 类型
const rules1 = new Map<string, FormRules[]>([
  [
    "username",
    [
      { required: true, message: '请输入用户名' },
      { min: 3, max: 10, message: '字数需为 3 至 10 位', trigger: 'blur' },
    ]
  ],
  [
    "phone",
    //正则校验
    [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'all' }]
  ],
  [
    "password",
    [
      //函数校验
      { validator: passwordValidator },
      //正则校验
      { pattern: /[a-zA-Z].*\d|\d.*[a-zA-Z]/, message: '密码需要包含字母和数字' },
    ]
  ]
])
//写在formItem上的rules
const passwordRules = ref<FormRules[]>([{ max: 12, message: '密码的长度不能大于12位' }])

const formRef1 = ref<RiceFormComponentPublicInstance | null>(null)

const submit1 = async () => {
  const result = await formRef1.value!.validate()
  //校验成功
  if (result == true) {
    showToast('校验成功')
  } else {
    //校验失败,返回校验失败的数组集合
    const errsName = (result as FormValidateErrors[]).map(v => v.name)
    console.log('校验失败的name合集', errsName)
  }
}
//只校验密码
const checkPassword = async () => {
  const result = await formRef1.value!.validateFields(['password'])
  const errMsg = result == true
    ? '密码校验成功'
    : '密码校验失败:' + (result as FormValidateErrors[])[0].message
  showToast(errMsg)
}
// 清除校验结果
const clearAllValidate = () => {
  formRef1.value!.clearAllValidate()
  //清除指定字段的校验信息可调用以下方法
  // formRef1.value!.clearValidate(['username','password'])
}
//自定义 rice-input 的样式
const inputStyle = ref({
  height: '24px',
  padding: '0px',
  backgroundColor: 'transparent',
})
scss
.demo-form {
  background-color: var(--demo-block-color);
  padding: 0 16px;
}

.btn {
  flex: 1;
}

.flex {
  flex-direction: row;
  flex-wrap: wrap;
  background-color: var(--demo-block-color);
  padding: 16px;
}

.reset-text {
  background-color: var(--demo-block-color);
  text-align: right;
  font-size: 12px;
  color: var(--demo-text-color-2);
  padding-bottom: 12px;
  padding-right: 18px;
  /* #ifdef WEB */
  cursor: pointer;
  /* #endif */
}

异步校验

vue
<template>
  <rice-form :model="form2" :rules="rules2" ref="formRef2" label-width="100px" class="demo-form">
    <rice-form-item name="username" label="用户名">
      <rice-input v-model="form2.username" placeholder="输入123才校验成功" border="none" :custom-style="inputStyle" />
    </rice-form-item>
    <rice-form-item name="password" label="密码">
      <rice-input v-model="form2.password" placeholder="输入123456才校验成功" border="none" :custom-style="inputStyle" />
    </rice-form-item>
  </rice-form>
  <view class="flex">
    <rice-button type="primary" text="提 交" class="btn" shape="round" @click="submit2" />
  </view>
</template>
ts
import { FormRules, FormValidateErrors } from "@/uni_modules/rice-ui"
type Form2 = {
  username : string,
  password : string
}
const form2 = ref<Form2>({
  username: '',
  password: '',
})
//异步校验函数,直接返回一个 Promise 对象 示例
const usernameAsyncValidator = (value : any | null) => {
  return new Promise<boolean | string>((resolve) => {
    setTimeout(() => {
      //只有返回 true 才表示校验通过
      resolve(value == '123' ? true : '请输入123')
    }, 500)
  })
}
// 模拟异步操作
const sleep = (value : string) => {
  return new Promise<boolean>((resolve) => {
    setTimeout(() => {
      resolve(value == '123456')
    }, 1500)
  })
}
//异步校验函数 使用 async/await 示例
const passwordAsyncValidator = async (value : any | null) => {
  const res = await sleep(value as string)
  return res
}

//异步校验函数
const rules2 = new Map<string, FormRules[]>([
  [
    "username",
    [
      { required: true, message: '请输入用户名', trigger: 'blur' },
      { validator: usernameAsyncValidator, trigger: 'blur' },
    ]
  ],
  [
    "password",
    [{ validator: passwordAsyncValidator, trigger: 'blur', message: '请输入123456' }]
  ],

])
const formRef2 = ref<RiceFormComponentPublicInstance | null>(null)
const submit2 = async () => {
  uni.showLoading({
    title: '校验中…',
    mask: true
  })
  const result = await formRef2.value!.validate()
  uni.hideLoading()
  //校验成功
  if (result == true) {
    showToast('校验成功')
  } else {
    //校验失败,返回校验失败的数组集合
    const errs = (result as FormValidateErrors[]).map(v => `${v.label}:${v.message}`).join('/')
    showToast(errs)
  }
}
//自定义 rice-input 的样式
const inputStyle = ref({
  height: '24px',
  padding: '0px',
  backgroundColor: 'transparent',
})

自定义样式

  • required-position 可以设置必填符号的位置,支持 leftright;
  • error-bottom 可以设置校验未通过时下边框是否描红,仅 border-bottomtrue 时生效;
  • label-style 可以设置标签的颜色大小等样式;
  • content-style 可以设置 FormItem 内容区域的样式;
  • error-style 可以设置错误提示区域的样式,如文字样式大小等样式,如想要此区域与label左对齐,设置 {marginLeft:0}即可;
vue
<template>
  <rice-form :model="form3" label-width="100px" required-position="right" error-bottom
    :label-style="{fontSize:'26rpx'}" :error-style="{'text-align':'right'}" :disabled="formStatus=='disabled'"
    :readonly="formStatus=='readonly'" ref="formRef3" class="demo-form">
    <rice-form-item label="用户名" name="username" required>
      <rice-input v-model="form3.username" placeholder="请输入用户名" border="none" :custom-style="inputStyle"
        input-align="right" />
    </rice-form-item>
    <rice-form-item label="生日" name="birthday" required suffix-icon="arrow-down" @click="showDatePicker=true">
      <rice-input v-model="form3.birthday" placeholder="请选择生日" border="none" :custom-style="inputStyle" readonly
        input-align="right" />
    </rice-form-item>
    <rice-form-item label="性别" name="gender" required :rules="genderRules"
      :content-style="{'align-items':'flex-end'}">
      <rice-radio-group v-model="form3.gender" direction="row">
        <rice-radio value="man" label="男" />
        <rice-radio value="woman" label="女" />
        <rice-radio value="unknow" label="保密" />
      </rice-radio-group>
    </rice-form-item>
  </rice-form>
  <view class="flex">
    <rice-button type="primary" text="提 交" class="btn" shape="round" @click="submit3" />
  </view>
  <!-- 日期选择 -->
  <rice-datetime-picker v-model:show="showDatePicker" min-date="1900-01-01" max-date="2025-12-01"
    model-value="2000-01-01" title="选择生日" @confirm="onDateConfirm" />
</template>
ts
import { FormRules, FormValidateErrors } from "@/uni_modules/rice-ui"
type Form3 = {
  username : string,
  birthday : string,
  gender : 'man' | 'woman'
}
const form3 = ref<Form3>({
  username: '',
  birthday: '',
  gender: 'man'
})
const formStatus = ref('normal')
const genderValidator = (value : any | null) => {
  if (value == 'unknow') return '未知的性别'
  return true
}
const genderRules = ref<FormRules[]>([{ validator: genderValidator }])
const formRef3 = ref<RiceFormComponentPublicInstance | null>(null)
const submit3 = async () => {
  const result = await formRef3.value!.validate()
  //校验成功
  if (result == true) {
    showToast('校验成功')
  } else {
    showToast('校验未通过')
    //校验失败,返回校验失败的数组集合
    const errsName = (result as FormValidateErrors[]).map(v => v.name)
    console.log('校验失败的name合集', errsName)
  }
}
//选择日期
const showDatePicker = ref(false)
const onDateConfirm = (val : string) => {
  form3.value.birthday = val
}
//自定义 rice-input 的样式
const inputStyle = ref({
  height: '24px',
  padding: '0px',
  backgroundColor: 'transparent',
})

自定义插槽

支持 labelerror, suffix 插槽

vue
<template>
  <rice-form :model="form4" ref="formRef4" class="demo-form" label-position="top">
    <rice-form-item name="username" :content-style="{'flex-direction':'row'}" required :border-bottom="false">
      <template #label>
        <view class="slot-label">
          <text class="slot-label__text">用户名</text>
          <rice-icon name="info" />
        </view>
      </template>
      <input v-model="form4.username" placeholder="请输入用户名" class="form-input" />
      <template #error="{message}">
        <view class="error-slot">
          <rice-icon name="info" color="#ee0a24" size="14px" />
          <text class="error-slot__text">用户名校验失败:{{message}}</text>
        </view>
      </template>
      <template #suffix>
        <rice-icon name="user" size="18px" :custom-style="{'margin-left':'10px'}" />
      </template>
    </rice-form-item>
  </rice-form>
  <view class="flex">
    <rice-button type="primary" text="提 交" class="btn" shape="round" @click="submit4" />
  </view>
</template>
ts
import { FormRules, FormValidateErrors } from "@/uni_modules/rice-ui"
type Form4 = {
  username : string,
  password : string,
}
const form4 = ref<Form4>({
  username: "",
  password: "",
})
const formRef4 = ref<RiceFormComponentPublicInstance | null>(null)
const submit4 = async () => {
  const result = await formRef4.value!.validate()
  //校验成功
  if (result == true) {
    showToast('校验成功')
  } else {
    showToast('校验未通过')
    //校验失败,返回校验失败的数组集合
    const errsName = (result as FormValidateErrors[]).map(v => v.name)
    console.log('校验失败的name合集', errsName)
  }
}
//自定义 rice-input 的样式
const inputStyle = ref({
  height: '24px',
  padding: '0px',
  backgroundColor: 'transparent',
})
scss
.demo-form {
  background-color: var(--demo-block-color);
  padding: 0 16px;
}

.btn {
  flex: 1;
}

.flex {
  flex-direction: row;
  flex-wrap: wrap;
  background-color: var(--demo-block-color);
  padding: 16px;
}

.reset-text {
  background-color: var(--demo-block-color);
  text-align: right;
  font-size: 12px;
  color: var(--demo-text-color-2);
  padding-bottom: 12px;
  padding-right: 18px;
  /* #ifdef WEB */
  cursor: pointer;
  /* #endif */
}

.form-input {
  flex: 1;
  background-color: var(--demo-block-color-6);
  color: var(--demo-text-color);
  border-radius: 8px;
  height: 40px;
  font-size: 15px;
  padding: 0 12px;
}

.error-slot {
  flex-direction: row;

  &__text {
    color: var(--rice-form-error-color);
    font-size: 12px;
    margin-left: 4px;
  }
}

.slot-label {
  flex-direction: row;

  &__text {
    color: var(--demo-text-color);
    font-size: 15px;
    margin-right: 4px;
  }
}

不显示错误信息

设置 show-errorfalse 即可不显示错误信息

vue
<template>
  <rice-form :model="form5" :show-error="false" ref="formRef5" label-width="100px" class="demo-form">
    <rice-form-item name="username" label="用户名" required>
      <rice-input v-model="form5['username']" placeholder="请输入用户名" border="none" :custom-style="inputStyle" />
    </rice-form-item>
  </rice-form>
  <view class="flex">
    <rice-button type="primary" text="提 交" class="btn" shape="round" @click="submit5" />
  </view>
</template>
ts
const form5 = ref({
  username: ''
})
const formRef5 = ref<RiceFormComponentPublicInstance | null>(null)
const submit5 = async () => {
  const result = await formRef5.value!.validate()
  //校验成功
  if (result == true) {
    showToast('校验成功')
  } else {
    //校验失败,返回校验失败的数组集合
    const errs = (result as FormValidateErrors[]).map(v => `${v.label}:${v.message}`).join('/')
    showToast(errs)
  }
}
//自定义 rice-input 的样式
const inputStyle = ref({
  height: '24px',
  padding: '0px',
  backgroundColor: 'transparent',
})

表单状态

info 表单的 disabledreadonly 状态会影响以下组件:
rice-checkbox 复选框rice-input 输入框rice-radio 单选框rice-rate 评分rice-slider 滑块rice-stepper 步进器rice-switch 开关rice-textarea 多行文本框

API

Form Props

属性名类型说明默认值
modelUTSJSONObject/自定义type类型(只能为对象类型)表单数据对象-
rulesMap<string, FormRules[]>表单校验规则,注意为 Map 类型FormRules数据格式见下-
label-widthString|Number标签的宽度auto
label-positionString标签的位置,默认 left,可选 right topleft
label-styleUTSJSONObject自定义标签style,如文字大小和颜色-
show-requiredBoolean是否显示必填的符号,默认根据rules规则显示;只是页面显示效果,不会进行空值的校验-
required-positionString必填符号的位置,默认 left,可选 rightleft
show-errorBoolean校验失败时是否显示错误信息true
border-bottomBoolean是否显示表单域的下划线边框true
error-bottomBoolean校验未通过时下边框是否标红,border-bottomtrue 时生效false
scroll-to-errorBoolean是否自动滚动到第一个校验不通过的字段,APP端需在 scroll-viewlist-view 组件中使用才有效,当前仅APP端支持false
disabledBoolean是否禁用此表单中的所有组件,支持的组件见上false
readonlyBoolean是否只读此表单中的所有组件,支持的组件见上false
error-styleUTSJSONObject错误信息区域的自定style样式-
custom-styleUTSJSONObject自定style样式-

FormItem Props

属性名类型说明默认值
nameString表单域model对象的属性名-
labelString标签文字-
label-widthString|Number标签的宽度,会覆盖 Form 中的 label-widthauto
label-positionString标签的位置,默认 left,可选 right top,会覆盖 Form 中的 label-positionleft
label-styleUTSJSONObject自定义标签style,如文字大小和颜色,会和 Form 中的 label-style进行合并-
rulesFormRules[]表单项的校验规则,会与 Form 中同名(name 值一致)的校验规则自动合并,注意为 FormRules[] 类型FormRules数据格式见下-
requiredBoolean是否必填,为 true时会对表单项进行空值的校验false
show-requiredBoolean是否显示必填的符号,默认根据rules规则显示;只是页面显示效果,不会进行空值的校验-
required-positionString必填符号的位置,默认 left,可选 rightleft
show-errorBoolean校验失败时是否显示错误信息true
border-bottomBoolean是否显示表单域的下划线边框true
error-bottomBoolean校验未通过时下边框是否标红,border-bottomtrue 时生效false
suffix-iconString尾部 Icon 的name值-
suffix-icon-styleUTSJSONObject尾部 Icon 的style样式-
content-styleUTSJSONObject默认区域内的自定样式-
error-styleUTSJSONObject错误信息区域的自定style样式,会和 Form 中的 error-style进行合并-
custom-styleUTSJSONObject自定style样式-

Form 方法

通过 ref 可以获取到 Form 实例并且调用实例的方法

方法名说明参数返回值
validate验证所有表单项-Promise<boolean | FormValidateErrors[]> , 返回 true 时表示校验通过,校验不通过时会返回未通过的表单项合集,FormValidateErrors格式见下
validateFields验证指定的表单项要校验表单项的name值合集,
validateFields(['name','age'])
validate 方法的返回值
clearAllValidate清除表单全部的校验信息--
clearValidate清除表单指定字段的校验信息要清除表单项的name值合集,
clearValidate(['name','age'])
-
scrollToField滚动到指定的字段位置,当前仅 App 端支持要滚动到某个字段的name值,如 scrollToField('name')-

调用方法示例

ts
const formRef = ref<RiceFormComponentPublicInstance | null>(null)
//需确保formRef.value不为null的情况下才能使用 "!."
formRef1.value!.validate()

FormItem Event

事件名说明回调参数
clickformItem的点击事件-
clickContent内容区域的点击事件-
clickSuffix尾部icon区域的点击事件-

Form Slots 插槽

名称说明参数
default默认内容区域-

FormItem Slots 插槽

名称说明参数
label标签区域-
suffix尾部区域-
error错误信息区域(message : string)

FormRules 数据结构

rules 属性定义的校验规则属性如下:

键名说明类型
required是否为必选字段,当值为空值时(空字符串、空数组、空对象、undefined、null ),校验不通过Boolean
message校验未通过时的错误信息String
trigger本项规则的触发时机,默认 change,可选值为 blur allFormTrigger
min最小值/长度,当值为数字类型时,比较的是数字的大小;当值为字符串/数组时,比较的是字符串/数组的长度Number
max最大值/长度,比较方式同 minNumber
pattern通过正则表达式进行校验,正则无法匹配表示校验不通过RegExp
validator通过函数进行校验,返回true表示校验通过,返回false或字符串表示校验不通过;可以返回一个 Promise 来进行异步校验(value : any | null) => (boolean | string) | Promise<boolean | string>

FormValidateErrors 数据结构

表单校验不通过时返回的表单项合集属性如下:

键名说明类型
name表单域model对象的属性名String
rule当前未通过的ruleFormRules
message校验未通过时的错误信息String
label标签文字String|Null

类型定义

Form 组件导出如下类型:

ts
//标签的位置
type FormLabelPosition = 'left' | 'top' | 'right'
//必填符号的位置
type FormRequiredPosition = 'left' | 'right'
//规则的触发时机
type FormTrigger = 'change' | 'blur' | 'all'
//rule 规则类型
type FormRules = {
	required ?: boolean,
	message ?: string,
	trigger ?: FormTrigger,
	min ?: number,
	max ?: number,
	pattern ?: RegExp,
	validator ?: (value : any | null) => (boolean | string) | Promise<boolean | string>,
}
//校验不通过时的表单项合集
type FormValidateErrors = {
	name : string,
	rule : FormRules,
	message : string,
	label ?: string,
}
//Form 组件类型
const formRef = ref<RiceFormComponentPublicInstance | null>(null)

FormItem 组件导出如下类型:

ts
//FormItem 组件类型
const formItemRef = ref<RiceFormItemComponentPublicInstance | null>(null)