基于ice/form
实现的动态表单组件。
$ npm i ice-dynamic-form --save
下面例子演示了如何创建一个简单的 form:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h2>个人资料</h2>
<FormDynamic
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
},{
name: 'age',
type: 'Input',
label: '年龄:',
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
Form
的基本用法
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h2>个人资料</h2>
<FormDynamic
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
},{
name: 'age',
type: 'Input',
label: '年龄:',
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
Form
子组件使用 function
渲染时,可以调用 FormCore
中的 API
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h2>个人资料</h2>
<FormDynamic
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
},{
name: 'age',
type: 'Input',
label: '年龄:',
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit',
style: {
marginRight: '20px'
}
}
},{
name: 'reset',
type: 'Button',
text: 'Reset',
props: {
onClick: (formCore) => formCore.reset()
}
}]}
>
</FormDynamic>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
校验规则可以写在 Form
属性上或者 Field
属性上
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h2>个人资料</h2>
<FormDynamic
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
},{
name: 'age',
type: 'Input',
label: '年龄:',
rules: [{
message: '年龄必填且大于18岁',
required: true,
validator: (rule, value) => value > 18
}]
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit',
style: {
marginRight: '20px'
}
}
}]}
>
</FormDynamic>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
异步校验,校验结果的 message
直接 callback
即可
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h2>个人资料</h2>
<FormDynamic
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
rules: {
async asyncValidator(rule, value, callback) {
if (!value) {
callback('名称必填');
} else {
await sleep(500);
if (~['john', 'paul', 'george', 'ringo'].indexOf(value)) {
callback('名称已存在');
} else {
callback(undefined)
}
}
}
},
props: {
autoComplete: 'off'
}
},{
name: 'age',
type: 'Input',
label: '年龄:',
rules: [{
message: '年龄必填且大于18岁',
required: true,
validator: (rule, value) => value > 18
}]
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
基础联动
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Form, Field } from '@ice/form';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input, Radio } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h2>个人资料</h2>
<FormDynamic
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}],
age: [{
required: true,
message: '大于18岁',
validator: (rule, value) => value > 18
}]
}}
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button,
Radio,
RadioGroup: Radio.Group
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
// 数组内为“且”还是“或”?
// linkages数组内的条件为 或 的逻辑
effects:[{
// conditions数组内的为 且 逻辑
conditions: [{
symbol: "===",
value: "Khaleesi"
}],
// action 为数组,条件满足是并发
// show/hide/setValue
actions: [{
type: "setValue",
target: "age",
value: 28
}]
}]
},{
name: 'gender',
type: 'RadioGroup',
label: '性别:',
effects: [{
conditions: [{
symbol: "===",
value: "female"
}],
actions: [{
type: "hide",
target: "age",
}]
},{
conditions: [{
symbol: "!==",
value: "female"
}],
actions: [{
type: "show",
target: "age",
}]
}],
props: {
dataSource: [{
value: 'male',
label: '男'
},{
value: 'female',
label: '女',
},{
value: 'x',
label: 'X'
}]
}
},{
name: 'age',
type: 'Input',
label: '年龄:',
effects:[{
conditions: [{
symbol: ">=",
value: "18",
type: "number"
}],
actions: [{
type: "show",
target: "idCard"
}]
},{
conditions: [{
symbol: "<",
value: "18",
type: "number"
}],
actions: [{
type: "hide",
target: "idCard"
}]
}]
},{
name: 'idCard',
label: '身份证:',
type: 'Input',
visible: false,
},{
name: 'intro',
type: 'TextArea',
label: '简介:'
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Field } from '@ice/form';
import { Button, Input } from '@alifd/next';
const Address = ({ name, label }) => (
<React.Fragment>
<div>
<Field
name={`${name}.street`}
component={Input}
label={`${label} Street:`}
placeholder={`${label} Street`}
/>
</div>
<div>
<Field
name={`${name}.city`}
label={`${label} City:`}
component={Input}
placeholder={`${label} City`}
/>
</div>
<div>
<Field
name={`${name}.postalCode`}
label={`${label} Postal Code:`}
component={Input}
placeholder={`${label} Postal Code`}
/>
</div>
</React.Fragment>
)
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
return (
<div>
<h1>可复用的 Field Group</h1>
<FormDynamic
components={{
Address,
Button
}}
config={[{
name: 'billing',
type: 'Address',
label: 'Billing',
props: {
name: 'billing',
label: 'Billing'
}
},{
name: 'shipping',
type: 'Address',
label: 'shipping',
props: {
name: 'shipping',
label: 'shipping'
}
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
onSubmit={this.onSubmit}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
异步加载数据进行首屏渲染
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const load = async () => {
await sleep(2000);
return {
username: 'erikras',
age: 20,
intro: '我是 erikras'
};
}
class App extends Component {
state = { data: {} }
async componentDidMount() {
this.setState({ loading: true });
const data = await load();
this.setState({ loading: false, data });
}
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
const Age = (<span style={{color: 'green'}}>年龄:</span>);
return (
<div>
<h2>加载表单数据并且初始化(label支持自定义jsx)</h2>
<FormDynamic
value={this.state.data}
onSubmit={this.onSubmit}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
},{
name: 'age',
type: 'Input',
label: '年龄:',
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
表单布局
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
class App extends Component {
async onSubmit(values) {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
render() {
const layout = {
labelCol: 1,
wrapperCol: 3,
labelTextAlign: 'right'
}
return (
<div>
<FormDynamic
layout={layout}
onSubmit={this.onSubmit}
rules={{
username: [{
required: true,
min: 5,
message: '姓名至少5个字符'
}]
}}
components={{
Input,
TextArea: Input.TextArea,
Button
}}
config={[{
name: 'username',
type: 'Input',
label: '姓名:',
},{
name: 'age',
type: 'Input',
label: '年龄:',
},{
name: 'intro',
type: 'TextArea',
label: '简介:',
tips: "介绍自己的经历介绍自己的经历介绍自己的经历介绍自己的经历"
}]}
buttons={[{
name: 'submit',
type: 'Button',
text: 'Submit',
props: {
htmlType: 'submit'
}
}]}
/>
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);
本 Demo 演示一行文字的用法。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import FormDynamic from 'ice-dynamic-form';
import { Button, Input } from '@alifd/next';
class DInput extends Component {
constructor(props){
super(props)
}
render(){
let {htmlType,onChange,value,tips,...props} = this.props
return <input
onChange={onChange}
value={value}
type={htmlType}
{...props} />
}
}
const Components = {
DInput,
Button,
Input
}
class App extends Component {
render() {
return (
<div>
<FormDynamic
layout={{
labelTextAlign: 'left'
}}
components={Components}
value={{
userName: "jack",
a: "32"
}}
config={[{
name: 'userName',
type: 'DInput',
label: '用户名',
rules: [{
required: true,
min: 5,
message: '用户名至少 5 个字符'
}],
props: {
style: {
width: '160px',
}
}
},{
name: 'userdesc',
type: 'Input',
label: '个性签名',
props: {
style: {
width: '160px',
}
}
}, {
name: 'password',
label: '密码',
type: 'Input',
tips: '<b>密码必须同时包含字母数字符号(提示支持 HTML 标签)</b>',
rules: [{
required: true,
min: 6,
message: "密码至少6位"
}],
props: {
htmlType: 'password',
// 支持自定义
style: {
width: '160px',
border: '2px solid green'
}
}
}, {
name: "a",
type: "DInput",
label: "输入值",
// 数组内为“且”还是“或”?
// linkages数组内的条件为 或 的逻辑
effects:[{
// conditions数组内的为 且 逻辑
conditions: [{
symbol: "===",
value: "32"
}],
// action 为数组,条件满足是并发
// show/hide/setValue
actions: [{
type: "show",
target: "b",
// value: "312"
}]
}]
},{
name: "b",
type: "DInput",
label: "test2",
// 初始化问题
visible: false,
props: {
// visible: false,
}
},{
name: "b3",
type: "DInput",
label: "sss",
display: "hide",
status: "view",
props: {
value: "332255"
}
},{
name: "c",
type: "DInput",
label: "test23",
},{
name: "d",
type: "DInput",
label: "test24",
display: "hide"
}]}
effects = {[{
event:{
origin: "c"
},
options: [{
conditions: [{
symbol: "===",
value: "32"
}],
// action 为数组,条件满足是并发
// show/hide/setValue
actions: [{
type: "show",
target: "d",
// value: "312"
}]
}]
}]}
buttons={[{
name: 'loginAction',
type: 'Button',
text: '登录(成功后跳转首页)',
actionEvent: 'submit',
props: {
className: 'login-btn',
style: {
marginRight: '10px'
},
htmlType: 'submit'
}
}, {
name: 'resetAction',
text: '重置',
actionEvent: 'reset',
}]} />
</div>
);
}
}
ReactDOM.render((
<App />
), mountNode);