由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据。
import { Form, FormItem } from 'uiw';
// or
import { Form, FormItem } from '@uiw/react-form';
import React, { useState, useRef } from "react";
import { Form, Input, Row, Col, Slider, Button, Notify } from 'uiw';
export default function Demo() {
const form = useRef()
const onSubmit = () => {
form.current.onSubmit()
}
const resetForm = () => {
form.current.resetForm()
}
const getFieldValues = () => {
console.log('getFieldValues', form.current.getFieldValues())
}
const setFieldValue=()=>{
form.current.setFieldValue('name','UIW')
}
return (
<div>
<Form
ref={form}
onChange={({ initial, current }) => {
console.log('onChange', initial, current);
}}
onSubmit={({ initial, current }) => {
if (current.name === initial.name) {
Notify.error({
title: '提交失败!',
description: `表单提交内容为空!`,
});
} else {
Notify.success({
title: '提交成功!',
description: `姓名为:${current.name},提交完成,将自动填充初始化值!`,
});
}
}}
fields={{
name: {
label: '姓名',
children: <Input placeholder="请输入姓名" />
},
}}
>
{({ fields, state, canSubmit }) => {
return (
<div>
<Row>
<Col style={{ maxWidth: 300 }}>{fields.name}</Col>
</Row>
<Row>
<Col>
<Button disabled={!canSubmit()} type="primary" htmlType="submit">提交</Button>
</Col>
</Row>
<Row>
<Col>
{JSON.stringify(state.current)}
</Col>
</Row>
</div>
)
}}
</Form>
<Button type="primary" onClick={onSubmit} >submit</Button>
<Button type="primary" onClick={resetForm}>resetForm</Button>
<Button type="primary" onClick={getFieldValues}>getValues</Button>
<Button type="primary" onClick={setFieldValue}>setFieldValue</Button>
</div>
)
}
一般校验可不需引入外部包解决,如果遇到大型工程表单比较多的地方推荐使用 jquense/yup
import React from 'react';
import { Form, Input, Notify, Checkbox, Switch, RadioGroup, Radio, Textarea, Row, Col, Button, Select, SearchSelect } from 'uiw';
export default function Demo() {
return(
<Form
onSubmit={({initial, current}) => {
const errorObj = {};
if (current.userName.startsWith('u')) {
errorObj.userName = `姓名 ${current.userName} 不能以 ‘u’ 开头`;
}
if (!current.checkboxOne) {
errorObj.checkboxOne = '一个多选条件 为必填';
}
if (!current.terms) {
errorObj.terms = '必须统一服务条款';
}
if(Object.keys(errorObj).length > 0) {
const err = new Error();
err.filed = errorObj;
throw err;
}
Notify.success({
title: '提交成功!',
description: `姓名为:${current.userName},提交完成,将自动填充初始化值!`,
});
}}
onSubmitError={(error) => {
if (error.filed) {
return { ...error.filed };
}
return null;
}}
fields={{
userName: {
initialValue: 'uiw',
label: '姓名',
children: <Input type="text" />,
help: '以“u”开头的名字将在此处显示错误信息'
},
age: {
initialValue: '9',
label: '年龄',
children: <Input type="number" />
},
select: {
children: (
<Select>
<Select.Option value="w">Choose an item...</Select.Option>
<Select.Option value="1">One</Select.Option>
<Select.Option value="2">Two</Select.Option>
<Select.Option value="3">Three</Select.Option>
<Select.Option value="4">Four</Select.Option>
</Select>
)
},
searchSelect: {
initialValue:[{label: 'a7', value: 7},{label: 'a8', value: 8}],
children: (
<SearchSelect
allowClear
labelInValue={true}
showSearch={true}
mode="multiple"
disabled={false}
placeholder="请选择选项"
option={[
{ label: 'a1', value: 1 },
{ label: 'a2', value: 2 },
{ label: 'a3', value: 3 },
{ label: 'a4', value: 4 },
{ label: 'a5', value: 5 },
{ label: 'a6', value: 6 },
{ label: 'a7', value: 7 },
{ label: 'a8', value: 8 },
]}
/>
)
},
checkbox: {
initialValue: ['四川菜'],
label: '选择你想吃的菜',
children: (
<Checkbox.Group>
<div>菜系</div>
<Checkbox value="四川菜">四川菜</Checkbox>
<Checkbox value="湖北菜">湖北菜</Checkbox>
<Checkbox value="西北菜">西北菜</Checkbox>
<Checkbox value="新疆菜">新疆菜</Checkbox>
<Checkbox value="东北菜">东北菜</Checkbox>
<div style={{ marginTop: 10 }}>家常菜</div>
<Checkbox value="红烧武昌鱼">红烧武昌鱼</Checkbox>
<Checkbox value="麻婆豆腐">麻婆豆腐</Checkbox>
<Checkbox value="北京烤鸭">北京烤鸭</Checkbox>
</Checkbox.Group>
)
},
checkboxOne: {
inline: true,
label: '一个多选条件',
children: <Checkbox value="1">四川菜</Checkbox>
},
switch: {
inline: true,
initialValue: true,
label: '开启',
children: <Switch size="small" />
},
radioGroup: {
inline: true,
initialValue: '男',
label: '单选',
children: (
<RadioGroup name="other">
<Radio value="男">男</Radio>
<Radio value="女">女</Radio>
<Radio value="人妖" disabled>人妖</Radio>
<Radio value="未知">未知</Radio>
</RadioGroup>
)
},
textarea: {
initialValue: '',
label: '多行文本输入框',
children: <Textarea placeholder="请输入内容" />
},
terms: {
validator: (currentValue) => {
return !currentValue ? '必须统一服务条款' : null;
},
style: { marginBottom: 0 },
children: <Checkbox value="1">已阅读并同意<a href="#">服务条款</a></Checkbox>
}
}}
>
{({ fields, state, canSubmit, resetForm }) => {
console.log('fields:-->', state);
return (
<div style={{ maxWidth: 500 }}>
<Row gutter={10}>
<Col>{fields.userName}</Col>
<Col>{fields.age}</Col>
</Row>
<Row gutter={10}>
<Col>{fields.select}</Col>
<Col>{fields.searchSelect}</Col>
</Row>
<Row gutter={10}>
<Col>{fields.checkbox}</Col>
<Col>{fields.checkboxOne}</Col>
</Row>
<Row gutter={10}>
<Col>{fields.radioGroup}</Col>
</Row>
<Row gutter={10}>
<Col>{fields.switch}</Col>
</Row>
<Row gutter={10}>
<Col>{fields.textarea}</Col>
</Row>
<Row gutter={10}>
<Col style={{ padding: '5px 0 10px 0' }}>
{fields.terms}
</Col>
</Row>
<Row gutter={10}>
<Col fixed>
<Button disabled={!canSubmit()} type="primary" htmlType="submit">提交</Button>
<Button type="light" onClick={resetForm}>重置表单</Button>
</Col>
</Row>
<Row>
<Col>
<pre style={{ padding: '10px 0 0 10px' }}>
{JSON.stringify(state.current, null, 2)}
</pre>
</Col>
</Row>
</div>
)
}}
</Form>
)
}
import React from 'react';
import { Form, Input, Row, Col, Notify, Button } from 'uiw';
export default function Demo() {
return (
<div>
<Form
onSubmit={({initial, current}) => {
const errorObj = {};
if (!current.username) {
errorObj.username = '用户名不能为空!';
}
if (!current.password) {
errorObj.password = '密码不能为空!';
}
if(Object.keys(errorObj).length > 0) {
const err = new Error();
err.filed = errorObj;
Notify.error({ title: '提交失败!', description: '请确认提交表单是否正确!' });
throw err;
}
console.log('-->>', initial, current);
Notify.success({ title: '提交成功!', description: '恭喜你登录成功!' });
}}
onSubmitError={(error) => {
if (error.filed) {
return { ...error.filed };
}
return null;
}}
fields={{
username: {
labelClassName: 'fieldLabel',
labelFor: 'username-inline',
children: <Input preIcon="user" id="username-inline" />
},
password: {
labelClassName: 'fieldLabel',
labelFor: 'password-inline',
children: <Input preIcon="lock" id="password-inline" type="password" />
},
}}
>
{({ fields, state, canSubmit, resetForm }) => {
console.log('fields:', state);
return (
<div>
<Row gutter={10}>
<Col fixed>{fields.username}</Col>
<Col fixed>{fields.password}</Col>
</Row>
<Row gutter={10}>
<Col>
<Button disabled={!canSubmit()} type="primary" htmlType="submit">提交</Button>
<Button type="danger" onClick={resetForm}>重置表单</Button>
</Col>
</Row>
</div>
)
}}
</Form>
</div>
);
}
import React from 'react';
import { Form, Input, Row, Col, Checkbox, Notify, Button } from 'uiw';
export default function Demo() {
return (
<div>
<Form
onSubmit={({initial, current}) => {
console.log('-->>', initial, current);
}}
fields={{
username: {
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
labelFor: 'username',
children: <Input preIcon="user" id="username" />
},
password: {
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
labelFor: 'password',
children: <Input preIcon="lock" id="password" type="password" />
},
terms: {
validator: (currentValue) => !currentValue ? '必须统一服务条款' : null,
children: <Checkbox value="1">已阅读并同意</Checkbox>
}
}}
>
{({ fields, state, canSubmit }) => {
console.log('fields:', state);
return (
<div>
<Row>
<Col fixed>{fields.username}</Col>
</Row>
<Row>
<Col fixed>{fields.password}</Col>
</Row>
<Row>
<Col fixed align="middle">{fields.terms}</Col>
<Col fixed style={{ marginTop: -4 }}><a href="#">服务条款</a></Col>
</Row>
<Row>
<Col fixed>
<Button disabled={!canSubmit()} type="primary" htmlType="submit">提交</Button>
</Col>
</Row>
</div>
)
}}
</Form>
</div>
)
}
import React from 'react';
import { Form, Input, Select, Row, Col, Button } from 'uiw';
export default function Demo() {
return (
<div>
<Form
onSubmit={({initial, current}) => {
console.log('-->>', initial, current);
}}
fields={{
firstName: {
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
inline: true,
label: '姓氏',
children: <Input />
},
lastName: {
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
initialValue: '先生',
inline: true,
label: '名字',
children: <Input />
},
email: {
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
validator: (currentValue) => {
return currentValue && currentValue.length < 2 ? 'Password must be 8+ characters' : null;
},
inline: true,
label: 'Email',
children: <Input />
},
select: {
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
inline: true,
label: '选择器',
children: (
<Select>
<Select.Option>Choose an item...</Select.Option>
<Select.Option value="1">One</Select.Option>
<Select.Option value="2">Two</Select.Option>
<Select.Option value="3">Three</Select.Option>
<Select.Option value="4">Four</Select.Option>
</Select>
),
},
}}
>
{({ fields, state, canSubmit }) => {
console.log('fields:', state);
return (
<div>
<Row gutter={10} style={{ marginBottom: 10 }}>
<Col>{fields.firstName}</Col>
<Col>{fields.lastName}</Col>
</Row>
<Row gutter={10}>
<Col>{fields.email}</Col>
<Col>{fields.select}</Col>
</Row>
<Row gutter={10}>
<Col />
<Col fixed align="bottom"><Button disabled={!canSubmit()} type="primary" htmlType="submit">提交</Button></Col>
</Row>
</div>
)
}}
</Form>
</div>
)
}
下面实例是在 <Form />
表单组件中,应用自定义 <CustomSelect />
控件组件。
⚠️ 注意,自定义控件需要两个必要的props
参数,value
和onChange
value
用于值传递,onChange(value)
用于值变更需要执行的回调函数,回调函数第一个参数必须是value
。
import React from 'react';
import { Form, Row, Col, Dropdown, Menu, Icon, Button, Notify } from 'uiw';
// 自定义组件
function CustomSelect(props) {
const { option = [], onChange } = props;
const [value, setValue] = React.useState(props.value);
const [isOpen, setIsOpen] = React.useState(false);
React.useEffect(() => {
if (value !== props.value) {
setValue(props.value);
}
}, [props.value]);
const label = option.find(item => value === item.value);
return (
<Dropdown
trigger="click"
onVisibleChange={(open) => setIsOpen(open)}
isOpen={isOpen}
menu={
<Menu bordered style={{ minWidth: 120 }}>
{option.map((item, idx) => (
<Menu.Item active={value === item.value} key={idx} text={item.label}
onClick={() => {
setValue(item.value);
setIsOpen(false)
onChange && onChange(item.value);
}}
/>
))}
</Menu>
}
>
<Button
style={{
boxShadow: 'inset 0 0 0 1px rgba(16, 22, 26, 0.2), inset 0 -1px 0 rgba(16, 22, 26, 0.1)'
}}
type="link"
>
{label.label}<Icon type={isOpen ? 'up' : 'down'} />
</Button>
</Dropdown>
);
}
// 自定义组件应用实例
export default function Demo() {
return (
<div>
<Form
onSubmitError={(error) => {
if (error.filed) {
return { ...error.filed };
}
return null;
}}
onSubmit={({initial, current}) => {
console.log('~~~', current);
const errorObj = {};
if (!current.select) {
errorObj.select = '内容为空,请输入内容';
}
if(Object.keys(errorObj).length > 0) {
const err = new Error();
err.filed = errorObj;
Notify.error({ title: '提交失败!', description: '请确认提交表单是否正确!' });
throw err;
}
Notify.success({
title: '提交成功!',
description: `表单提交成功,内容为:${current.select},将自动填充初始化值!`,
});
}}
fields={{
select: {
initialValue: 0,
children: (
<CustomSelect option={[
{ label: '请选择', value: 0 },
{ label: '经济舱', value: 1 },
{ label: '豪华经济舱', value: 2 },
{ label: '商务舱', value: 3 },
{ label: '头等舱', value: 4 },
]} />
)
},
}}
>
{({ fields, state, canSubmit }) => {
return (
<div>
<Row>
<Col style={{ maxWidth: 300 }}>{fields.select}</Col>
</Row>
<Row>
<Col fixed>
<Button disabled={!canSubmit()} type="primary" htmlType="submit">提交</Button>
</Col>
</Row>
</div>
)
}}
</Form>
</div>
)
}
对组件 FormItem
竖排展示示例。
⚠️ 注意:FormItem
组件只在Form
组件中使用,在@v4.10.4+
以上版本可以当普通form
使用。
import React from 'react';
import { Form, FormItem, Button, Input } from 'uiw';
export default function Demo() {
const [formData, setFormData] = React.useState({});
const handleSubmit = (_, e) => {
e && e.preventDefault();
const fData = new FormData(e.target);
const data = {};
fData.forEach((value, key) => { data[key] = value; });
setFormData(data);
}
return (
<Form onSubmit={handleSubmit} onReset={() => setFormData({})}>
<FormItem
label="可选字段"
labelFor="item-basic-input"
help={<span>在上面的字段中输入一个值</span>}
>
<Input id="item-basic-input" name="basic" type="text"/>
</FormItem>
<FormItem
label="用户名"
labelFor="item-username-input"
help={(!formData.username || formData.username.length < 8) ? "用户名长度至少为8个字符串。" : "用户名正确 √ "}
hasError={(!formData.username || formData.username.length < 8)}
>
<Input id="item-username-input" name="username" type="text"/>
</FormItem>
<FormItem>
<Button type="success" htmlType="submit"> Submit </Button>
<Button type="light" htmlType="reset"> Reset </Button>
</FormItem>
<pre>
{JSON.stringify(formData, null, 2)}
</pre>
</Form>
);
}
对组件 FormItem
横排展示示例。
⚠️ 注意:FormItem
组件只在Form
组件中使用,在@v4.10.4+
以上版本可以当普通form
使用。
import React from 'react';
import { Form, FormItem, Input } from 'uiw';
export default function Demo() {
return (
<Form>
<FormItem
inline={true}
label="可选字段"
labelFor="basic-input-inline"
help={<span>在上面的字段中输入一个值</span>}
onChange={() => {
console.log('TEST::');
}}
>
<Input id="basic-input-inline" name="basic" type="text"/>
</FormItem>
<FormItem
inline={true}
label="用户名"
labelFor="username-input-inline"
labelClassName="username"
help="用户名长度至少为8个字符串。"
hasError={true}
>
<Input id="username-input-inline" name="username" type="text"/>
</FormItem>
</Form>
)
}
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
fields | 设置字段 | object | - |
children | 回调 {fields , state , canSubmit , resetForm } |
function | - |
onSubmit | 提交表单时调用 | (state: FormSubmitProps, event: React.FormEvent) => any |
- |
afterSubmit @3.0.0+ |
提交回调 {initial , current } |
function({ initial, current }) | - |
onChange | 表单发生改变回调函数 {initial , current } |
function({ initial, current }) | - |
onSubmitError | 调用 onSubmit 抛出的任何错误。从字段名称返回对象映射。 |
function | - |
resetOnSubmit | 在 onSubmit 成功后将表单重置为其初始状态。 |
bool | true |
ref | 返回form各种内部函数,可用于主动触发事件 | Ref | - |
{
firstName: {
initialValue: '王',
inline: true,
label: '姓',
labelClassName: 'fieldLabel',
labelStyle: { width: 60 },
// 验证,通过 `canSubmit()` 方法获得,提交按钮是否被禁用
validator: (currentValue) => {},
help: '帮助提示信息!',
children: <Input type="number" />
},
}
const form = useRef()
render(<Form ref={form}/>)
form.current.onSubmit() // 提交表单
form.current.resetForm() // 重置form
const fieldValues = form.current.getFieldValues() // 获取所有 field的 value对象
const error = form.current.getError() // 获取所有提交时验证错误
form.current.setFields({ /** [fieldName]: value **/ }) // 设置表单的值,覆盖 form所有 field的值
form.current.setFieldValue(fieldName, value) // 对单个 field设置 value,如果 value为数组请自行深度拷贝后传值,以免破坏原数组
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
label | 表单标题展示 | string | - |
required | 表单是否必填标识 | boolean | - |
labelClassName | 表单标题样式名称 | string | - |
labelStyle | 表单标题样式 | object | - |
labelFor | 列的宽度相对于同一网格中其他列的比率 | number | - |
help | 提示信息 | ReactNode | - |
hasError | 如果为true,则应用错误CSS。转动边框并帮助文字变红。 | number | - |