Skip to content

表单组件

表单组件提供了完整的表单解决方案,包含表单项、表单布局、模态框表单、页面表单、设置表单等组件。

导入

typescript
import {
  DuxFormItem,
  DuxFormLayout,
  DuxModalForm,
  DuxPageForm,
  DuxSettingForm
} from '@duxweb/dvha-pro'

组件总览

DVHA Pro 提供以下表单组件:

  • DuxFormItem - 表单项组件
  • DuxFormLayout - 表单布局组件
  • DuxModalForm - 模态框表单组件
  • DuxPageForm - 页面表单组件
  • DuxSettingForm - 设置表单组件

DuxFormItem 表单项

表单项组件,基于 vee-validate 提供验证功能的表单项包装器。

重要提示

DuxFormItem 需要配合 useExtendForm 使用才能实现验证功能。如果单独使用,验证规则不会生效。其他表单组件(DuxModalFormDuxPageFormDuxSettingForm)内部已集成了 useExtendForm,可以直接使用验证功能。

属性

属性名类型默认值说明
labelstring-标签文本
descriptionstring | VNode-描述信息(可以是字符串或 VNode)
pathstring-表单字段路径
labelPlacement'left' | 'top' | 'setting'-标签位置
labelWidthnumber-标签宽度
ruleRuleExpression-验证规则(vee-validate 规则表达式)
messagestring | Record<string, string>-错误信息

插槽

插槽名说明
default表单控件

配合 useExtendForm 使用

vue
<script setup>
import { useExtendForm } from '@duxweb/dvha-core'
import { DuxFormItem } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const formData = ref({
  username: '',
  email: ''
})

// 必须使用 useExtendForm 才能让验证生效
const { form, isLoading, onSubmit, onReset } = useExtendForm({
  path: '/api/users',
  action: 'create',
  form: formData
})
</script>

<template>
  <form @submit.prevent="onSubmit">
    <DuxFormItem
      label="用户名"
      path="username"
      rule="required|min:3"
      description="请输入至少3个字符的用户名"
    >
      <n-input v-model:value="form.username" placeholder="请输入用户名" />
    </DuxFormItem>

    <DuxFormItem
      label="邮箱"
      path="email"
      rule="required|email"
    >
      <n-input v-model:value="form.email" placeholder="请输入邮箱" />
    </DuxFormItem>

    <div class="mt-4">
      <n-button type="primary" attr-type="submit" :loading="isLoading">
        提交
      </n-button>
      <n-button class="ml-2" @click="onReset">
        重置
      </n-button>
    </div>
  </form>
</template>

单独使用(无验证)

如果不需要验证功能,可以单独使用 DuxFormItem 作为布局组件:

vue
<script setup>
import { DuxFormItem } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const userName = ref('')
</script>

<template>
  <DuxFormItem
    label="用户名"
    description="这只是一个布局组件,没有验证功能"
  >
    <n-input v-model:value="userName" placeholder="请输入用户名" />
  </DuxFormItem>
</template>

不同标签位置

vue
<template>
  <!-- 左侧标签(默认) -->
  <DuxFormItem label="姓名" path="name" label-placement="left">
    <n-input v-model:value="form.name" />
  </DuxFormItem>

  <!-- 顶部标签 -->
  <DuxFormItem label="邮箱" path="email" label-placement="top">
    <n-input v-model:value="form.email" />
  </DuxFormItem>

  <!-- 设置样式(右对齐) -->
  <DuxFormItem label="通知设置" path="notification" label-placement="setting">
    <n-switch v-model:value="form.notification" />
  </DuxFormItem>
</template>

DuxFormLayout 表单布局

表单布局组件,提供统一的表单布局和上下文配置。

属性

属性名类型默认值说明
labelPlacement'left' | 'top' | 'setting''left'标签位置
labelWidthnumber-标签宽度
inlinebooleanfalse是否内联显示
dividerbooleanfalse是否显示分割线

插槽

插槽名说明
default表单内容

基础用法

vue
<script setup>
import { DuxFormItem, DuxFormLayout } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const form = ref({
  name: '',
  email: '',
  phone: ''
})
</script>

<template>
  <DuxFormLayout label-placement="top" :label-width="80" divider>
    <DuxFormItem label="姓名" path="name" rule="required">
      <n-input v-model:value="form.name" />
    </DuxFormItem>

    <DuxFormItem label="邮箱" path="email" rule="required|email">
      <n-input v-model:value="form.email" />
    </DuxFormItem>

    <DuxFormItem label="手机" path="phone">
      <n-input v-model:value="form.phone" />
    </DuxFormItem>
  </DuxFormLayout>
