在表单中,每个 Form.Item
代表一个表单项
function BasicForm() {
const onSubmit = (event: BaseEventOrig<FormProps.onSubmitEventDetail>) => {
Toast.open(JSON.stringify(event.detail.value))
}
return (
<Form onSubmit={onSubmit}>
<Toast id="toast" />
<Cell.Group inset>
<Form.Item name="username" rules={[{ required: true, message: "请填写用户名" }]}>
<Form.Label>用户名</Form.Label>
<Form.Control>
<Input placeholder="用户名" />
</Form.Control>
</Form.Item>
<Form.Item name="password" rules={[{ required: true, message: "请填写密码" }]}>
<Form.Label>密码</Form.Label>
<Form.Control>
<Input password placeholder="密码" />
</Form.Control>
</Form.Item>
<Field
name="text"
label={{ align: "left", children: "文本" }}
rules={[{ required: true, message: "请填写文本" }]}
>
<Input placeholder="请输入文本" />
</Field>
</Cell.Group>
<View style={{ margin: "16px" }}>
<Button shape="round" block color="primary" formType="submit">
提交
</Button>
</View>
</Form>
)
}
使用Field
组件
function BasicForm() {
const onSubmit = (event: BaseEventOrig<FormProps.onSubmitEventDetail>) => {
Toast.open(JSON.stringify(event.detail.value))
}
return (
<Form onSubmit={onSubmit}>
<Toast id="toast" />
<Cell.Group inset>
<Field label="用户名" name="username" rules={[{ required: true, message: "请填写用户名" }]}>
<Input placeholder="用户名" />
</Field>
<Field label="密码" name="password" rules={[{ required: true, message: "请填写密码" }]}>
<Input password placeholder="密码" />
</Field>
</Cell.Group>
<View style={{ margin: "16px" }}>
<Button shape="round" block color="primary" formType="submit">
提交
</Button>
</View>
</Form>
)
}
通过 rules
定义表单校验规则,所有可用字段见下方表格。
function FormWithRules() {
const asyncValidator = (val: any) =>
new Promise<boolean>((resolve) => {
Toast.loading("验证中...")
setTimeout(() => {
Toast.close("toast")
resolve(/\d{6}/.test(val))
}, 1000)
})
function onValidate(errors: FormValidError[]) {
Toast.open({
style: {
textAlign: "left",
},
message: JSON.stringify(errors, undefined, 2),
})
}
return (
<Form defaultValues={{ validatorMessage: "abc" }} onValidate={onValidate}>
<Toast id="toast" />
<Cell.Group inset>
<Field
label="文本"
name="pattern"
rules={[{ pattern: /\d{6}/, message: "请输入正确内容" }]}
>
<Input placeholder="正则校验" />
</Field>
<Field
label="文本"
name="validator"
rules={[{ validator: (val) => /1\d{10}/.test(val), message: "请输入正确内容" }]}
>
<Input placeholder="函数校验" />
</Field>
<Field
label="文本"
name="validatorMessage"
rules={[{ validator: (val) => `${val ?? ""} 不合法,请重新输入` }]}
>
<Input placeholder="校验函数返回错误提示" />
</Field>
<Field
label="文本"
name="asyncValidator"
rules={[{ validator: asyncValidator, message: "请输入正确内容" }]}
>
<Input placeholder="异步函数校验" />
</Field>
</Cell.Group>
<View style={{ margin: "16px" }}>
<Button shape="round" block color="primary" formType="submit">
提交
</Button>
</View>
</Form>
)
}
设置 disabled
后,会为 Form
内部的 taroify
组件 Input
, Textarea
, Checkbox
, Switch
, Checkbox.Group
, Radio.Group
, Rate
, Slider
, Stepper
, Uploader
设置 disabled
form 设置 disabled 后,也可以单独为表单项和组件设置 disabled={false}, 优先级:表单 < 表单项 < 组件
在表单中使用 Checkbox 组件。
<Field label="复选框" name="checkbox">
<Checkbox shape="square" />
</Field>
<Field label="复选框组" name="checkboxGroup">
<Checkbox.Group direction="horizontal">
<Checkbox name="1" shape="square">
复选框 1
</Checkbox>
<Checkbox name="2" shape="square">
复选框 2
</Checkbox>
</Checkbox.Group>
</Field>
在表单中使用 Radio 组件。
<Field label="单选框" name="radio">
<Radio.Group direction="horizontal">
<Radio name="1">单选框 1</Radio>
<Radio name="2">单选框 2</Radio>
</Radio.Group>
</Field>
在表单中使用 Uploader 组件。
function UploaderField() {
const itemRef = useRef<FormItemInstance>()
function onUpload() {
chooseImage({
count: 1,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
}).then(({ tempFiles }) => {
itemRef.current?.setValue([
...(itemRef.current?.getValue() ? [...itemRef.current?.getValue()] : []),
{
url: tempFiles[0].path,
type: tempFiles[0].type,
name: tempFiles[0].originalFileObj?.name,
},
])
})
}
return (
<Field label="文件上传" ref={itemRef} name="uploader">
<Uploader multiple maxFiles={2} onUpload={onUpload} />
</Field>
)
}
在表单中使用 Picker 组件。
function PickerField() {
const itemRef = useRef<FormItemInstance>()
const [open, setOpen] = useState(false)
const columns = useMemo(
() => [
{ label: "杭州", value: "Hangzhou" },
{ label: "宁波", value: "Ningbo" },
{ label: "温州", value: "Wenzhou" },
{ label: "绍兴", value: "Shaoxing" },
{ label: "湖州", value: "Huzhou" },
],
[],
)
return (
<>
<Field label="选择器" ref={itemRef} name="picker" clickable isLink>
<Input readonly placeholder="点击选择城市" onClick={() => setOpen(true)} />
</Field>
<Popup open={open} rounded placement="bottom" onClose={setOpen}>
<Picker
title="选择城市"
columns={columns}
onCancel={() => setOpen(false)}
onConfirm={(newValue) => {
itemRef.current?.setValue(newValue)
setOpen(false)
}}
></Picker>
</Popup>
</>
)
}
在表单中使用 DatetimePicker 组件。
function DatetimePickerField() {
const itemRef = useRef<FormItemInstance>()
const [open, setOpen] = useState(false)
const formatDate = (date: any) => {
if (date) {
const hours = _.padStart(_.toString(date?.getHours()), 2, "0")
const minutes = _.padStart(_.toString(date?.getMinutes()), 2, "0")
return `${hours}:${minutes}`
}
}
return (
<>
<Field label="时间选择" ref={itemRef} name="datetimePicker" clickable isLink>
{(controller) => (
<Input
value={formatDate(controller.value)}
disabled={controller.disabled}
readonly
placeholder="点击选择时间"
onClick={() => setOpen(true)}
/>
)}
</Field>
<Popup open={open} rounded placement="bottom" onClose={setOpen}>
<DatetimePicker
type="hour-minute"
onCancel={() => setOpen(false)}
onConfirm={(newValue) => {
itemRef.current?.setValue(newValue)
setOpen(false)
}}
></DatetimePicker>
</Popup>
</>
)
}
在表单中使用 Calendar 组件。
function CalendarField() {
const itemRef = useRef<FormItemInstance>()
const [open, setOpen] = useState(false)
const formatDate = (date: any) => {
if (date) {
const months = _.padStart(_.toString(date?.getMonth() + 1), 2, "0")
const days = _.padStart(_.toString(date?.getDate()), 2, "0")
return `${months}-${days}`
}
}
return (
<>
<Field label="日历" ref={itemRef} name="calendar" clickable isLink>
{(controller) => (
<Input
value={formatDate(controller.value)}
disabled={controller.disabled}
readonly
placeholder="点击选择日期"
onClick={() => setOpen(true)}
/>
)}
</Field>
<Calendar
type="single"
poppable
showPopup={open}
onCancel={() => setOpen(false)}
onConfirm={(newValue) => {
itemRef.current?.setValue(newValue)
setOpen(false)
}}
></Calendar>
</>
)
}
通过 Form.List 动态增减表单项 v0.1.1-alpha.3
function DynamicForm() {
const ref = useRef<FormInstance>(null)
const onManual = () => {
ref.current?.setValues({
contacts: [
{ name: "小红", phone: "10000" },
{ name: "小绿", phone: "10086" },
],
})
}
return (
<Form
ref={ref}
onSubmit={(e) => {
Toast.open(JSON.stringify(e.detail.value, undefined, 2))
}}
>
<Form.List name="contacts" defaultValue={[{ name: "小明", phone: "10086" }]}>
{(fields, { add, remove }) => (
<Cell.Group inset>
{fields.map((field, idx) => (
<Fragment key={field.key}>
<Field label="姓名" name={`${field.name}.name`} key={`${field.key}.name`}>
{({ value, onChange }) => (
<>
<Input
placeholder="请输入姓名"
value={value}
onChange={(e) => {
onChange?.(e.detail.value)
}}
/>
<View
style={{ flexShrink: 0 }}
onClick={() => {
remove(idx)
}}
>
删除
</View>
</>
)}
</Field>
<Field
label="电话"
name={`${field.name}.phone`}
key={`${field.key}.phone`}
rules={[{ required: true, message: "必填" }]}
>
<Input placeholder="请输入电话" />
</Field>
</Fragment>
))}
<Button variant="text" color="primary" onClick={() => add({})}>
添加联系人
</Button>
</Cell.Group>
)}
</Form.List>
<View style={{ margin: "16px" }}>
<Button shape="round" block color="primary" formType="submit">
提交
</Button>
<Button style={{ marginTop: "16px" }} shape="round" block color="info" onClick={onManual}>
手动
</Button>
<Button style={{ marginTop: "16px" }} shape="round" block color="warning" formType="reset">
重置
</Button>
</View>
</Form>
)
}
通过 dependencies 自动触发校验
function DependenciesDemo() {
const formRef = useRef<FormInstance>()
const onSubmit = (event: BaseEventOrig<FormProps.onSubmitEventDetail>) => {
Toast.open(JSON.stringify(event.detail.value))
}
return (
<Form ref={formRef} onSubmit={onSubmit} validateTrigger="onChange">
<Toast id="toast" />
<Cell.Group inset>
<Form.Item name="username" rules={[{ required: true, message: "请输入用户名" }]}>
<Form.Label>用户名</Form.Label>
<Form.Control>
<Input placeholder="用户名" />
</Form.Control>
</Form.Item>
<Form.Item name="password" rules={[{ required: true, message: "请输入密码" }]}>
<Form.Label>密码</Form.Label>
<Form.Control>
<Input placeholder="密码" />
</Form.Control>
</Form.Item>
<Form.Item
name="confirmPassword"
dependencies={["password"]}
rules={[
{ required: true, message: "请再次输入密码" },
{
validator: (val) => {
return formRef.current?.getValues<any>()?.password === val ? true : "密码不一致"
},
},
]}
>
<Form.Label>确认密码</Form.Label>
<Form.Control>
<Input placeholder="确认密码" />
</Form.Control>
</Form.Item>
</Cell.Group>
<View style={{ margin: "16px" }}>
<Button shape="round" block color="primary" formType="submit">
提交
</Button>
</View>
</Form>
)
}
通过 shouldUpdate 和 noStyle 触发重新渲染, Form.Item 里包裹的子组件必须由函数返回,否则 shouldUpdate 不会起作用, Field 暂不支持
function ShouldUpdateDemo() {
const formRef = useRef<FormInstance>()
return (
<Form
ref={formRef}
onSubmit={(e) => {
Toast.open(JSON.stringify(e.detail.value, undefined, 2))
}}
>
<Toast id="toast" />
<Cell.Group inset>
<Form.Item name="type">
<Form.Label>复选框</Form.Label>
<Form.Control>
<Checkbox shape="square" />
</Form.Control>
</Form.Item>
<Form.Item name="radio">
<Form.Label>单选框</Form.Label>
<Form.Control>
<Radio.Group direction="horizontal">
<Radio name="1">单选框 1</Radio>
<Radio name="2">单选框 2</Radio>
</Radio.Group>
</Form.Control>
</Form.Item>
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.type !== cur.type}>
{() => {
const type = formRef.current?.getValues<any>()?.type
if (type) {
return (
<Form.Item name="a1">
<Form.Label>复选框选中</Form.Label>
<Form.Control>
<Input />
</Form.Control>
</Form.Item>
)
} else {
return (
<>
<Form.Item name="a2">
<Form.Label>复选框未选中</Form.Label>
<Form.Control>
<Input />
</Form.Control>
</Form.Item>
<Form.Item name="a3">
<Form.Label>复选框未选中</Form.Label>
<Form.Control>
<Input />
</Form.Control>
</Form.Item>
</>
)
}
}}
</Form.Item>
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.radio !== cur.radio}>
{() => (
<Field name="cc" label={`单选框${formRef.current?.getValues<any>()?.radio}`}>
<Input placeholder={`结果${JSON.stringify(formRef.current?.getValues<any>())}`} />
</Field>
)}
</Form.Item>
</Cell.Group>
<View style={{ margin: "16px" }}>
<Button shape="round" block color="primary" formType="submit">
提交
</Button>
</View>
</Form>
)
}
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
defaultValues | 表单默认值 | object | |
labelAlign | 表单项 label 对齐方式,可选值为 center right | string | left |
controlAlign | 表单项 control 对齐方式,可选值为 center right | string | left |
validateTrigger | 表单校验触发时机,可选值为 onChange 、onSubmit ,详见下表 | string | onBlur |
colon | 是否在 label 后面添加冒号 | boolean | false |
disabled v0.3.1-alpha.0 | 是否禁用表单 | boolean | false |
事件名 | 说明 | 回调参数 |
---|---|---|
onSubmit | 提交表单且验证通过后触发 | event: BaseEventOrig<FormProps.onSubmitEventDetail> |
onReset | 重置表单后触发 | event: BaseEventOrig |
onValidate | 提交表单且验证不通过后触发 | errors: { name: string, errors: string[] }[] |
onValuesChange | 字段值更新后触发 | changedValues: object, allValues: object |
通过 ref 可以获取到 Form 实例并调用实例方法。
方法名 | 说明 | 参数 | 返回值 |
---|---|---|---|
setValues | 设置表单值(浅合并) | object | - |
getValues | 获得表单值,支持传入 name 来获得单个或部分表单项 | name?: string | string[] | object |
setErrors | 设置表单验证错误信息(浅合并) | FormValidError[] | void |
getErrors | 获得表单验证错误信息,支持传入 name 来获得单个或部分表单项 | name?: string | string[] | FormValidError[] |
validate | 验证表单,支持传入 name 来验证单个或部分表单项 | name?: string | string[] | Promise |
submit v0.3.1-alpha.0 | 提交表单,与点击提交按钮的效果等价 | - | - |
reset | 重置表单 | - | void |
通过 validateTrigger
属性可以自定义表单校验的触发时机。
值 | 描述 |
---|---|
onSubmit | 仅在提交表单时触发校验 |
onBlur | 在提交表单和输入框失焦时触发校验 |
onChange | 在提交表单和输入框内容变化时触发校验 |
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
name | 表单项名称,提交表单的标识符 | string | - |
defaultValue | 表单项默认值 | any | - |
required | 是否显示表单必填星号 | boolean | false |
rules | 表单校验规则 | FormRule[] | - |
dependencies v0.1.6-alpha.0 | 当依赖的字段值改变时,触发自身的校验 | string[] | - |
shouldUpdate v0.1.6-alpha.0 | 当值为 true 时,触发当前区域重新渲染 | boolean|(prevValues, curValues) => boolean | - |
noStyle v0.1.6-alpha.0 | 直接渲染 children | boolean | - |
属性继承自 Cell 组件,更多属性参见:Cell 组件
使用 Form.Item 的 rules
属性可以定义校验规则,可选属性如下:
键名 | 说明 | 类型 |
---|---|---|
required | 是否为必选字段,当值为空字符串、空数组、undefined 、null 时,校验不通过 | boolean |
message | 错误提示文案 | string | (value, rule) => string |
validator | 通过函数进行校验 | (value, rule) => boolean | string | Promise |
validateFirst v0.5.0-alpha.0 | 当某一规则校验不通过时,是否停止剩下的规则的校验。 | boolean |
pattern | 通过正则表达式进行校验 | RegExp |
trigger | 本项规则的触发时机,可选值为 onChange 、onBlur | string |
formatter | 格式化函数,将表单项的值转换后进行校 验 | (value, rule) => any |
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
align | 对齐方式,可选值为 center right | string | left |
status | 反馈状态,可选值为 valid warning invalid | string | - |
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
align | 对齐方式,可选值为 center right | string | left |
children | 内容 | ReactNode|((controller: FormController) => ReactNode) | — |
interface FormController<V> {
value?: V // 当前表单项值
validateStatus?: FormValidateStatus // 当前表单项验证状态
disabled?: boolean // 当前表单项是否禁用
onChange?(value: V): void // 改变当前表单项值
onBlur?(value: V): void // 触发onBlur当前表单项校验
}
Tips: 使用 onBlur 触发表单验证,自定义表单项时,要手动调用 onBlur,才能触发校验
| 参数 | 说明 | 类型 | | ------------ | ---------------------------- | ------------------------------------------------------------------------------------ | --- | | children | 渲染函数 | (fields: { key: string, name: string }[], operation: { add, remove }) => ReactNode | _ | | name | 表单项名称,提交表单的标识符 | string | | defaultValue | 表单项默认值 | any |
通过@taroify/core/form
导入组件类型:
import { FormRule, FormItemInstance, FormListInstance, FormInstance } from "@taroify/core/form"
组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 ConfigProvider 组件。
名称 | 默认值 | 描述 |
---|---|---|
form-label-width | 6.2em | - |
form-label-color | var(—gray-7) | - |
form-label-margin-right | var(—padding-sm) | - |
form-label-disabled-color | var(—gray-5) | - |
form-item-icon-size | 16px * $hd | - |
form-item-right-icon-color | var(—gray-6) | - |
form-item-right-icon-padding | 0 var(—padding-xs) | - |
form-item-right-icon-margin-right | -8px * $hd | - |
form-item-right-button-margin-left | var(—padding-xs) | - |
form-control-color | var(—text-color) | - |
form-control-min-height | var(—cell-line-height) | - |
form-feedback-font-size | var(—font-size-sm) | - |
form-feedback-valid-color | var(—success-color) | - |
form-feedback-warning-color | var(—warning-color) | - |
form-feedback-invalid-color | var(—danger-color) | - |