「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
介绍
从DripForm的源码中可以看到两个子包drip-form-plugin-formats和drip-form-plugin-keywords,DripForm利用ajv提供动态表单的校验能力,当然ajv可能默认提供的能力并不能很好的满足需求,和大多数工具一样,开放了插槽式的体验,能够对原本处理代码的流程进行扩展,加入自定的formats和keywords等。在开发ajv的插件时,建议遵循如下规则:
- 插件所导出的函数需要满足第一个参数是ajv的实例
- 函数需要满足返回值也是一个ajv实例,便于链式调用
- 导出的函数能够接受一个可选的配置作为第二个参数
ajv插件雏形
就拿DripForm开发的format插件,增加了两个format,提供了对color和date-time格式的支持。我们可以很容易的从上面的规则中写出如下代码,根据ajv官网对自定义插件的描述,我们在使用typescript的同时,可以导入ajv的Plugin类型支持。
import type { Plugin, Options } from 'ajv/dist/2019';
const addFormat: Plugin<Options> = (ajv, options) => {
return ajv;
};
export default addFormat;
复制代码
ajv添加format的要求
当我们要校验ajv默认未提供的类型时,又该怎么办呢?比如说要添加对颜色属性的格式校验,支持rgba、rgb、十六进制的色值。这时候ajv实例为我们提供了一个addFormat的方法,用以自定义format类型,参照官方的要求 ajv.addFormat(name: string, format: Format): Ajv
,要提供一个Format类型的参数,name接受一个字符串,代表自定义的format类型名称。可以看到要么传递string、RegExp或者是一个范围值为boolean类型的函数,看到这里,就可以去实现自己的自定义类型了。
type Format =
| true // to ignore this format (and pass validation)
| string // will be converted to RegExp
| RegExp
| (data: string) => boolean
| Object // format definition (see below and in types)
复制代码
编写addFormat的参数对象
对于color类型,设想的是接受一个string类型的参数,返回各种颜色表达格式的正则测试结果。对于复杂的颜色正则表达式校验,我们可以先校验是否是rgb或rgba开头的,如果成功了,再去进行完整的正则校验,这样可以提升正则表达式的性能,减少不必要的消耗。
对于date-time类型,相对而言就简单了许多,直接传入正则表达式就可以了。
const dateTimeReg = /^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)$/i;
export default dateTimeReg;
复制代码
将format与雏形函数进行整合
我们可以看到,自定义的addFormat函数中,还有一个options对象,该参数接受一个formats数组,数组里面的format属性将会被添加到ajv实例中,但是遇到未定义的format属性会抛出异常,除非在初始化的时候,配置取消严格模式。得先判断传入的是否是一个数组,如果是数组的话,就会校验自定义的formats属性名是否在该配置的数组里面,如果不在则调用ajv.addFormat()像ajv的实例中添加format规则。options未定义的话,将默认添加已经定义好的format。
const addFormat: Plugin<Options> = (ajv, options) => {
if (Array.isArray(options)) {
Object.keys(formats)
.filter((item) => options.includes(item as formatsName))
.map((item) => {
ajv.addFormat(item, formats[itemas formatsName])
})
} else if (!options) {
Object.keys(formats).map((item) => {
ajv.addFormat(item, formats[item as formatsName])
})
}
return ajv
}
复制代码