在 Vben5 的 Antd 模式下,完全可以将表单从「JS 配置化」改写成「模板可视化」形式,把表单项直接写在 Vue 模板中,更直观且符合传统 Vue 开发习惯。
以下是官网的「JS 配置化」示例:
typescript
<script lang="ts" setup>
import { message } from 'ant-design-vue';
import { useVbenForm, z } from '#/adapter/form';
const [Form] = useVbenForm({
// 所有表单项共用,可单独在表单内覆盖
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
// 提交函数
handleSubmit: onSubmit,
// 垂直布局,label和input在不同行,值为vertical
// 水平布局,label和input在同一行
scrollToFirstError: true,
layout: 'horizontal',
schema: [
{
// 组件需要在 #/adapter.ts内注册,并加上类型
component: 'Input',
// 对应组件的参数
componentProps: {
placeholder: '请输入',
},
// 字段名
fieldName: 'field1',
// 界面显示的label
label: '字段1',
rules: 'required',
},
{
component: 'Input',
componentProps: {
placeholder: '请输入',
},
defaultValue: '默认值',
fieldName: 'field2',
label: '默认值(必填)',
rules: 'required',
},
{
component: 'Input',
componentProps: {
placeholder: '请输入',
},
fieldName: 'field3',
label: '默认值(非必填)',
rules: z.string().default('默认值').optional(),
},
{
component: 'Input',
componentProps: {
placeholder: '请输入',
},
fieldName: 'field31',
label: '自定义信息',
rules: z.string().min(1, { message: '最少输入1个字符' }),
},
{
component: 'Input',
// 对应组件的参数
componentProps: {
placeholder: '请输入',
},
// 字段名
fieldName: 'field4',
// 界面显示的label
label: '邮箱',
rules: z.string().email('请输入正确的邮箱'),
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入',
},
fieldName: 'number',
label: '数字',
rules: 'required',
},
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
placeholder: '请选择',
showSearch: true,
},
defaultValue: undefined,
fieldName: 'options',
label: '下拉选',
rules: 'selectRequired',
},
{
component: 'RadioGroup',
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
fieldName: 'radioGroup',
label: '单选组',
rules: 'selectRequired',
},
{
component: 'CheckboxGroup',
componentProps: {
name: 'cname',
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
fieldName: 'checkboxGroup',
label: '多选组',
rules: 'selectRequired',
},
{
component: 'Checkbox',
fieldName: 'checkbox',
label: '',
renderComponentContent: () => {
return {
default: () => ['我已阅读并同意'],
};
},
rules: 'selectRequired',
},
{
component: 'DatePicker',
defaultValue: undefined,
fieldName: 'datePicker',
label: '日期选择框',
rules: 'selectRequired',
},
{
component: 'RangePicker',
defaultValue: undefined,
fieldName: 'rangePicker',
label: '区间选择框',
rules: 'selectRequired',
},
{
component: 'InputPassword',
componentProps: {
placeholder: '请输入',
},
fieldName: 'password',
label: '密码',
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
</script>
<template>
<Form />
</template>
以下是完整的「模板可视化」改写示例,保留原功能但结构更清晰:
改写思路
- 放弃 JS 中的
schema
配置 :将每个表单项(如 Input、Select、DatePicker)直接写在模板的<Form>
标签内。 - 用
FormItem
包裹表单项 :通过FormItem
的name
(对应原fieldName
)、label
、rules
等属性绑定字段信息和校验规则。 - 保留
useVbenForm
核心能力:仍用该钩子获取表单实例,实现提交、校验等功能,确保和原逻辑一致。
完整改写代码
typescript
<template>
<!-- 表单容器:绑定表单实例,配置布局和提交逻辑 -->
<Form
:form="formInstance"
:layout="formLayout"
:scroll-to-first-error="true"
@submit="onSubmit"
class="grid-cols-1"
>
<!-- 1. 字段1:Input(必填) -->
<FormItem
name="field1"
label="字段1"
:rules="[{ required: true, message: '请输入字段1' }]"
>
<Input
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 2. 字段2:Input(必填 + 默认值) -->
<FormItem
name="field2"
label="默认值(必填)"
:rules="[{ required: true, message: '请输入字段2' }]"
initial-value="默认值" <!-- 对应原 defaultValue -->
>
<Input
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 3. 字段3:Input(非必填 + 默认值) -->
<FormItem
name="field3"
label="默认值(非必填)"
initial-value="默认值"
>
<Input
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 4. 字段31:Input(自定义校验:最少1个字符) -->
<FormItem
name="field31"
label="自定义信息"
:rules="[{ required: true, min: 1, message: '最少输入1个字符' }]"
>
<Input
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 5. 字段4:邮箱Input(邮箱格式校验) -->
<FormItem
name="field4"
label="邮箱"
:rules="[{ required: true, type: 'email', message: '请输入正确的邮箱' }]"
>
<Input
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 6. 数字输入:InputNumber(必填) -->
<FormItem
name="number"
label="数字"
:rules="[{ required: true, message: '请输入数字' }]"
>
<InputNumber
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 7. 下拉选择:Select(必填) -->
<FormItem
name="options"
label="下拉选"
:rules="[{ required: true, message: '请选择选项' }]"
>
<Select
allow-clear
filter-option
placeholder="请选择"
show-search
class="w-full"
>
<Select.Option value="1">选项1</Select.Option>
<Select.Option value="2">选项2</Select.Option>
</Select>
</FormItem>
<!-- 8. 单选组:RadioGroup(必填) -->
<FormItem
name="radioGroup"
label="单选组"
:rules="[{ required: true, message: '请选择一项' }]"
>
<RadioGroup class="w-full">
<Radio value="1">选项1</Radio>
<Radio value="2">选项2</Radio>
</RadioGroup>
</FormItem>
<!-- 9. 多选组:CheckboxGroup(必填) -->
<FormItem
name="checkboxGroup"
label="多选组"
:rules="[{ required: true, message: '请至少选择一项' }]"
>
<CheckboxGroup name="cname" class="w-full">
<Checkbox value="1">选项1</Checkbox>
<Checkbox value="2">选项2</Checkbox>
</CheckboxGroup>
</FormItem>
<!-- 10. 单独复选框:Checkbox(必填:同意协议) -->
<FormItem
name="checkbox"
label="" <!-- 空label,避免多余占位 -->
:rules="[{ required: true, message: '请勾选同意协议' }]"
>
<Checkbox class="w-full">我已阅读并同意</Checkbox>
</FormItem>
<!-- 11. 日期选择:DatePicker(必填) -->
<FormItem
name="datePicker"
label="日期选择框"
:rules="[{ required: true, message: '请选择日期' }]"
>
<DatePicker class="w-full" />
</FormItem>
<!-- 12. 区间选择:RangePicker(必填) -->
<FormItem
name="rangePicker"
label="区间选择框"
:rules="[{ required: true, message: '请选择区间' }]"
>
<RangePicker class="w-full" />
</FormItem>
<!-- 13. 密码输入:InputPassword(必填) -->
<FormItem
name="password"
label="密码"
:rules="[{ required: true, message: '请输入密码' }]"
>
<InputPassword
placeholder="请输入"
class="w-full"
/>
</FormItem>
<!-- 提交按钮 -->
<FormItem>
<Button type="primary" html-type="submit">提交表单</Button>
</FormItem>
</Form>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { message } from 'ant-design-vue';
// 导入 Vben 表单核心组件和钩子
import { useVbenForm } from '#/adapter/form';
// 导入 Antd 基础组件(Vben 适配版)
import {
Form,
FormItem,
Input,
InputNumber,
Select,
RadioGroup,
Radio,
CheckboxGroup,
Checkbox,
DatePicker,
RangePicker,
InputPassword,
Button
} from '#/adapter/component';
// 1. 初始化表单:获取表单实例(替代原 schema 配置)
const { form: formInstance } = useVbenForm();
// 2. 表单布局(对应原 layout: 'horizontal')
const formLayout = ref('horizontal');
// 3. 提交函数(和原逻辑完全一致)
const onSubmit = (values: Record<string, any>) => {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
};
</script>
关键改动说明
-
模板结构更直观
每个表单项都以「
FormItem
包裹组件」的形式写在模板中,字段名(name
)、标签(label
)、校验规则(rules
)一目了然,无需在 JS 中找schema
配置。 -
保留原功能不变
- 校验规则:通过
FormItem
的rules
属性直接绑定(如邮箱校验、必填校验),逻辑和原schema
一致。 - 默认值:用
FormItem
的initial-value
替代原defaultValue
。 - 布局和提交:
layout
用变量控制,提交函数onSubmit
完全复用。
- 校验规则:通过
-
组件引入更清晰
直接从
#/adapter/antd
导入需要的组件(如Select
、DatePicker
),和模板中的使用一一对应,降低理解成本。
优势
- 可视化强 :表单项的层级、顺序、组件类型在模板中直接可见,便于快速修改(比如调整表单项顺序,只需拖动模板中的
FormItem
)。 - 调试方便 :若某个表单项有问题,直接定位到模板中的对应位置,无需在 JS 的
schema
数组中查找。 - 学习成本低:符合 Vue 开发者"模板写结构、JS 写逻辑"的习惯,新接手的同事更容易上手。
如果需要添加更复杂的逻辑(如动态表单项、联动校验),也只需在模板中通过 v-if
、v-for
或组件事件实现,比在 JS 配置中写 render
或 watch
更直观。