我开源了一个表单库 - 元数据定义一次,即可渲染

31 阅读3分钟

code1.png

  • 我查看了市面上所有的表单库,都有一个致命的缺点,定义多次才能实现表单
  • 比如,像下面的代码(伪代码)
interface Test {
  firstName: string;
}
const form = useForm<Test>({
  defaultValues: {
    firstName: "default",
  },
  onSubmit: async ({ value }) => {
    console.log(value);
  },
});
<form.Field
  name="firstName"
  //...
/>
  • 众所周知,实现的越多,那么未来出现错误的概率越大
  • 像上面的场景,如果我们想修改firstNamename,那么至少需要修改三次,这极大的增加了代码的不稳定性
  • 所以我实现了一个表单库皮影.仅用一次定义,实现了以上所有逻辑
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,如果您还需要其他框架兼容,欢迎反馈

现在是否可以使用?

项目地址

联系我

  • 如果您有任何意见或建议,欢迎联系我wszgrcy@gmail.com