</template>

DuxModalForm 模态框表单

模态框表单组件,集成了表单管理、验证和模态框显示。

属性

属性名类型默认值说明
idstring | number-编辑时的记录 ID
action'create' | 'edit'-操作类型
pathstring-API 路径
dataMaybeRef<Record<string, any>>-表单数据
onClose() => void-关闭回调
titlestring-标题(默认根据 action 自动设置)
onSuccess(data?: IDataProviderResponse) => void-成功回调
onError(error?: IDataProviderError) => void-错误回调

继承自 DuxFormLayout 的所有属性

插槽

插槽名说明
default表单内容

基础用法

vue
<script setup>
import { DuxFormItem, DuxModalForm } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const showModal = ref(false)
const formData = ref({
  name: '',
  email: ''
})

function handleSuccess(data) {
  console.log('保存成功:', data)
  showModal.value = false
}
</script>

<template>
  <DuxModalForm
    v-if="showModal"
    title="创建用户"
    path="/api/users"
    action="create"
    :data="formData"
    label-placement="top"
    @close="showModal = false"
    @success="handleSuccess"
  >
    <DuxFormItem label="姓名" path="name" rule="required">
      <n-input v-model:value="formData.name" />
    </DuxFormItem>

    <DuxFormItem label="邮箱" path="email" rule="required|email">
      <n-input v-model:value="formData.email" />
    </DuxFormItem>
  </DuxModalForm>
</template>

编辑模式

vue
<script setup>
const editData = ref({})

function handleEdit(id) {
  showModal.value = true
  editId.value = id
}
</script>

<template>
  <DuxModalForm
    v-if="showModal"
    :id="editId"
    title="编辑用户"
    path="/api/users"
    action="edit"
    :data="editData"
    @close="showModal = false"
    @success="handleSuccess"
  >
    <DuxFormItem label="姓名" path="name" rule="required">
      <n-input v-model:value="editData.name" />
    </DuxFormItem>

    <DuxFormItem label="邮箱" path="email" rule="required|email">
      <n-input v-model:value="editData.email" />
    </DuxFormItem>
  </DuxModalForm>
</template>

DuxPageForm 页面表单

页面表单组件,提供完整的页面级表单布局。

属性

属性名类型默认值说明
idstring | number-编辑时的记录 ID
action'create' | 'edit'-操作类型
pathstring-API 路径
dataMaybeRef<Record<string, any>>-表单数据
onSuccess(data?: IDataProviderResponse) => void-成功回调
onError(error?: IDataProviderError) => void-错误回调
size'small' | 'medium' | 'large''medium'表单尺寸

插槽

插槽名说明参数
default表单内容{ form, isLoading, onSubmit, onReset, isEdit }
actions自定义操作按钮{ form, isLoading, onSubmit, onReset, isEdit }

基础用法

vue
<script setup>
import { DuxFormItem, DuxFormLayout, DuxPageForm } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const formData = ref({
  name: '',
  email: '',
  description: ''
})

function handleSuccess(data) {
  console.log('保存成功:', data)
  // 可以跳转到列表页或其他操作
}
</script>

<template>
  <DuxPageForm
    path="/api/users"
    action="create"
    :data="formData"
    size="large"
    @success="handleSuccess"
  >
    <template #default="{ form, isLoading }">
      <DuxFormLayout label-placement="top" divider>
        <DuxFormItem label="姓名" path="name" rule="required">
          <n-input v-model:value="form.name" :disabled="isLoading" />
        </DuxFormItem>

        <DuxFormItem label="邮箱" path="email" rule="required|email">
          <n-input v-model:value="form.email" :disabled="isLoading" />
        </DuxFormItem>

        <DuxFormItem label="描述" path="description">
          <n-input
            v-model:value="form.description"
            type="textarea"
            :disabled="isLoading"
            :rows="4"
          />
        </DuxFormItem>
      </DuxFormLayout>
    </template>
  </DuxPageForm>
</template>

DuxSettingForm 设置表单

设置表单组件,适用于设置页面,支持标签页布局。

属性

属性名类型默认值说明
idstring | number-编辑时的记录 ID
action'create' | 'edit'-操作类型
pathstring-API 路径
dataMaybeRef<Record<string, any>>-表单数据
onSuccess(data?: IDataProviderResponse) => void-成功回调
onError(error?: IDataProviderError) => void-错误回调
tabsbooleanfalse是否启用标签页布局
defaultTabstring''默认激活的标签页
size'small' | 'medium' | 'large''medium'表单尺寸

插槽

