react-jsonschema-form

使用JSON Schema构建Web表单的React组件。https://mozilla-services.github.io/react-jsonschema-form

一个简单的React组件,能够从JSON模式构建HTML表单,默认情况下使用Bootstrap语义。

一个活动的游乐场在gh-pages上面。

live playground

设计哲学

response-jsonschema-form旨在基于JSON模式自动生成一个response表单。它是kinto-admin项目中的一个主要组件。如果您想为任何数据生成一个表单(看不见),只需给出一个JSON模式,那么response-jsonschema-form可能适合您。如果您对数据有先入为主的了解,并且希望有一个用于为其生成表单的工具包,那么您可以在其他地方寻找。

response-jsonschema-form验证数据是否符合给定的模式,但不阻止用户输入不适合的数据(例如,从数字字段中删除非数字,或者向已经“满”的数组中添加值)。

安装

需要 React 15.0.0+.

注意:存储库的主分支反映了正在进行的开发。版本作为标记发布。永远不要盲目地从master安装,而应该检查可用的稳定版本。

作为一个基于npm的项目依赖项

1
npm install react-jsonschema-form --save

注意:当库呈现自引导HTML语义时,您必须自己构建和加载Bootstrap样式。

作为CDN提供的脚本

1
<script src="https://unpkg.com/react-jsonschema-form/dist/react-jsonschema-form.js"></script>

源映射在此url中可用

注意:CDN版本不嵌入react或react-dom

您还需要别名默认导出属性来使用表单组件:

1
2
3
const Form = JSONSchemaForm.default;
// or
const {default: Form} = JSONSchemaForm;

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import React, { Component } from "react";
import { render } from "react-dom";

import Form from "react-jsonschema-form";

const schema = {
title: "Todo",
type: "object",
required: ["title"],
properties: {
title: {type: "string", title: "Title", default: "A new task"},
done: {type: "boolean", title: "Done?", default: false}
}
};

const log = (type) => console.log.bind(console, type);

render((
<Form schema={schema}
onChange={log("changed")}
onSubmit={log("submitted")}
onError={log("errors")} />
), document.getElementById("app"));

这会生成这样的表单(假设您加载了标准的Bootstrap样式表):

Bootstrap样式

表单初始化

通常需要用现有数据预填表单;这是通过传递与模式匹配的formData prop对象来实现的:

1
2
3
4
5
6
7
8
9
const formData = {
title: "First task",
done: true
};

render((
<Form schema={schema}
formData={formData} />
), document.getElementById("app"));

注意:如果表单只有一个字段,则将一个值传递给formData. ex: formData=’Charlie’

警告:如果您遇到父组件可以重新呈现的情况,请确保侦听onChange事件并更新传递给formData属性的数据。

表单事件处理

表单提交

表单错误事件处理

表单数据变化

表单字段失焦事件

表单字段焦点事件

以编程方式提交表单

您可以使用该引用来获取表单组件,并调用submit方法以编程方式提交表单,无需提交按钮。此方法将分派表单的提交事件,并调用传递给onSubmit props的函数。

1
2
3
4
5
6
7
8
9
const onSubmit = ({formData}) => console.log("Data submitted: ",  formData);
let yourForm;

render((
<Form schema={schema}
onSubmit={onSubmit} ref={(form) => {yourForm = form;}}/>
), document.getElementById("app"));

yourForm.submit();

表单定制

uiSchema对象

JSONSchema在描述如何将给定的数据类型呈现为表单输入组件时受到限制。这就是为什么这个库引入了UI模式的概念。

UI模式基本上是一个对象文字,提供了关于表单应该如何呈现的信息,而JSON模式告诉我们应该如何呈现。

uiSchema对象遵循表单字段层次结构的树形结构,并定义如何呈现每个属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const schema = {
type: "object",
properties: {
foo: {
type: "object",
properties: {
bar: {type: "string"}
}
},
baz: {
type: "array",
items: {
type: "object",
properties: {
description: {
"type": "string"
}
}
}
}
}
}

