- 我查看了市面上所有的表单库,都有一个致命的缺点,定义多次才能实现表单
- 比如,像下面的代码(伪代码)
interface Test {
firstName: string;
}
const form = useForm<Test>({
defaultValues: {
firstName: "default",
},
onSubmit: async ({ value }) => {
console.log(value);
},
});
<form.Field
name="firstName"
//...
/>
- 众所周知,实现的越多,那么未来出现错误的概率越大
- 像上面的场景,如果我们想修改
firstName为name,那么至少需要修改三次,这极大的增加了代码的不稳定性 - 所以我实现了一个表单库皮影.仅用一次定义,实现了以上所有逻辑
v.object({ firstName: v.optional(v.string(), "default") });
皮影是如何实现上面的逻辑的?
- 首先感谢valibot,上面的代码其实就是一个简单的
schema定义 - 皮影实现了一个遍历器,收集相关元数据
- 然后将元数据转换为组件和表单配置
- 使其可以在任何前端框架上使用
定义是固定的,那么怎么实现布局呢?
- 皮影实现了布局移动,通过
layout方法可以将任何控件移动到可以存在子级的schema中
v.intersect([
v.pipe(v.object({}), setAlias("scope1")),
v.object({
key1: v.pipe(
v.object({
test1: v.pipe(v.optional(v.string(), "value1"), layout({ keyPath: ["#", "@scope1"] })),
}),
),
}),
]);
- 也就是说,定义虽然是固定的,但是在视图中是可以自由决定位置的,做到了定义与视图位置分离
- 关于
object的字段顺序,则可以参照MDN
如何进行更加高级的布局?
- 我们都知道,有时候不仅仅要显示字段,可能还需要更多额外的功能
- 比如控件的标签,验证,悬停提示,则可以通过包装器实现
v.pipe(v.number(), v.title("k2-label"), setWrappers(["label"]));
- 而如果要修改空间组的样式,则可以自定义组件
虽然包装器也可以用于控件组,但是直接自定义会更方便些
v.pipe(
v.object({
k1: v.pipe(v.string(), v.title("k1-label"), setWrappers(["label"])),
k2: v.pipe(v.number(), v.title("k2-label"), v.minValue(10), setWrappers(["label", "validator"])),
}),
setComponent("fieldset"),
);
如何自定义包装器/组件?
- 上面的一些代码,我并没有说是应用于哪个前端框架,因为它们都是通用的
- 而包装器和组件的定义却是每个框架各有不同的方法
- 大家可以查看快速开始查找自己所使用的框架的定义方法.目前已支持
Angular,Vue,React,如果您还需要其他框架兼容,欢迎反馈
现在是否可以使用?
- 皮影表单在正式开源之前,已经经过半年以上的内部使用,绝大部分功能已经经过严格的测试.代码覆盖率达到了95%以上;完全可以应用于生成环境
- 皮影表单实现了很多的用例演示及对市面上的主流库的用例做了等价的实现,方便大家迁移
- ngx-formly 用例实现
- vee-validate 用例实现
- formik 用例实现
- react-hook-form 用例实现
- react-tanstack用例实现
项目地址
联系我
- 如果您有任何意见或建议,欢迎联系我
wszgrcy@gmail.com