插槽名说明参数
default表单内容{ form, isLoading, onSubmit, onReset, isEdit }

基础用法

vue
<script setup>
import { DuxFormItem, DuxFormLayout, DuxSettingForm } from '@duxweb/dvha-pro'
import { ref } from 'vue'

const settingsData = ref({
  siteName: '',
  siteUrl: '',
  emailEnabled: false,
  emailHost: '',
  emailPort: 587
})
</script>

<template>
  <DuxSettingForm
    path="/api/settings"
    action="edit"
    :data="settingsData"
    size="large"
  >
    <template #default="{ form }">
      <DuxFormLayout label-placement="setting" divider>
        <DuxFormItem label="站点名称" path="siteName" rule="required">
          <n-input v-model:value="form.siteName" />
        </DuxFormItem>

        <DuxFormItem label="站点URL" path="siteUrl" rule="required|url">
          <n-input v-model:value="form.siteUrl" />
        </DuxFormItem>

        <DuxFormItem label="启用邮件" path="emailEnabled">
          <n-switch v-model:value="form.emailEnabled" />
        </DuxFormItem>

        <DuxFormItem label="邮件主机" path="emailHost" rule="required_if:emailEnabled,true">
          <n-input v-model:value="form.emailHost" :disabled="!form.emailEnabled" />
        </DuxFormItem>
      </DuxFormLayout>
    </template>
  </DuxSettingForm>
</template>

标签页模式

vue
<script setup>
import { DuxFormItem, DuxFormLayout, DuxSettingForm } from '@duxweb/dvha-pro'
import { NTabPane } from 'naive-ui'
import { ref } from 'vue'

const settingsData = ref({
  // 基础设置
  siteName: '',
  siteUrl: '',
  // 邮件设置
  emailEnabled: false,
  emailHost: '',
  emailPort: 587
})
</script>

<template>
  <DuxSettingForm
    path="/api/settings"
    action="edit"
    :data="settingsData"
    tabs
    default-tab="basic"
    size="large"
  >
    <template #default="{ form }">
      <NTabPane name="basic" tab="基础设置">
        <DuxFormLayout label-placement="setting" divider>
          <DuxFormItem label="站点名称" path="siteName" rule="required">
            <n-input v-model:value="form.siteName" />
          </DuxFormItem>

          <DuxFormItem label="站点URL" path="siteUrl" rule="required|url">
            <n-input v-model:value="form.siteUrl" />
          </DuxFormItem>
        </DuxFormLayout>
      </NTabPane>

      <NTabPane name="email" tab="邮件设置">
        <DuxFormLayout label-placement="setting" divider>
          <DuxFormItem label="启用邮件" path="emailEnabled">
            <n-switch v-model:value="form.emailEnabled" />
          </DuxFormItem>

          <DuxFormItem label="邮件主机" path="emailHost" rule="required_if:emailEnabled,true">
            <n-input v-model:value="form.emailHost" :disabled="!form.emailEnabled" />
          </DuxFormItem>

          <DuxFormItem label="邮件端口" path="emailPort" rule="required_if:emailEnabled,true|numeric">
            <n-input-number v-model:value="form.emailPort" :disabled="!form.emailEnabled" />
          </DuxFormItem>
        </DuxFormLayout>
      </NTabPane>
    </template>
  </DuxSettingForm>
</template>

表单验证

所有表单组件都内置了基于 useExtendForm 的验证功能,支持 vee-validate 规则和 Yup Schema 验证。

基础验证规则

vue
<template>
  <DuxFormItem label="用户名" path="username" rule="required|min:3|max:20">
    <n-input v-model:value="form.username" />
  </DuxFormItem>

  <DuxFormItem label="邮箱" path="email" rule="required|email">
    <n-input v-model:value="form.email" />
  </DuxFormItem>

  <DuxFormItem label="年龄" path="age" rule="required|numeric|min_value:18">
    <n-input-number v-model:value="form.age" />
  </DuxFormItem>
</template>

Yup Schema 验证

vue
<script setup>
import * as yup from 'yup'

const validationSchema = yup.object({
  username: yup.string()
    .required('用户名是必填的')
    .min(3, '用户名至少3个字符')
    .max(20, '用户名最多20个字符'),
  email: yup.string()
    .required('邮箱是必填的')
    .email('请输入有效邮箱'),
  age: yup.number()
    .required('年龄是必填的')
    .min(18, '年龄必须大于18岁')
})
</script>

<template>
  <DuxModalForm
    path="/api/users"
    action="create"
    :data="formData"
    :rules="validationSchema"
  >
    <!-- 表单项 -->
  </DuxModalForm>
</template>