const uiSchema = {
foo: {
bar: {
"ui:widget": "textarea"
},
},
baz: {
// note the "items" for an array
items: {
description: {
"ui:widget": "textarea"
}
}
}
}

render((
<Form schema={schema}
uiSchema={uiSchema} />
), document.getElementById("app"));

选择小部件

uiSchema ui:widget属性告诉表单应该使用哪个ui小部件呈现字段。

例子:

1
2
3
4
5
6
7
8
9
10
11
const uiSchema =  {
done: {
"ui:widget": "radio" // could also be "select"
}
};

render((
<Form schema={schema}
uiSchema={uiSchema}
formData={formData} />
), document.getElementById("app"));

以下是针对不同JSONSchema数据类型支持的可选小部件列表:

boolean 字段

  • radio:以true、false作为可选值的单选按钮组;
  • select:以true和false作为选项的选择框;
  • 默认情况下,使用复选框

注意:要设置布尔字段的标签,可以在模式中设置enumNames,而不是使用true和false。注意,enumNames属于您的模式,而不是uiSchema,而且顺序总是[true、false]。

string 字段

  • textarea:使用textarea元素;
  • password:使用input[type=password]元素;
  • color:使用input[type=color]元素;
  • 默认情况下,使用常规input[type=text]元素。
string 格式

内置的string字段还支持JSONSchema format属性,默认情况下将为以下字符串格式呈现适当的小部件:

  • email:使用input[type=email]元素;
  • uri:使用input[type=url]元素;
  • data-url:默认情况下,使用input[type=file]元素;如果字符串是数组的一部分,将自动处理多个文件(请参阅文件小部件)。
  • date:默认情况下,使用input[type=date]元素;
  • date-time:默认情况下,使用input[type=datetime-local]元素。

date-time

请注意,尽管它们是标准化的,但是Firefox和IE还不支持date-time-local和date输入元素。如果您打算针对这些平台,可以使用两个替代小部件:

  • alt-datetime:选择年、月、日、时、分、秒六个元素;
  • alt-date:三个select元素用于选择年份、月份和日期。

通过向uiSchema中的ui:options提供yearsRange属性,您可以自定义显示在year下拉菜单中的year列表。还可以使用hideNowButton和hideClearButton选项删除Now和Clear按钮。

1
2
3
4
5
6
7
8
9
10
11
12
uiSchema: {
a_date: {
"alt-datetime": {
"ui:widget": "alt-datetime",
"ui:options": {
yearsRange: [1980, 2030],
hideNowButton: true,
hideClearButton: true,
},
},
},
},

number和integer字段

  • updown:一个input[type=number]向上向下选择器;
  • range: input[type=range]滑块;
  • radio:带有枚举值的单选按钮组。这只能在为该输入指定枚举值时使用。
  • 默认情况下,使用常规input[type=text]元素。

注意:如果定义了JSONSchema的minimum、maximum和multipleOf值,则input属性值的min、max和step值将采用这些值。

禁用字段

ui:disabled uiSchema指令将禁用给定字段中的所有子小部件。

只读字段

ui:readonly uiSchema指令将指定字段中的所有子部件标记为只读。

注意:如果您想知道禁用字段和只读字段之间的区别:将字段标记为只读将使其呈现灰色,但是它的文本值是可选择的。禁用它将完全阻止选择它的值。

隐藏小部件

通过将其ui:widget uiSchema指令设置为hidden,可以为字段使用隐藏小部件:

1
2
3
4
5
6
7
8
9
10
const schema = {
type: "object",
properties: {
foo: {type: "boolean"}
}
};

const uiSchema = {
foo: {"ui:widget": "hidden"}
};

笔记:

  • 隐藏小部件只支持布尔、字符串、数字和整数模式类型;
  • 隐藏的小部件从formData支柱获取它的值。

文件部件

Multiple files
File widget input ref

对象字段排序

对象item选项

expandable 选项

数组item选项

orderable选项

addable选项

removable选项

自定义CSS类名

枚举字段的自定义标签

