SchemaForm 表单
用一份 schema 描述表单:字段、布局、校验、联动、分组、数组和弹窗。基于 TanStack Form。
参照 vben 的 useVbenForm 设计。useSchemaForm 返回表单的 api,<SchemaForm form={form} /> 负责渲染;schema 只在创建时读一次,之后的变化(接口返回的选项、翻译后的文字)通过 dependencies、updateSchema 或 setState({ schema }) 传进去。
安装
pnpm dlx shadcn@latest add https://docs.linasan.cn/r/schema-form.json第一次装本站的组件前先在项目里执行一次 shadcn init,详见 安装。
弹窗表单和列表页筛选区是单独的两项:schema-form-dialog、schema-search-form,安装命令把上面的名字换掉即可。
用法
import { SchemaForm } from '@/components/schema-form/schema-form';
import { useSchemaForm } from '@/components/schema-form/use-schema-form';
const form = useSchemaForm({
layout: 'horizontal',
wrapperClass: 'grid-cols-1 md:grid-cols-2',
handleSubmit: (values) => save(values),
schema: [
{ component: 'Input', fieldName: 'name', label: '姓名', rules: 'required' },
{ component: 'Select', fieldName: 'status', label: '状态', componentProps: { options } },
],
});
<SchemaForm form={form} />示例
校验
rules 可以是 'required'、'selectRequired'、函数(可以 async)、Standard Schema(Zod、Valibot、Effect Schema……),或它们的数组(依次校验,第一条失败的显示)。
联动
dependencies 在 triggerFields 变化时重算:if(卸载,值不提交)/ show(只隐藏)/ disabled / required / rules / componentProps,trigger 用来改别的字段。
分组与数组
type: 'group' 是一组字段(可折叠,有自己的栅格);type: 'array' 是可增删的多行,子字段的联动拿得到本行的值(row)。
弹窗表单
SchemaFormDialog 把表单放进 Dialog:底部按钮调用 form.submit(),提交中不可关闭,有修改时关闭前确认。
内置控件
component 写名字,componentProps 传给控件:
| 名字 | 控件 |
|---|---|
Input / InputPassword / Textarea | Input、PasswordInput、Textarea(clearable、prefix、showCount) |
InputNumber | NumberInput |
Select / Combobox / ApiSelect | Select、Combobox、选项来自接口的 Combobox(api、resultField、labelField、valueField、remote) |
RadioGroup / CheckboxGroup / Checkbox | 单选(variant: 'button' | 'card')、多选组、单个勾选 |
Switch / Segmented / Slider | 开关、分段控件、滑块 |
DatePicker / DateRangePicker | 日期选择 |
TagInput / ChoiceChips | 标签输入、选择标签 |
IconPicker / IconSelect | 图标选择 |
TreeCheck | 权限树 |
NewPassword | 新密码 + 强度条 + 泄露提示 |
PinInput | 验证码 |
自己的控件用 registerFormComponent('UserPicker', { render: UserPicker }) 注册,或直接把组件传给 component。控件拿到 value、onChange、onBlur、id、aria-invalid 等(FieldControlProps)。
表单 api
ApiSelect 的选项来自接口(可远程搜索);下面的按钮演示 useSchemaForm 返回的 api。
| 方法 | 作用 |
|---|---|
getValues() / getRawValues() | 提交用的值(去掉 if 为假的字段,经过 codec.encode)/ 原始值 |
setValues(v) / setFieldValue(name, v) | 合并设置值 |
reset(v?) | 恢复初始值,传值则以它为新的初始值 |
validate() / validateField(name) | 校验并显示错误 |
setFieldError(name, msg) / clearValidation() | 手动设置错误(如服务端返回的)/ 清空 |
submit() | 校验并调用 handleSubmit,返回提交值,不通过返回 undefined |
updateSchema(patches) / appendSchema / removeSchemaByFields | 按 fieldName 改 schema |
setState(patch) | 改布局、按钮、禁用等选项 |
merge(other).submitAll() | 多个表单一起校验提交(分步表单) |
useSchemaFormValues(form)、useSchemaFormStatus(form)(submitting、dirty)在组件里订阅表单状态。
分步表单
每一步一个表单,最后 first.merge(second).submitAll() 一起校验、合并成一个对象。
- 账号
- 公司
列表页筛选区
列表页的筛选用 SchemaSearchForm:受控(values 是页面的筛选草稿),改条件 300ms 后自动搜索,默认收成一行。
改条件 300ms 后自动搜索
属性
属性
类型