JSON SCHEMA
有官网,开源的草案。JSON SCHEMA官网
本项目最终产出的项目就是基于JSON SCHEMA实现,目的就是表单的自动化装配。
JSON SCHEMA:用json定义数据,并校验数据。
一些名称的定义最好参考官网的建议。
AJV
AJV 官网
一个JSON SCHEMA的校验器。
AJV最简单的用法(其实也没有别的用法)
核心功能就是校验一份数据是不是我们想要的schema,如果可以返回收到每一个不是的标记的地方。
安装AJV
npm install ajv
新建schema-tests\test1.js
:
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'string',
minLength: 10
}
//生成schema校验规则
const validate = ajv.compile(schema)
const data = 'jokcy'
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
代码会有很多eslint报错,新增.eslintignore
文件,忽略一下整个文件夹:
schema-tests
执行js文件
image.png
如果传入一个数字:
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'string',
minLength: 10
}
//生成schema校验规则
const validate = ajv.compile(schema)
const data = 12
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
image.png
稍微复杂一下:
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
// minLength: 10,
},
age: {
type: "number"
},
pets: {
type: 'array',
items: {
type: 'string'
}
},
isWorker: {
type: 'boolean'
}
},
}
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
运行正常,没有打印数据:
image.png
非空校验如下编写:
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
// minLength: 10,
},
age: {
type: "number"
},
pets: {
type: 'array',
items: {
type: 'string'
}
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
image.png
还可以更深入地限制数组:
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
// minLength: 10,
},
age: {
type: "number"
},
pets: {
type: 'array',
items: [{
type: 'string'
}, {
type: 'number'
}] //数组只能有2个值,第一个值必须是string,第二个值必须是数字
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
Format
格式校验。format只针对String和number,其他类型没有此属性。
image.png
自定义format
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
format: "test"
// minLength: 10,
},
age: {
type: "number"
},
pets: {
type: 'array',
// items: [{
// type: 'string'
// }, {
// type: 'number'
// }] //数组只能有2个值,第一个值必须是string,第二个值必须是数字
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
ajv.addFormat('test', (data) => {
console.log(data, '------------------------')
return data === 'haha'
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 80],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
image.png
怎么通过,修改传入数据的data的name为haha即可:
const data = {
name: 'haha',
age: 18,
pets: ['mimi', 80],
isWorker: true
}
image.png
ajv中自定义关键字
自定义关键字有4种方法。
image.png
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
test: true,
},
age: {
type: "number"
},
pets: {
type: 'array',
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
ajv.addKeyword('test', {
validate(schema, data) {
console.log(schema, data)
return true;
}
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
image.png
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
test: true,
},
age: {
type: "number"
},
pets: {
type: 'array',
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
ajv.addKeyword('test', {
compile(sch, parentSchema) {
console.log(sch, parentSchema)
return () => true
}
// validate(schema, data) {
// console.log(schema, data)
// return true;
// }
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
image.png
compile可以根据相应的配置返回对应的函数。
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
test: true,
},
age: {
type: "number"
},
pets: {
type: 'array',
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
ajv.addKeyword('test', {
compile(sch, parentSchema) {
console.log(sch, parentSchema)
return () => true
},
metaSchema: {
type: 'boolean',
}
// validate(schema, data) {
// console.log(schema, data)
// return true;
// }
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
metaSchema值类型的限制检测。
image.png
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
const schema = {
type: 'object',
properties: {
name: {
type: "string",
test: true,
},
age: {
type: "number"
},
pets: {
type: 'array',
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
ajv.addKeyword('test', {
// compile(sch, parentSchema) {
// console.log(sch, parentSchema)
// return () => true
// },
// metaSchema: {
// type: 'boolean',
// },
macro(schema, parentSchema) {
return {
minLength: 10
}
}
// validate(schema, data) {
// console.log(schema, data)
// return true;
// }
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) console.log(validate.errors)
image.png
macro:相当于一个关键字申明了多个系统的schema。
错误信息语言改成中文
首先安装:
npm install ajv-i18n -S
image.png
const Ajv = require('ajv')
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
var localize = require('ajv-i18n')
const schema = {
type: 'object',
properties: {
name: {
type: "string",
test: true,
},
age: {
type: "number"
},
pets: {
type: 'array',
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
ajv.addKeyword('test', {
// compile(sch, parentSchema) {
// console.log(sch, parentSchema)
// return () => true
// },
// metaSchema: {
// type: 'boolean',
// },
macro(schema, parentSchema) {
return {
minLength: 10
}
}
// validate(schema, data) {
// console.log(schema, data)
// return true;
// }
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) {
localize.zh(validate.errors);
console.log(validate.errors)
}
image.png
自定义报错信息:
validate: function fun(schema, data) {
// console.log(schema, data)
fun.errors = [{
instancePath: '/name',
schemaPath: '#/properties/name/test',
keyword: 'test',
params: {},
message: '总是校验不通过的'
}]
return false;
}
自定义校验结果不通过时的报错信息自定义
安装:
npm install ajv-errors -S
使用:先包装一下使用对象:
const ajv = new Ajv({
allErrors: true
})
require('ajv-errors')(ajv)
完整demo:
const Ajv = require('ajv')
const ajv = new Ajv({
allErrors: true,
jsonPointers: true
}) // options can be passed, e.g. {allErrors: true}
var localize = require('ajv-i18n')
const schema = {
type: 'object',
properties: {
name: {
type: "string",
// test: true,
errorMessage: "这是不对的",
minLength: 10
},
age: {
type: "number"
},
pets: {
type: 'array',
},
isWorker: {
type: 'boolean'
}
},
required: ['name', 'age']
}
require('ajv-errors')(ajv)
ajv.addKeyword('test', {
// compile(sch, parentSchema) {
// console.log(sch, parentSchema)
// return () => true
// },
// metaSchema: {
// type: 'boolean',
// },
macro(schema, parentSchema) {
return {
minLength: 10
}
},
validate: function fun(schema, data) {
// console.log(schema, data)
fun.errors = [{
instancePath: '/name',
schemaPath: '#/properties/name/test',
keyword: 'test',
params: {},
message: '总是校验不通过的'
}]
return false;
}
})
//生成schema校验规则
const validate = ajv.compile(schema)
const data = {
name: 'jokcy',
age: 18,
pets: ['mimi', 'wangcai'],
isWorker: true
}
// 校验数据是否符合规则
const valid = validate(data)
if (!valid) {
localize.zh(validate.errors);
console.log(validate.errors)
}
不同的对象传递不同的报错信息:
const schema = {
type: "object",
required: ["foo", "bar"],
properties: {
foo: {type: "integer"},
bar: {type: "string"},
},
errorMessage: {
type: "should be an object", // will not replace internal "type" error for the property "foo"
required: {
foo: 'should have an integer property "foo"',
bar: 'should have a string property "bar"',
},
},
}
类库实现
考虑将来的扩展性、可以自定义的能力、非标准的功能如何方便的去编写。
确定组件的接口和定义
开发入口组件的实现
发开基渲染的实现
接口,即props。
props涉及包括但不限于:schema
、value
、locale
(语言包)、onChange
、uiSchema
(界面交互schema)
定义如下:
### API 设计
```jsx
<JsonSchemaForm
schema={schema}
value={value}
onChange={handleChange}
locale={locale}
contextRef={someRef}
uiSchema={uiSchema}
/>
schema
json schema 对象,用来定义数据,同事定义表单的依据
value
表单的数据结果,可以从外部改变 value,在表单被编辑的时候,会通过 onChange 透出 value
注意:因为 vue 使用可变数据,如果每次变化都去改变 value
的对象地址,会导致重新渲染,性能降低。
从实践中看,穿肚对象在内部修改其 field
的值不会有什么副作用。也就是说,如果value
是一个对象,从JsonSchemaForm
内部修改的值并不会修改 value
本身,但仍需要去触发onChange
,因为可能在表单变化之后,使用者需要进行一些操作
onChage
在表单值有任何变化时触发回调方法,并把新的值返回
locale
语言,使用ajv-i18n
指定错误信息使用的语言
contextRef
需要传入一个 vue3 的Ref
对象,会在对象挂载doValidate
方法,可以通过如下实现表单主动校验:
const yourRef=ref({})
onMounted(()=>{
yourRef.value.doValidate()
})
<JsonSchemaForm contextRef={yourRef}/>
vue2 的实现:
<Comp ref="comp"/>
this.$ref.comp.xxx()
uiSchema
对表单的展现进行一些定制,类型如下:
export interface VueJsonSchemaConfig{
title?:string
descrription?:string
component?:string
additionProps?:{
[key:string]:any
}
withFormItem?:boolean
widget?:'checkbox'|'textarea'|'select'|'radio'|'range'|string
items?:UISchema|UISchema[]
}
export interface UISchema extends VueJsonSchemaConfig{
properties?:
[property:string]:UISchema
}
网友评论