写在前面
JSON Schema 是一种标准的定义 JSON 数据结构的规范,并不包含对这些规范转换成表单具体说明,@yelon/form
也是根据自己的理解并结合 ng-zorro-antd
现有数据录入组件库产生的动态构建表单类库。
JSON Schema 始终都必须有一个类型为 type="object"
作为根节点,因此一个最简单的 Schema 结构至少是:
schema = {
type: 'object', // 可有可无,默认会强制为 `object`
properties: {}
}
在描述 Schema 说明之前,有必要对表单元素与 Schema 之前的联系做一个系统性说明。
我们知道,表单是由一组HTML元素组件,每一个元素对应一个 Schema 属性,属性有自己的数据类型、格式信息、视觉信息等,但这些信息不足以表述 ng-zorro-antd
所提供的丰富API接口。为了更好利用这些API接口,@yelon/form
除了实现绝大部分 JSON Schema 标准以外,额外唯一增加了一个 ui
属性用于表述属性如何渲染的问题。
无污染
当然若你对标准有非常严格,或者 JSON Schema 数据结构是来自后端的产生时,可以通过 <sf [ui]="ui">
来额外对当前 JSON Schema 添加 UI 渲染。例如:
schema = {
properties: {
url: {
type: 'string',
title: 'Web Site'
}
}
}
一个URL属性,若我们不希望用于添加 https://
前缀的情况下,就单纯的 JSON Schema 结构是无法表述,而 nz-input
又支持非常丰富的前后缀文本,则我们可以为 ui
定制并增加 https://
的前缀文本:
ui = {
$url: {
addOnBefore: 'https://'
}
}
ui 本身也是一个 JSON 结构,为了区分 JSON Schema 属性名的对应关系,必须统一对属性名加上 $
前缀;对于数组的元素对象必须使用 $items
替代。当KEY为 *
时表示对所有子表单元素都有效。
表单元素与数据结构的对应关系
一个完整的表单元素我们认为应该包含以下若干元素:
从左至向各元素描述:
结构源 | 参数 | 说明 | 类型 | 默认值 |
---|
Schema | [required] | 是否必填项 | string[] | - |
Schema | [title] | 属性描述 | string | - |
ui | [optional] | 标签可选信息 | string | - |
ui | [optionalHelp] | 标签可选帮助 | string, SFOptionalHelp | - |
ui | [placeholder] | 文字框中显示提示信息 | string | - |
Schema | [description] | 属性目的性解释 | string | - |
- | [error] | 错误信息 | string | - |
一点规范
JSONSchema(SFSchema)
JSON Schema 有完整的对每个属性的规范描述,@yelon/form
当前是基于 draft-07 规范,下列是规范具体说明:
常规类
参数 | 说明 | 类型 | 默认值 |
---|
[type] | 数据类型,支持 JavaScript 基础类型 | number,string,boolean,object,array | object |
[enum] | 枚举,静态数据源 | SFSchemaEnumType[] | - |
数值类型
参数 | 说明 | 类型 | 默认值 |
---|
[minimum] | 最小值 | number | - |
[exclusiveMinimum] | 约束是否包括 minimum 值 | boolean | - |
[maximum] | 最大值 | number | - |
[exclusiveMaximum] | 约束是否包括 maximum 值 | boolean | - |
[multipleOf] | 倍数 | number | - |
关于exclusiveMinimum和exclusiveMaximum
sf
的实现机制导致无法很好的处理 type
类型的错误捕获,因此默认情况下 sf
是忽略了所有 type
(见 config.ts)类型错误,而这两种都错误都会被认为 type
类型错误,从而导致触发无效检查的原因。(更多细节请参考 #676)
字符串类型
参数 | 说明 | 类型 | 默认值 |
---|
[maxLength] | 定义字符串的最大长度 | number | - |
[minLength] | 定义字符串的最小长度 | number | - |
[pattern] | 验证输入字段正则表达式字符串 | string | - |
数组类型
参数 | 说明 | 类型 | 默认值 |
---|
[items] | 数组元素类型描述,只支持数组对象,若需要基础类型数组可通过其他部件支持 | SFSchema | - |
[minItems] | 约束数组最小的元素个数 | number | - |
[maxItems] | 约束数组最大的元素个数 | number | - |
[uniqueItems] | 约束数组每个元素都不相同 | boolean | - |
[additionalItems] | 数组额外元素的校验规则 | SFSchema | - |
对象类型
参数 | 说明 | 类型 | 默认值 |
---|
[maxProperties] | 最大属性个数,必须是非负整数 | number | - |
[minProperties] | 最小属性个数,必须是非负整数 | number | - |
[required] | 必需属性 | string[] | - |
[properties] | 定义属性 | { [key: string]: SFSchema } | - |
条件类
参数 | 说明 | 类型 | 默认值 |
---|
[if] | 条件验证 | SFSchema | - |
[then] | 条件验证 | SFSchema | - |
[else] | 条件验证 | SFSchema | - |
条件类的校验非常强大和丰富,但是出于会破坏UI导致整个组件构建更复杂,@yelon/form
仅实现 required
的处理,并且把它当成是否显示校验目标,比如:一个登录页,会根据不同登录方式来显示不同登录模式:
schema: SFSchema = {
properties: {
type: { type: 'string', enum: [ 'mobile', 'name' ], default: 'mobile' },
name: { type: 'string' },
pwd: { type: 'string' },
mobile: { type: 'string' },
code: { type: 'string' }
},
required: [ 'type' ],
if: {
properties: { type: { enum: [ 'mobile' ] } }
},
then: {
required: [ 'mobile', 'code' ]
},
else: {
required: [ 'name', 'pwd' ]
}
};
上述的最终行为是当登录方式为 mobile
时UI显示 mobile
和 code
,反之UI显示 name
和 pwd
。
其实条件类最终被解析成 ui.visibleIf
,将其转换成如下:
{
properties: {
login_type: {
type: "string",
title: "登录方式",
enum: [
{ label: "手机", value: "mobile" },
{ label: "账密", value: "account" }
],
default: "mobile",
ui: {
widget: "radio",
styleType: "button"
}
},
mobile: {
type: "string",
ui: {
visibleIf: {
login_type: val => val === "mobile"
}
}
},
code: {
type: "number",
ui: {
visibleIf: {
login_type: val => val === "mobile"
}
}
},
name: {
type: "string",
ui: {
visibleIf: {
login_type: val => val === "account"
}
}
},
pwd: {
type: "string",
ui: {
type: "password",
visibleIf: {
login_type: val => val === "account"
}
}
}
},
required: ["login_type"]
};
逻辑类
参数 | 说明 | 类型 | 默认值 |
---|
[allOf] | 不建议 使用,可用 required 替代 | SFSchema[] | - |
[anyOf] | 不建议 使用,可用 required 和 minProperties 替代 | SFSchema[] | - |
[oneOf] | 不建议 使用,值必须是其中之一 | SFSchema[] | - |
不建议 主要是并没有对逻辑类进行UI相关处理,它同条件类类似,会影响UI渲染。
格式与视觉类
参数 | 说明 | 类型 | 默认值 |
---|
[title] | 属性描述 | string | - |
[description] | 属性目的性解释 | string | - |
[default] | 默认值 | any | - |
[readOnly] | 是否只读状态,等同 nzDisabled | boolean | - |
[format] | 数据格式,文档 | string | - |
其他
参数 | 说明 | 类型 | 默认值 |
---|
[definitions] | 内部类型定义体 | SFSchemaDefinition | - |
[$ref] | 引用定义体 | string | - |
[$comment] | 针对开发者的注释,无任何意义,也不会被校验 | string | - |
非标准
参数 | 说明 | 类型 | 默认值 |
---|
[ui] | 指定UI配置信息,优先级高于 sf 组件 ui 属性值 | SFUISchemaItem | - |
UI(SFUISchemaItem)
UI Schema 结构由通用性和小部件API两部分组成,以下是通用性部分进行接口说明,小部件部分自行参数小部件API。
为了小部件的API完整性,小部件Schema说明可能也会包含下列通用性部分。
SFUISchema
等同 <sf [ui]="ui">
一组与 JSON Schema 结构相对应的 UI 结构体,类型为:[ key: string ]: SFUISchemaItem
。
基础类
参数 | 说明 | 类型 | 默认值 |
---|
[debug] | 调试模式 | boolean | - |
[order] | 属性顺序 | string[] | - |
[asyncData] | 异步静态数据源 | (input?: any) => Observable<SFSchemaEnumType[]> | - |
[hidden] | 是否隐藏渲染 | boolean | false |
[visibleIf] | 指定条件时才显示 | { [key: string]: any[] | ((value: any, property: FormProperty) => boolean) } | - |
[visibleIfLogical] | 指定多个 visibleIf 时采用的逻辑关系 | or, and | or |
[acl] | ACL权限,等同 can() 参数值 | ACLCanType | - |
visibleIf
指定条件时才显示,例如:
visibleIf: { shown: [ true ] }
:当 shown: true
时才显示当前属性
visibleIf: { shown: [ '$ANY$' ] }
:当 shown
包括任意值时
visibleIf: { shown: (value: any, property: FormProperty) => value > 0 }
:复杂表达式
校验类
参数 | 说明 | 类型 | 默认值 |
---|
[liveValidate] | 是否实时校验 | boolean | true |
[firstVisual] | 是否立即呈现错误视觉 | boolean | false |
[onlyVisual] | 是否只展示错误视觉不显示错误文本 | boolean | false |
[ignoreKeywords] | 忽略某些数据类型校验 | string[] | |
[errors] | 自定义错误信息文本 | { [ key: string ]: string | ((obj: ErrorData) => string) } | - |
[showRequired] | 是否展示必填项标识 * | boolean | - |
[validator] | 自定义校验,最后结果会与 Ajv 校验结果进行合并显示 | (value: any, formProperty: FormProperty, form: PropertyGroup) => ErrorData[] | - |
数组类
参数 | 说明 | 类型 | 默认值 |
---|
[items] | 指定子元素的UI | SFUISchema | - |
[addTitle] | 指定添加按钮文本 | string | 添加 |
[addType] | 指定添加按钮风格,等同按钮 nzType | string | dashed |
[removable] | 指定是否显示移除按钮 | boolean | - |
[removeTitle] | 指定移除按钮文本 | string | 移除 |
表单元素类
参数 | 说明 | 类型 | 默认值 |
---|
[type] | 指定 input 的 type 值 | string | text |
[placeholder] | 文字框中显示提示信息 | string | - |
[autofocus] | 加载时是否获得焦点 | boolean | - |
渲染类
参数 | 说明 | 类型 | 默认值 |
---|
[widget] | 指定采用什么小部件渲染 | string | - |
[i18n] | 指 schema.title 的国际化键值 | string | - |
[descriptionI18n] | 指 schema.description 的国际化键值 | string | - |
[class] | 自定义类,等同 [ngClass] 值 | string,string[] | - |
[width] | 指定宽度,单位:px | number | - |
[size] | 元素组件大小 | default,large,small | - |
[grid] | 响应式属性 | SFGridSchema | - |
[optional] | 标签可选信息 | string | - |
[optionalHelp] | 标签可选帮助 | string, SFOptionalHelp | - |
响应式属性SFGridSchema
grid
属性等同完整的 Grid栅格系统,透过 grid
可以决定表单如何渲染。
参数 | 说明 | 类型 | 默认值 |
---|
[gutter] | 栅格间隔 | number | - |
[span] | 每个表单元素栅格占位格数,为 0 时相当于 display: none | number | - |
[xs] | <768px 响应式栅格,可为栅格数或一个包含其他属性的对象 | number, SFGridSizeSchema | - |
[sm] | ≥768px 响应式栅格,可为栅格数或一个包含其他属性的对象 | number, SFGridSizeSchema | - |
[md] | ≥992px 响应式栅格,可为栅格数或一个包含其他属性的对象 | number, SFGridSizeSchema | - |
[lg] | ≥1200px 响应式栅格,可为栅格数或一个包含其他属性的对象 | number, SFGridSizeSchema | - |
[xl] | ≥1600px 响应式栅格,可为栅格数或一个包含其他属性的对象 | number, SFGridSizeSchema | - |
[xxl] | 保留字段,0.7.0 后支持 | number, SFGridSizeSchema | - |
水平布局类Schema
务必二者总和为 24
参数 | 说明 | 类型 | 默认值 |
---|
[spanLabel] | label 所占栅格数 | number | 5 |
[spanControl] | 表单控件所占栅格数 | number | 19 |
[offsetControl] | control 栅格左侧的间隔格数,间隔内不可以有栅格 | number | - |
[spanLabelFixed] | label 固定宽度 | number | - |