另一种兼容json模式的方法

枚举字段的禁用属性

多项选择题列表

自动生成小部件ids

默认情况下,这个库将为所有呈现的小部件生成表单特有的id。如果您打算在同一个页面中使用表单组件的多个实例,明智的做法是为这些实例声明一个根前缀,使用ui:rootFieldId uiSchema指令:

1
2
3
const uiSchema = {
"ui:rootFieldId": "myform"
};

所以所有小部件的id都以myform为前缀。

表单操作按钮

帮助文本

标题文本

描述文本

自动对焦

文本区域的行选项

占位符

字段标签

HTML5的Input类型

Form属性

Form组件支持以下html属性:

1
2
3
4
5
6
7
8
9
10
11
<Form
id="edit-form"
className="form form-wide"
name="awesomeForm"
method="post"
target="_blank"
action="/users/list"
autocomplete="off"
enctype="multipart/form-data"
acceptcharset="ISO-8859-1"
schema={} />

Form禁用

高级定制

- 自定义字段 自定义模板 自定义部件
它所做的 覆盖所有的行为 只覆盖布局 只覆盖输入框(而不是布局、标签、帮助或验证)

字段模板

要控制每个字段(每个表单行)的内部组织,可以为表单定义一个字段模板。

字段模板基本上是一个正在传递与字段相关的道具的无状态组件,允许您按照自己的喜好构造表单行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function CustomFieldTemplate(props) {
const {id, classNames, label, help, required, description, errors, children} = props;
return (
<div className={classNames}>
<label htmlFor={id}>{label}{required ? "*" : null}</label>
{description}
{children}
{errors}
{help}
</div>
);
}

render((
<Form schema={schema}
FieldTemplate={CustomFieldTemplate} />,
), document.getElementById("app"));

如果您想自己处理每个元素的呈现,可以使用props rawHelp、rawDescription和rawErrors。

以下props传递给自定义字段模板组件:

  • id: 层次结构中字段的id。您可以使用它呈现针对包装的小部件的标签
  • classNames: 包含基本Bootstrap CSS类的字符串,与uiSchema中定义的自定义类合并
  • label: 该字段的计算标签,作为字符串
  • description:呈现字段描述的组件实例,如果定义了字段描述(这将使用任何自定义DescriptionField定义)
  • rawDescription: 包含定义的任何ui:description uiSchema指令的字符串
  • children: 该字段行的字段或小部件组件实例
  • errors: 组件实例列出该字段遇到的任何错误.
  • rawErrors: 一个字符串数组,列出从该字段遇到的错误中生成的所有错误消息.
  • help: 呈现任何ui的组件实例:帮助定义的uiSchema指令.
  • rawHelp: 包含任何ui的字符串:帮助定义uiSchema指令。注意:如果传递的ui:help是一个response组件而不是字符串,rawHelp将是未定义的.
  • hidden: 一个布尔值,表示字段是否应该隐藏.
  • required: 一个布尔值,表示是否需要字段.
  • readonly: 一个布尔值,表示字段是否只读.
  • disabled:一个布尔值,表示字段是否禁用.
  • displayLabel: 一个布尔值,表示标签是否应该被呈现。这对于不想让UI混乱的数组中的嵌套字段非常有用.
  • fields: 包含所有表单字段的数组,包括自定义字段和内置字段.
  • schema: 该字段的模式对象.
  • uiSchema: 该领域的uiSchema对象.
  • formContext: 传递给Form的formContext对象.

注意:您只能为表单定义一个字段模板。如果您需要许多字段,那么可能是时候查看自定义字段了。

数组字段模板

FieldTemplate类似,您可以使用ArrayFieldTemplate自定义如何呈现数组。这允许您自定义数组和数组中的每个元素。

请参见customArray.js了解更好的例子

