schemaForm的核心组件。用于解析JsonSchema,为SchemaForm提供支持。
- ajv
- jsonschema
jsonschema;用于描述json的结构。 uischema;用于描述界面的表现形式,是jsonschema的增强属性。
- 去掉ajv的依赖
let schema = {
type: "object",
$id: "dnd-oneof",
title: "oneof测试schema",
default: {},
required: ["value"],
properties: {
type: {
type: "number",
enum: [1, 2, 3, 4],
title: "类型选择",
description: "1:数字,2:字符串,3:bool,4:object"
},
value: {
oneOf: [{
$id: "dnd-oneof-number",
type: "number",
title: "这是一个数字类型"
}, {
$id: "dnd-oneof-string",
type: "string",
title: "这是一个字符串类型"
}, {
$id: "dnd-oneof-boolean",
type: "boolean",
title: "这是一个bool类型"
}, {
$id: "dnd-oneof-object",
type: "object",
title: "这是一个object类型",
default: {},
required: ["a", "b"],
properties: {
a: {
type: "string",
default: "nick"
},
b: {
type: "boolean",
default: true
}
}
}]
}
}
};
存储了所有key与schemaKey的对应关系
example: 'dnd-oneof-object/a': 'dnd-oneof-object#/properties/a',
存储了schemaKey对应的schema
example:
{
'dnd-oneof-object#/properties/a': {
type: 'string',
default: 'nick',
keys: ['value','a'],
schemaPath: 'dnd-oneof-object#/properties/a'
}
}
所有的keyword处理方式。目前有ref和oneOf;
- ref: 处理schema中的$ref关键字
- oneOf: 处理schema中的oneOf关键字
- anyOf: 处理schema中的anyOf关键字
- definitions: 处理schema中的definitions关键字
schema类型的处理方式
- array schema中数组类型
- object schema中的对象类型
- undefined schema中的其他简单类型(string,number,integer,any,boolean)
schemaTypeFactory.add("array", array);
schemaTypeFactory.add("string", none);
schemaTypeFactory.add("undefined", none);
schemaTypeFactory.add("number", none);
schemaTypeFactory.add("null", none);
schemaTypeFactory.add("any", none);
schemaTypeFactory.add("integer", none);
schemaTypeFactory.add("boolean", none);
schemaTypeFactory.add("object", object);
解析schema中的所有字段,存储到【schemaFieldFactory】中
/**
* 构造函数
* @param ajv Ajv的一个实例
* @param schema jsonschema
* @param $id schema的$id字段,用于找到schema
*/
constructor(private ajv: Ajv, schema: JSONSchema6, public readonly $id = "")
解析uiSchama,与对应的schema合并
/**
* 构造函数
* @param ajv Ajv的一个实例
* @param schema schemaPath
* @param parent 父亲schema
* @param uiSchemas uiSchemas
*/
constructor(ajv: Ajv, private schemaPath: string, public parent: UiSchema | null = null, private uiSchemas: Array<UiSchema | string> = ["*"]) {
定义Schema
const schema: JSONSchema6 = {
type: "object",
$id: "design",
required: ["name", "dsModelIds"],
properties: {
name: {
type: "string",
title: "面板名称"
},
description: {
type: "string",
title: "面板详情"
},
appType: {
type: "string",
title: "应用类型"
},
dsModelIds: {
type: "array",
items: {
type: "number"
}
},
dsModelData: {
type: "object",
properties: {
data: {
type: "object"
},
ids: {
type: "object"
}
}
},
infoOptions: {
type: "array",
items: {
type: "object",
properties: {
label: {
type: "string"
},
data: {
type: "object"
},
infoOptions: {
$ref: "design#/properties/infoOptions"
}
}
}
}
}
};
解析上一步中定义的schema,curAjv是一个ajv的实例。
let someResolve = new ResolveLib(curAjv, schema);
最后与定义的uiSchema做合并。
/**
* 参数说明
* @param $1 ajv的一个实例
* @param $2 jsonschema的当前路径
* @param $3 父亲schema
* @param $4 uiSchema
* @return Array类型
*/
let merge = new MergeLib(curAjv, "design", null, ["infoOptions/-"]);
返回值:
[{
"type": "object",
"properties": {
"label": {
"type": "string",
"keys": ["infoOptions", "-", "label"]
},
"data": {
"type": "object",
"keys": ["infoOptions", "-", "data"]
},
"infoOptions": {
"$ref": "design#/properties/infoOptions",
"keys": ["infoOptions", "-", "infoOptions"]
}
},
"keys": ["infoOptions", "-"],
"schemaPath": "design#/properties/infoOptions/items",
"key": "design/infoOptions/-"
}]
{
"type": "object",
"$id": "echart",
"title": "echarts参数设置",
"default": {},
"properties": {
"title": {
"$ref": "echart-title#"
},
"toolbox": {
"$ref": "echart-toolbox#"
},
"tooltip": {
"$ref": "echart-tooltip#"
},
"legend": {
"$ref": "echart-legend#"
},
"series": {
"$ref": "echart-series#"
},
"xAxis": {
"$ref": "echart-axis#"
},
"yAxis": {
"$ref": "echart-axis#"
}
}
}
在做echart的配置界面的时候,由于参数众多,而且很多参数都重复,不得不把echart的jsonschema拆分成若干个json文件来复用。上面的json文件使用$ref来连接其他的schema,使得schema的依赖过于繁琐。如果我们要使用这个schema,就必须先解析其依赖的schema,这样就有问题了。我们能不能不关系依赖呢?
解决方案:
- 这个方法用于加载我们需要的schema文件。
/**
* 动态加载schema方法
* 可以在组件中去使用
*/
const initSchema = (schemaId: string) => {
// getSchema是一个接口方法,用来获取json的数据
return getSchema.get(null, {
params: {
id: schemaId + ".json"
}
}).then((schema: JSONSchema6) => {
// 这里使用compileAsync来获取schema的验证信息
// 这个方法可以解析依赖关系,然后使用ajv中的loadSchema来加载依赖的jsonschema
curAjv.compileAsync(schema).then(() => {
// 解析获取的schema,这里已经解析完了所有的依赖
let resolve = new ResolveLib(curAjv, schema);
});
}).catch(() => {
console.error("fetch schema [" + uri + "] error!");
});
}
- 配置ajv中的loadSchema方法,用于加载$ref中使用的schema文件。
// 初始化ajv实例
export const curAjv: ajv.Ajv = ajvErrors(new ajv({
allErrors: true,
jsonPointers: true,
useDefaults: true,
format: "full",
$data: true,
errorDataPath: "property",
removeAdditional: true,
// 关键参数
loadSchema: initSchema
}));
- react示例
import { ResolveLib, schemaKeysFactory } from "fx-schema-form-core";
class ComponentHoc extends React.PureComponent<any, any> {
/**
* 加载完毕后,update当前组件
*/
private initSchema(schemaId: string){
initSchema(schemaId).then(this.forceUpdate);
}
/**
* 如果当前的schema不存在,则远程拉取
*/
public render(): JSX.Element | null {
const { schemaId, ...extraProps } = this.props;
if (!schemaKeysFactory.has(schemaId)) {
this.initSchema(schemaId);
return null;
}
return <span>schema已经解析好了�</span>;
}
}
npm test
测试命令npm run build
打包命令