突发奇想,还未实践,在Vben5的Antd模式下,将表单从「JS 配置化」改写成「模板可视化」形式(豆包版)

在 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>

以下是完整的「模板可视化」改写示例,保留原功能但结构更清晰:

改写思路

  1. 放弃 JS 中的 schema 配置 :将每个表单项(如 Input、Select、DatePicker)直接写在模板的 <Form> 标签内。
  2. FormItem 包裹表单项 :通过 FormItemname(对应原 fieldName)、labelrules 等属性绑定字段信息和校验规则。
  3. 保留 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>

关键改动说明

  1. 模板结构更直观

    每个表单项都以「FormItem 包裹组件」的形式写在模板中,字段名(name)、标签(label)、校验规则(rules)一目了然,无需在 JS 中找 schema 配置。

  2. 保留原功能不变

    • 校验规则:通过 FormItemrules 属性直接绑定(如邮箱校验、必填校验),逻辑和原 schema 一致。
    • 默认值:用 FormIteminitial-value 替代原 defaultValue
    • 布局和提交:layout 用变量控制,提交函数 onSubmit 完全复用。
  3. 组件引入更清晰

    直接从 #/adapter/antd 导入需要的组件(如 SelectDatePicker),和模板中的使用一一对应,降低理解成本。

优势

  • 可视化强 :表单项的层级、顺序、组件类型在模板中直接可见,便于快速修改(比如调整表单项顺序,只需拖动模板中的 FormItem)。
  • 调试方便 :若某个表单项有问题,直接定位到模板中的对应位置,无需在 JS 的 schema 数组中查找。
  • 学习成本低:符合 Vue 开发者"模板写结构、JS 写逻辑"的习惯,新接手的同事更容易上手。

如果需要添加更复杂的逻辑(如动态表单项、联动校验),也只需在模板中通过 v-ifv-for 或组件事件实现,比在 JS 配置中写 renderwatch 更直观。

相关推荐
悟能不能悟6 小时前
js闭包问题
开发语言·前端·javascript
秋秋_瑶瑶7 小时前
vue-amap组件呈现的效果图如何截图
前端·javascript·vue-amap
LFly_ice8 小时前
学习React-9-useSyncExternalStore
javascript·学习·react.js
gnip8 小时前
js上下文
前端·javascript
中草药z8 小时前
【Stream API】高效简化集合处理
java·前端·javascript·stream·parallelstream·并行流
不知名raver(学python版)8 小时前
npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR!
前端·npm·node.js
醉方休8 小时前
React中使用DDD(领域驱动设计)
前端·react.js·前端框架
excel9 小时前
📖 小说网站的预导航实战:link 预加载 + fetch + 前进后退全支持
前端