下面的道具被传递到每个ArrayFieldTemplate:

  • DescriptionField:注册表中的DescriptionField(如果您想使用它)
  • TitleField:注册表中的TitleField(如果您想使用它)
  • canAdd:一个布尔值,表示是否可以向数组中添加新元素
  • className:类名字符串
  • disabled:一个布尔值,表示数组是否禁用
  • idSchema:对象
  • items:表示数组中项目的对象数组。每一项都代表一个子元素,其属性如下所述
  • onAddClick: (event) => void:向数组中添加新项的函数
  • readonly:一个布尔值,表示数组是否只读
  • required:一个布尔值,表示是否需要数组
  • schema:该数组的模式对象
  • uiSchema:这个数组字段的uiSchema对象
  • title:包含数组标题的字符串值
  • formContext:传递给Form的formContext对象
  • formData:该数组的formData

以下 props是items中每个元素的一部分:

  • children:项目内容的html
  • className:类名字符串
  • disabled:表示数组项是否禁用的布尔值
  • hasMoveDown:一个布尔值,表示数组项是否可以向下移动
  • hasMoveUp:一个布尔值,表示数组项是否可以向上移动
  • hasRemove:一个布尔值,表示是否可以删除数组项
  • hasToolbar:一个布尔值,表示数组项是否有工具栏
  • index:表示数组项在项中出现的索引的数字
  • onDropIndexClick: (index) => (event) => void:返回一个函数,该函数删除索引处的项目
  • onReorderClick: (index, newIndex) => (event) => void:返回一个与newIndex交换索引项的函数
  • readonly:一个布尔值,用于声明数组项是否为只读

对象字段模板

与FieldTemplate类似,您可以使用ObjectFieldTemplate自定义如何呈现对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function ObjectFieldTemplate(props) {
return (
<div>
{props.title}
{props.description}
{props.properties.map(element => <div className="property-wrapper">{element.content}</div>)}
</div>
);
}

render((
<Form schema={schema}
ObjectFieldTemplate={ObjectFieldTemplate} />,
), document.getElementById("app"));
  • DescriptionField:注册表中的DescriptionField(如果您想使用它)
  • TitleField:注册表中的TitleField(如果您想使用它)。
  • title:包含对象标题的字符串值。
  • description:包含对象描述的字符串值。
  • properties:表示数组中属性的对象数组。每个属性表示一个子属性,其属性描述如下。
  • required:一个布尔值,表示是否需要对象。
  • schema:此对象的模式对象。
  • uiSchema:该对象字段的uiSchema对象。
  • idSchema:包含此对象的id和其属性的id的对象。
  • formData:对象的表单数据。
  • formContext:传递给Form的formContext对象。

以下props是properties中每个元素的一部分:

  • content:属性内容的html。
  • name:表示属性名称的字符串。
  • disabled:一个布尔值,表示对象属性是否禁用。
  • readonly:一个布尔值,表示属性是否只读。

错误列表模板

Id前缀

为了避免与DOM中现有的id冲突,可以更改ids使用的前缀(默认是root)

1
2
3
4
render((
<Form schema={schema}
idPrefix={"rjsf_prefix"}/>,
), document.getElementById("app"));

这将呈现<input id="rjsf_prefix_key">,而不是<input id="root_key">

自定义小部件和字段

API允许指定您自己的自定义部件和字段组件:

  • 小部件表示用户输入数据的HTML标记,例如。input、select等。
  • 一个字段通常封装一个或多个部件,通常处理内部字段状态;可以将字段看作表单行,包括标签。

自定义小部件组件

您可以为以下json数据类型向uiSchema提供您自己的自定义小部件:

  • string
  • number
  • integer
  • boolean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const schema = {
type: "string"
};

const uiSchema = {
"ui:widget": (props) => {
return (
<input type="text"
className="custom"
value={props.value}
required={props.required}
onChange={(event) => props.onChange(event.target.value)} />
);
}
};

render((
<Form schema={schema}
uiSchema={uiSchema} />,
), document.getElementById("app"));

