【VUE+TS】2.0 JSON SCHEMA

JSON SCHEMA

有官网,开源的草案。JSON SCHEMA官网
本项目最终产出的项目就是基于JSON SCHEMA实现,目的就是表单的自动化装配。
JSON SCHEMA:用json定义数据,并校验数据。
一些名称的定义最好参考官网的建议。

AJV

AJV 官网
一个JSON SCHEMA的校验器。
AJV最简单的用法(其实也没有别的用法)

image.png

核心功能就是校验一份数据是不是我们想要的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涉及包括但不限于:schemavaluelocale(语言包)、onChangeuiSchema(界面交互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
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值