fix(@vben-core/form-ui)!: group field slot component props (#8215)

* refactor(@vben-core/form-ui)!: group field slot component props

* fix(@vben-core/form-ui): stabilize grouped field slot bindings

Resolve function-based common component props with field context.

Preserve internal model and event bindings when custom field slots spread componentProps.

Add regression coverage for array contexts, disabled precedence, and stale binding isolation.

* feat(@vben/vite-config): warn about field slot migration

Print the temporary field-slot migration warning when the development server starts.

Inject the same message into the browser console and keep the plugin serve-only.

* docs(@vben/docs): document field slot migration

Place the breaking field-slot notice at the start of both form documents.

Explain old and new bindings, development warnings, and planned notice removal.

* feat(@vben/playground): extend custom form example

Add a switchable input and select field to demonstrate schema component updates.

Update the composite phone field to emit new tuple values so validation observes changes.
This commit is contained in:
dream-weave
2026-07-31 18:13:49 +08:00
committed by GitHub
parent 32495e40b2
commit 9f5b1cd9fb
19 changed files with 498 additions and 50 deletions

View File

@@ -4,6 +4,24 @@ outline: deep
# Vben Form 表单
::: warning 字段插槽破坏性变更
字段命名 slot 的控件绑定已统一收拢到 `slotProps.componentProps`。旧写法会把 `field``formApi``values` 等表单元数据一并传给实际控件,可能产生无效属性和 Vue 运行时警告。
```vue
<!-- 旧写法 -->
<Input v-bind="slotProps" />
<!-- 新写法 -->
<Input v-bind="slotProps.componentProps" />
```
请将所有字段 slot 的 `v-bind="slotProps"` 迁移为 `v-bind="slotProps.componentProps"`。根级的 `field``componentField``modelValue``name``disabled``isInValid``values``formApi` 仍可用于模板逻辑,但不会再自动传入实际控件。
当前版本启动 Vben 应用或 Playground 开发服务器时会在终端输出一次迁移警告,页面加载时浏览器控制台也会提示。该提示不会进入生产构建,并计划在下个版本移除。
:::
框架提供的表单组件,可适配 `Element Plus``Ant Design Vue``Naive UI` 等框架。
> 如果文档内没有参数说明,可以尝试在在线示例内寻找
@@ -385,7 +403,9 @@ async function fillForm() {
</template>
```
字段命名插槽提供 `field``componentField``modelValue``name``disabled``isInValid``values``formApi`。默认插槽提供 `shapes``values``formApi``reset-before``submit-before``expand-before``expand-after` 提供 `values``formApi`未声明 `TValues` 时仍兼容任意字段名,但 slot props 会回退为宽泛类型。
字段命名插槽提供完整控件绑定 `componentProps`,以及 `field``componentField``modelValue``name``disabled``isInValid``values``formApi`。默认插槽提供 `shapes``values``formApi``reset-before``submit-before``expand-before``expand-after` 提供 `values``formApi`
建议为表单声明没有字符串索引签名的精确接口,使每个字段插槽都能推导自己的值类型。使用 `Record<string, unknown>` 等宽泛类型时slot props 仍保持完整结构,不再整体退化为 `any`,但字段值只能推导为索引值类型。
### FormApi
@@ -746,6 +766,18 @@ import { z } from '#/adapter/form';
::: tip 字段插槽
除了以上内置插槽之外,`schema`属性中每个字段的`fieldName`都可以作为插槽名称这些字段插槽的优先级高于`component`定义的组件。也就是说,当提供了与`fieldName`同名的插槽时,这些插槽的内容将会作为这些字段的组件,此时`component`的值将会被忽略。
除了以上内置插槽之外,`schema` 属性中每个字段的 `fieldName` 都可以作为插槽名称这些字段插槽的优先级高于 `component` 定义的组件。
字段 slot 的控件绑定统一收拢在 `componentProps` 中,其中包含模型值、对应的 `update:*` 事件、schema/common/dependencies props 和 disabled 状态:
```vue
<Form>
<template #fieldName="slotProps">
<Input v-bind="slotProps.componentProps" />
</template>
</Form>
```
`field``componentField``modelValue``name``disabled``isInValid``values``formApi` 保留在 slot 根级,供模板逻辑使用,不会自动传入实际控件。
:::

View File

@@ -62,7 +62,7 @@ function onSubmit(values: Record<string, any>) {
<template>
<Form>
<template #field3="slotProps">
<Input placeholder="请输入" v-bind="slotProps" />
<Input placeholder="请输入" v-bind="slotProps.componentProps" />
</template>
</Form>
</template>

View File

@@ -4,6 +4,24 @@ outline: deep
# Vben Form
::: warning Field Slot Breaking Change
Named field slot control bindings are now grouped under `slotProps.componentProps`. The old binding forwards form metadata such as `field`, `formApi`, and `values` to the rendered control, which can produce invalid attributes and Vue runtime warnings.
```vue
<!-- Old usage -->
<Input v-bind="slotProps" />
<!-- New usage -->
<Input v-bind="slotProps.componentProps" />
```
Migrate every field slot from `v-bind="slotProps"` to `v-bind="slotProps.componentProps"`. Root metadata remains available for template logic through `field`, `componentField`, `modelValue`, `name`, `disabled`, `isInValid`, `values`, and `formApi`, but it is no longer forwarded automatically to the rendered control.
In this release, starting a Vben application or Playground development server prints this migration warning in the terminal, and loading the page prints the same warning in the browser console. The warning is excluded from production builds and is planned for removal in the next release.
:::
`Vben Form` is the shared form abstraction used across different UI-library variants such as `Ant Design Vue`, `Element Plus`, `Naive UI`, and other adapters added inside this repository.
It uses [TanStack Form](https://tanstack.com/form/latest/docs/framework/vue/overview) internally for state and validation lifecycles, with [Zod 4](https://zod.dev/v4) schemas. Application code should continue using `useVbenForm`, `FormApi`, and the adapter layer instead of depending on the raw TanStack instance.
@@ -252,7 +270,23 @@ async function fillForm() {
</template>
```
Named field slots expose `field`, `componentField`, `modelValue`, `name`, `disabled`, `isInValid`, `values`, and `formApi`. The default slot exposes `shapes`, `values`, and `formApi`; action slots expose `values` and `formApi`. Forms without an explicit `TValues` remain compatible with arbitrary slot names and broad props.
Named field slots expose grouped control bindings through `componentProps`, together with `field`, `componentField`, `modelValue`, `name`, `disabled`, `isInValid`, `values`, and `formApi`. The default slot exposes `shapes`, `values`, and `formApi`; action slots expose `values` and `formApi`.
Use a precise form-value interface without a string index signature to infer each field value. A broad type such as `Record<string, unknown>` keeps the complete slot-prop structure instead of degrading the whole scope to `any`, but field values can only use the declared index value type.
## Field Slots
Control bindings are grouped under `componentProps`. It contains the model value, matching `update:*` event, schema/common/dependency props, and disabled state:
```vue
<Form>
<template #fieldName="slotProps">
<Input v-bind="slotProps.componentProps" />
</template>
</Form>
```
Root metadata remains available for template logic through `field`, `componentField`, `modelValue`, `name`, `disabled`, `isInValid`, `values`, and `formApi`; it is not forwarded automatically to the rendered control.
## Form Codec