以下props传递给自定义小部件组件:

  • id:该字段生成的id;
  • schema:此字段的JSONSchema子模式对象;
  • value:该字段的当前值;
  • required:该字段的所需状态;
  • disabled:如果小部件被禁用,则为true;
  • readonly:如果小部件是只读的,则为true;
  • onChange:值更改事件处理程序;每次它改变时,用新值调用它;
  • onBlur:输入模糊事件处理程序;使用小部件id和值调用它;
  • onFocus:输入焦点事件处理程序;使用小部件id和值调用它;
  • options:作为prop传递到组件的选项的映射(请参阅自定义小部件选项)。
  • formContext:传递给Form的formContext对象。

注意:在v0.35.0之前,options道具包含枚举字段的选项列表(标签和值)。由于v0.35.0,它现在将此列表作为options对象中的enumOptions属性公开

自定义组件注册

或者,您可以通过将小部件道具传递给表单组件来一次性注册它们,并从uiSchema引用它们的标识符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const MyCustomWidget = (props) => {
return (
<input type="text"
className="custom"
value={props.value}
required={props.required}
onChange={(event) => props.onChange(event.target.value)} />
);
};

const widgets = {
myCustomWidget: MyCustomWidget
};

const uiSchema = {
"ui:widget": "myCustomWidget"
}

render((
<Form
schema={schema}
uiSchema={uiSchema}
widgets={widgets} />
), document.getElementById("app"));

如果您将uiSchema公开为纯JSON,这将非常有用,因为JSON不能携带函数。

注意:在0.40.0之前,可以将小部件注册为对象,形状{component: MyCustomWidget, options:{…} }。这个未文档化的API已经被删除。相反,您可以使用React defaultProps属性注册一个定制小部件。defaultProps。选项可以是包含自定义选项的对象。

自定义小部件选项

如果需要将选项传递给定制小部件,可以添加一个包含这些属性的ui:options对象。如果小部件有defaultProps,这些选项将与defaultProps的(可选)options对象合并:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const schema = {
type: "string"
};

function MyCustomWidget(props) {
const {options} = props;
const {color, backgroundColor} = options;
return <input style={{color, backgroundColor}} />;
}

MyCustomWidget.defaultProps = {
options: {
color: "red"
}
};

const uiSchema = {
"ui:widget": MyCustomWidget,
"ui:options": {
backgroundColor: "yellow"
}
};

// renders red on yellow input
render((
<Form schema={schema}
uiSchema={uiSchema} />
), document.getElementById("app"));

定制部件文本输入

所有呈现文本输入的小部件都在内部使用BaseInput组件。如果需要自定义所有文本输入,而不需要单独自定义所有小部件,则可以在小部件属性的Form中提供一个基输入组件(请参见自定义组件注册)。

自定义字段组件

通过指定ui:field属性,您可以为uiSchema提供您自己的字段组件,这些组件基本上适用于任何json模式数据类型。

例如,让我们创建并注册一个处理纬度和经度的geo组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const schema = {
type: "object",
required: ["lat", "lon"],
properties: {
lat: {type: "number"},
lon: {type: "number"}
}
};

// Define a custom component for handling the root position object
class GeoPosition extends React.Component {
constructor(props) {
super(props);
this.state = {...props.formData};
}

onChange(name) {
return (event) => {
this.setState({
[name]: parseFloat(event.target.value)
}, () => this.props.onChange(this.state));
};
}

render() {
const {lat, lon} = this.state;
return (
<div>
<input type="number" value={lat} onChange={this.onChange("lat")} />
<input type="number" value={lon} onChange={this.onChange("lon")} />
</div>
);
}
}

// Define the custom field component to use for the root object
const uiSchema = {"ui:field": "geo"};

// Define the custom field components to register; here our "geo"
// custom field component
const fields = {geo: GeoPosition};

// Render the form with all the properties we just defined passed
// as props
render((
<Form
schema={schema}
uiSchema={uiSchema}
fields={fields} />
), document.getElementById("app"));

注意:注册的字段可以跨整个模式重用

字段 props

字段组件将始终传递以下props:

  • schema:该字段的JSON模式;
  • uiSchema:该领域的uiSchema;
  • idSchema:每个子字段的惟一id树;
  • formData:该字段的数据;
  • errorSchema:该字段及其子字段的错误树;
  • registry:registry对象(接下来读取)
  • formContext: formContext对象(下一个读)
