跳转到内容

表单 form

数据录入组件。三层同源:无头内核给出解剖与状态机,Vue 组件与自定义元素只是它的两层外壳,行为完全一致。

示例

基础用法

默认只在提交时整表校验:过了发 submit,没过发 invalid、摘要显形并把焦点送到第一个出错的字段

校验时机

blur 与 change 两种模式下 validate 仍整表跑(校验可能带跨字段规则),但只把当事字段那一条写回错误表

受控值表

传了 values 就由宿主说了算:组件内部不再落值,只发 update:values;页面别处也能直接改这张表

宿主持有的值:{"host":"127.0.0.1","port":"5173"}

禁用与只读

disabled 把提交、重置、写值三条路一起封死;read-only 只封写值与重置,提交照发

整表禁用

只读:能提交,改不动

已提交:(还没提交过)

动态字段

字段容器随数组增删,值表的键跟着字段名走;校验只遍历当下这几行,删掉的行不再参与

已提交:(还没提交过)

异步校验

核验结果落在宿主自己的表里,validate 同步读它;核验回来直接写受控错误表,提交这一路照样拦得住

改动后自动核验,占用的名字会被挡下

已提交:(还没提交过)

跨字段规则与手动入口

validate 拿到的是整张值表,可以写两个字段互相约束的规则;插槽里的 setFieldError 与 clearErrors 随时能单独动一条

提醒但不拦下

可疑的值只在描述里提醒一句,不写进错误表:控件的 aria-invalid 仍是 false,提交照样放行

这是个人邮箱,同事之间通常填公司邮箱

已提交:(还没提交过)

分步校验

校验函数每次提交现读一次:闭住当前这一步,提交就只校验这一步的字段;存草稿走的是普通按钮,一条规则都不跑

第 1 步 · 联系人

草稿:(还没存过)

嵌套模型与路径字段名

字段名直接写成路径,值仍住在宿主自己的嵌套对象里:表单只管错误、id 与摘要跳转,提交时不用把扁平表折回去

已提交:(还没提交过)

重置回默认值

复合控件的值攥在组件里,原生重置只还原原生控件——它们各自认这条事件,一起回到 defaultValue

产物

自定义元素<xh-form>
Vue 组件XhFormErrorSummary XhFormErrorSummaryItem XhFormFieldGroup XhFormResetTrigger XhFormRoot XhFormSubmitTrigger
组合式函数useForm
状态机formMachine
皮肤@xihan-ui/styles/form.css

解剖

部件名即 data-part 属性值,也是皮肤的选择器。加粗的是必备部件,不渲染它组件不工作(Web Components 适配器会在诊断通道上报 wc.missing-part)。

data-scope="form"root · field-group · error-summary · error-summary-item · submit-trigger · reset-trigger

Props

属性类型必填说明
valuesFormValues受控值表;给定即受控:cell 直读 prop,写只发 onValuesChange 不落内部值。
defaultValuesFormValues非受控初值,同时也是 reset 的落点。
errorsFormErrorPatch受控错误表;给定即受控。空串会被清理掉(空串不是一条错误)。
defaultErrorsFormErrorPatch
validate(values: FormValues) => FormErrorPatch校验函数。同步返回「字段名 → 错误文案」,没错的字段给空串或干脆不写。 不给这个函数即没有校验,提交时沿用当下的错误表。
validateOnFormValidateOn校验时机,默认 submit。
disabledboolean整个表单禁用:提交、重置、写值一概不发生,两颗按钮带原生 disabled。
readOnlyboolean只读:写值与重置不发生,但仍可提交。
onValuesChange(details: FormValuesChangeDetails) => void值表变化意图回调;受控时是唯一出口,非受控随内部写入一并通知。
onErrorsChange(details: FormErrorsChangeDetails) => void错误表变化意图回调;受控时是唯一出口。
onSubmit(details: FormSubmitDetails) => void校验通过才调。
onInvalid(details: FormInvalidDetails) => void校验不通过时调,带上拦下来的整张错误表。

状态机

状态idle · invalid

事件SUBMIT · RESET · VALIDATION.PASS · VALIDATION.FAIL · FIELD.SET · FIELD.BLUR · ERROR.SET · ERRORS.CLEAR · ERROR.FOCUS

判据isEnabled · isEditable

connect API

useForm 产出的对象。getXxxProps() 铺到对应部件的宿主元素上,其余是可读状态与操作入口。

成员类型说明
valuesFormValues当下的值表。
errorsFormErrors当下的错误表(已清理)。
errorNamesstring[]出错的字段名,插入顺序。
errorCountnumber
invalidboolean错误表非空。与"提交失败过"无关,挂载时作者塞进来的错误也算。
submitFailedboolean上一次提交被拦下了:错误摘要据此显形。
disabledboolean
readOnlyboolean
validateOnFormValidateOn
getFieldId(name: string) => string字段容器的 DOM id;错误摘要的链接指向它。
getFieldValue(name: string) => unknown
getFieldError(name: string) => string | undefined该字段此刻的错误文案;没错时为 undefined。
isFieldInvalid(name: string) => boolean
setFieldValue(name: string, value: unknown) => void写一个字段的值;禁用或只读时不动。
setFieldError(name: string, message?: string) => void写一个字段的错误;不给文案(或给空串)即清掉这一条。
clearErrors() => void
submit() => void走完整的校验与提交流程,与用户按提交键同一条路。
reset() => void值与错误都回到初始;禁用或只读时不动。
getRootProps() => T['element']
getFieldGroupProps(props: FormFieldGroupProps) => T['element']
getErrorSummaryProps() => T['element']
getErrorSummaryItemProps(props: FormErrorSummaryItemProps) => T['element']
getSubmitTriggerProps() => T['button']
getResetTriggerProps() => T['button']

键盘

规格出处:W3C APG

无键盘交互(不接收焦点,或焦点行为完全由原生元素提供)。

Released under The MIT License