registry对象

registry是一个对象,包含注册的自定义字段和小部件以及根模式定义。

  • fields:自定义注册字段。默认情况下,该对象包含标准的schemfields、TitleField和DescriptionField组件;
  • widgets:自定义注册小部件(如果有);
  • definitions:根模式定义(如果有的话)
  • formContext: formContext对象。

registry是向下传递到组件树的,因此您可以从自定义字段和SchemaField组件访问它。

formContext对象

您可以为表单提供一个formContext对象,该对象传递给所有字段和小部件(包括TitleField和DescriptionField)。用于实现上下文感知字段和小部件。

自定义数组字段按钮

ArrayField组件提供了一个用于添加、删除和重新排序数组项的UI,这些按钮使用Bootstrap glyphicons。如果您不使用符号图标,但仍然希望为这些按钮提供自己的图标或文本,您可以使用CSS轻松地做到这一点:

1
2
3
4
5
i.glyphicon { display: none; }
.btn-add::after { content: 'Add'; }
.array-item-move-up::after { content: 'Move Up'; }
.array-item-move-down::after { content: 'Move Down'; }
.array-item-remove::after { content: 'Remove'; }

自定义SchemaField

警告:这是一个强大的特性,因为您可以覆盖整个表单行为,并很容易将其搞乱。小心轻放。

您可以提供自己的SchemaField base React组件实现,用于呈现任何JSONSchema字段类型,包括对象和数组。当您希望用补充幂来扩充给定字段类型时,这非常有用。

要进行此操作,请将具有SchemaField属性的fields对象传递给Form组件;下面是包装标准SchemaField lib组件的一个相当愚蠢的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import SchemaField from "react-jsonschema-form/lib/components/fields/SchemaField";

const CustomSchemaField = function(props) {
return (
<div id="custom">
<p>Yeah, I'm pretty dumb.</p>
<SchemaField {...props} />
</div>
);
};

const fields = {
SchemaField: CustomSchemaField
};

render((
<Form schema={schema}
uiSchema={uiSchema}
formData={formData}
fields={fields} />
), document.getElementById("app"));

如果您想知道这是如何有用的,请查看Kinto formbuilder存储库,了解如何使用它为任何表单字段提供编辑功能。

传递给定制模式的道具与传递给定制字段的props是相同的。

自定义默认字段和小部件

您可以覆盖任何默认字段和小部件,包括内部小部件,如ObjectField为布尔值呈现的CheckboxWidget。您可以覆盖任何字段和小部件,只要在字段和小部件道具中提供定制的字段/小部件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const CustomCheckbox = function(props) {
return (
<button id="custom" className={props.value ? "checked" : "unchecked"} onClick={() => props.onChange(!props.value)}>
{props.value}
</button>
);
};

const widgets = {
CheckboxWidget: CustomCheckbox
};

render((
<Form schema={schema}
uiSchema={uiSchema}
formData={formData}
widgets={widgets} />
), document.getElementById("app"));

这允许您使用自定义字段和小部件创建可重用的自定义表单类:

1
2
3
4
5
6
7
8
9
10
11
12
const customFields = {StringField: CustomString};
const customWidgets = {CheckboxWidget: CustomCheckbox};

function MyForm(props) {
return <Form fields={customFields} widgets={customWidgets} {...props} />;
}

render((
<MyForm schema={schema}
uiSchema={uiSchema}
formData={formData} />
), document.getElementById("app"));

自定义标题

自定义描述

表单数据验证

表单样式

模式定义和引用

属性依赖性

模式的依赖关系

这个库还支持基于表单数据修改模式的某些部分。

条件

动态

JSON模式支持状态

该组件遵循JSON模式规范。由于窗体小部件的局限性,有以下几个例外:

提示和技巧

贡献

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2021 朝着牛逼的道路一路狂奔 All Rights Reserved.

访客数 : | 访问量 :