# ByForm 表单组件

基于 Element UI 的动态表单组件,支持多种表单控件类型、展开收起、自定义插槽、表单验证等功能,适用于复杂的表单场景。

注意:本组件基于 Element UI 实现,支持 Element UI 的所有功能。如需了解更多高级配置和功能,请参考 Element UI 官方文档 (opens new window)

# 基础用法

使用 formItems 属性配置表单项,支持双向绑定。

<template>
  <by-form v-model="formData" :form-items="formItems" @submit="handleSubmit" @reset="handleReset" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItems: [
        {
          field: 'name',
          type: 'input',
          label: '姓名',
          placeholder: '请输入姓名'
        },
        {
          field: 'gender',
          type: 'select',
          label: '性别',
          placeholder: '请选择性别',
          options: [
            { label: '男', value: 'male' },
            { label: '女', value: 'female' }
          ]
        },
        {
          field: 'department',
          type: 'select',
          label: '部门',
          placeholder: '请选择部门',
          reserveKeyword: true, // 保留搜索关键词
          loadOptions: () => {
            // 异步加载部门数据
            return new Promise(resolve => {
              setTimeout(() => {
                resolve([
                  { label: '研发部', value: 'dev' },
                  { label: '市场部', value: 'marketing' },
                  { label: '财务部', value: 'finance' }
                ])
              }, 1000)
            })
          }
        },
        {
          field: 'birthday',
          type: 'datepicker',
          label: '生日',
          placeholder: '请选择生日'
        },
        {
          type: 'formButtons',
          otherOptions: {
            submitText: '提交',
            resetText: '重置'
          }
        }
      ]
    }
  },
  methods: {
    handleSubmit(formData) {
      console.log('表单数据:', formData)
    },
    handleReset() {
      console.log('表单重置')
    }
  }
}
</script>

# 高级功能

# 1. 展开收起功能

支持配置展开收起功能,当表单项较多时可以隐藏部分字段,提升用户体验。

<template>
  <by-form v-model="formData" :form-items="formItems" :flexible="flexible" :is-flexible="true" @submit="handleSubmit" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      flexible: {
        foldField: ['email', 'address'], // 需要折叠的字段
        unfold: false // 默认是否展开
      },
      formItems: [
        {
          field: 'name',
          type: 'input',
          label: '姓名',
          placeholder: '请输入姓名'
        },
        {
          field: 'phone',
          type: 'input',
          label: '手机号',
          placeholder: '请输入手机号'
        },
        {
          field: 'email',
          type: 'input',
          label: '邮箱',
          placeholder: '请输入邮箱'
        },
        {
          field: 'address',
          type: 'input',
          label: '地址',
          placeholder: '请输入地址'
        },
        {
          type: 'formButtons'
        }
      ]
    }
  }
}
</script>

特性:

  • 自动检测需要折叠的字段,当 flexible.foldField 中的字段存在于 formItems 中时显示展开收起按钮
  • 支持默认展开状态配置
  • 展开收起状态会保持到组件销毁

# 2. 自定义插槽

支持通过插槽自定义表单项内容,满足复杂的业务需求。

<template>
  <by-form v-model="formData" :form-items="formItems" @submit="handleSubmit">
    <!-- 自定义表单项 -->
    <template #customField>
      <el-button @click="handleCustomAction">自定义操作</el-button>
    </template>

    <!-- 头部插槽 -->
    <template #header>
      <div class="form-header">
        <h3>用户信息</h3>
      </div>
    </template>

    <!-- 底部插槽 -->
    <template #footer>
      <div class="form-footer">
        <el-button @click="handleExport">导出数据</el-button>
      </div>
    </template>
  </by-form>
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItems: [
        {
          field: 'name',
          type: 'input',
          label: '姓名'
        },
        {
          field: 'customField',
          type: 'custom', // 自定义类型
          label: '自定义操作'
        },
        {
          type: 'formButtons'
        }
      ]
    }
  },
  methods: {
    handleCustomAction() {
      console.log('自定义操作')
    },
    handleExport() {
      console.log('导出数据')
    }
  }
}
</script>

特性:

  • 支持通过 type: 'custom' 定义自定义表单项
  • 提供 headerfooter 插槽用于添加头部和底部内容
  • 自定义插槽名称与 field 属性对应

# 3. 表单验证

支持完整的表单验证功能,包括必填验证、自定义验证规则等。

<template>
  <by-form v-model="formData" :form-items="formItems" :rules="rules" @submit="handleSubmit" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      rules: {
        name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
        email: [
          { required: true, message: '请输入邮箱', trigger: 'blur' },
          { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
        ]
      },
      formItems: [
        {
          field: 'name',
          type: 'input',
          label: '姓名',
          placeholder: '请输入姓名'
        },
        {
          field: 'email',
          type: 'input',
          label: '邮箱',
          placeholder: '请输入邮箱'
        },
        {
          type: 'formButtons'
        }
      ]
    }
  }
}
</script>

特性:

  • 支持 Element UI 的所有验证规则
  • 支持单个字段验证和全局验证
  • 验证失败时会阻止表单提交

# 4. 响应式布局

支持响应式布局配置,适配不同屏幕尺寸。

<template>
  <by-form v-model="formData" :form-items="formItems" :col-layout="colLayout" @submit="handleSubmit" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      colLayout: {
        xl: 4, // >1920px 4个
        lg: 6, // >1200px 6个
        md: 8, // >992px 8个
        sm: 12, // >768px 12个
        xs: 24 // <768px 24个
      },
      formItems: [
        {
          field: 'name',
          type: 'input',
          label: '姓名',
          placeholder: '请输入姓名'
        },
        {
          field: 'phone',
          type: 'input',
          label: '手机号',
          placeholder: '请输入手机号'
        },
        {
          type: 'formButtons'
        }
      ]
    }
  }
}
</script>

特性:

  • 支持 Element UI 的栅格系统
  • 可全局配置或单个字段配置布局
  • 自动适配不同屏幕尺寸

# 5. 自定义日期选择器

支持自定义日期选择器,提供更灵活的日期范围选择功能。

<template>
  <by-form v-model="formData" :form-items="formItems" @submit="handleSubmit" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItems: [
        {
          field: 'dateRange',
          type: 'customDatePicker',
          label: '时间范围',
          placeholder: '请选择时间范围'
        },
        {
          field: 'dateRange',
          startTimeField: 'startTime',
          endTimeField: 'endTime',
          type: 'customDatePicker',
          label: '分别绑定时间',
          placeholder: '请选择时间范围'
        },
        {
          type: 'formButtons'
        }
      ]
    }
  }
}
</script>

特性:

  • 支持时间段方式绑定(数组格式)
  • 支持分别绑定开始和结束时间(两个独立字段)
  • 提供预设时间范围快捷选择

# 6. 双数字输入框

支持范围输入,适用于价格、数量等范围查询。

<template>
  <by-form v-model="formData" :form-items="formItems" @submit="handleSubmit" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItems: [
        {
          field: 'priceRange',
          type: 'pairNumberInput',
          label: '价格范围',
          earliestPlaceholder: '最低价格',
          latestPlaceholder: '最高价格'
        },
        {
          type: 'formButtons'
        }
      ]
    }
  }
}
</script>

特性:

  • 支持数字范围输入
  • 自动验证输入格式
  • 支持自定义占位符文本

# 完整示例

<template>
  <div class="form-container">
    <by-form
      v-model="formData"
      :form-items="formItems"
      :flexible="flexible"
      :is-flexible="true"
      :rules="rules"
      :col-layout="colLayout"
      @submit="handleSubmit"
      @reset="handleReset"
      @change="handleChange"
    >
      <template #header>
        <div class="form-header">
          <h3>用户信息表单</h3>
          <p>请填写完整的用户信息</p>
        </div>
      </template>

      <template #customField>
        <el-button @click="handleCustomAction" type="primary">自定义操作</el-button>
      </template>

      <template #footer>
        <div class="form-footer">
          <el-button @click="handleExport">导出数据</el-button>
          <el-button @click="handlePreview">预览</el-button>
        </div>
      </template>
    </by-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      flexible: {
        foldField: ['email', 'address', 'remark'],
        unfold: false
      },
      colLayout: {
        xl: 6,
        lg: 8,
        md: 12,
        sm: 24,
        xs: 24
      },
      rules: {
        name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
        phone: [
          { required: true, message: '请输入手机号', trigger: 'blur' },
          { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
        ],
        email: [{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }]
      },
      formItems: [
        {
          field: 'name',
          type: 'input',
          label: '姓名',
          placeholder: '请输入姓名'
        },
        {
          field: 'phone',
          type: 'input',
          label: '手机号',
          placeholder: '请输入手机号'
        },
        {
          field: 'gender',
          type: 'select',
          label: '性别',
          placeholder: '请选择性别',
          options: [
            { label: '男', value: 'male' },
            { label: '女', value: 'female' }
          ]
        },
        {
          field: 'birthday',
          type: 'datepicker',
          label: '生日',
          placeholder: '请选择生日'
        },
        {
          field: 'email',
          type: 'input',
          label: '邮箱',
          placeholder: '请输入邮箱'
        },
        {
          field: 'address',
          type: 'input',
          label: '地址',
          placeholder: '请输入地址'
        },
        {
          field: 'customField',
          type: 'custom',
          label: '自定义操作'
        },
        {
          field: 'remark',
          type: 'input',
          label: '备注',
          placeholder: '请输入备注',
          otherOptions: {
            type: 'textarea',
            rows: 3
          }
        },
        {
          type: 'formButtons',
          otherOptions: {
            submitText: '提交',
            resetText: '重置'
          }
        }
      ]
    }
  },
  methods: {
    handleSubmit(formData) {
      console.log('表单提交:', formData)
      this.$message.success('表单提交成功')
    },
    handleReset() {
      console.log('表单重置')
      this.$message.info('表单已重置')
    },
    handleChange(event) {
      console.log('表单数据变化:', event)
    },
    handleCustomAction() {
      console.log('自定义操作')
      this.$message.info('执行自定义操作')
    },
    handleExport() {
      console.log('导出数据')
      this.$message.success('数据导出成功')
    },
    handlePreview() {
      console.log('预览数据:', this.formData)
      this.$message.info('预览功能')
    }
  }
}
</script>

<style scoped>
.form-container {
  padding: 20px;
}

.form-header {
  text-align: center;
  margin-bottom: 20px;
}

.form-header h3 {
  margin: 0 0 10px 0;
  color: #303133;
}

.form-header p {
  margin: 0;
  color: #909399;
  font-size: 14px;
}

.form-footer {
  text-align: center;
  margin-top: 20px;
}
</style>

# API

# Props

参数 说明 类型 默认值
value/v-model 表单数据对象 object {}
formItems 表单项配置数组 array []
labelWidth 表单域标签的宽度 string '100px'
inline 行内表单模式 boolean false
flexible 展开收起配置 object
isFlexible 是否显示展开按钮 boolean true
colLayout 响应式布局配置 object
rules 表单验证规则 object {}
elSize 组件尺寸 string 'mini'
itemStyle 表单项样式 object

# Events

事件名 说明 参数
change 表单项值改变时触发 (event)
submit 点击搜索按钮时触发 (formData)
reset 点击重置按钮时触发
input 表单数据双向绑定 (formData)
suffix-input-change 后置输入框值变化时触发 (event)

# Slots

插槽名 说明 参数
header 表单头部
footer 表单底部
[field] 自定义表单项

# flexible 配置

参数 说明 类型 默认值
foldField 需要折叠的字段 array []
unfold 默认是否展开 boolean false

# formItems 字段配置

参数 说明 类型 默认值
field 字段名 string
type 字段类型 string
label 标签文本 string
placeholder 占位符文本 string
options 选项数据 array []
otherOptions 其他配置选项 object {}
reserveKeyword 是否保留搜索关键词 boolean true
isHidden 是否隐藏 boolean false
colLayout 单个字段布局 object
rules 单个字段验证 array []

# 支持的字段类型

类型 说明 示例
input 输入框 文本输入
password 密码输入框 密码输入
select 选择器 下拉选择
commonSelector 通用选择器 多功能选择器
datepicker 日期选择器 日期选择
cascader 级联选择器 级联选择
switch 开关 开关控件
radioGroup 单选框组 单选按钮
checkboxGroup 多选框组 多选按钮
text 文本显示 纯文本
pairNumberInput 双数字输入框 范围输入
customDatePicker 自定义日期选择器 日期范围
custom 自定义组件 插槽内容
search 搜索按钮 单个搜索按钮
formButtons 表单按钮组 搜索+重置按钮

# 字段类型配置说明

# select 类型配置

type: 'select' 时,支持以下配置选项:

参数 说明 类型 默认值
options 选项数据 array []
loadOptions 异步加载数据函数 function null
autoLoad 是否自动加载 boolean true
reserveKeyword 是否保留搜索关键词 boolean true
otherOptions 其他配置选项 object {}

reserveKeyword 说明:

  • 当设置为 true(默认值)时,选择器会保留用户输入的搜索关键词
  • 当设置为 false 时,选择器不会保留搜索关键词,每次展开都是空白状态
  • 这个配置适用于需要保持搜索状态的场景,提升用户体验

# commonSelector 类型配置

type: 'commonSelector' 时,支持以下配置选项:

参数 说明 类型 默认值
selectorType 选择器类型 string 'select'
multiple 是否多选 boolean false
options 选项数据 array []
loadOptions 异步加载数据函数 function null
reserveKeyword 是否保留搜索关键词 boolean true
otherOptions 其他配置选项 object {}

# 注意事项

  1. 字段名唯一性formItems 中的 field 必须唯一,否则会导致数据绑定冲突
  2. 展开收起逻辑:只有当 flexible.foldField 中的字段存在于 formItems 中时,才会显示展开收起按钮
  3. 自定义插槽:使用 type: 'custom' 时,插槽名称必须与 field 属性一致
  4. 数据初始化:建议在 mounted 生命周期中初始化表单数据,确保组件正常工作
  5. 验证规则:表单验证规则支持全局配置和单个字段配置,单个字段的验证规则优先级更高
  6. 响应式布局colLayout 配置遵循 Element UI 的栅格系统,支持 xl、lg、md、sm、xs 断点

# 高级示例

# 使用通用选择器

通用选择器(commonSelector)是一个功能强大的选择器组件,支持多种选择模式和交互效果,适用于复杂的选择场景。

<template>
  <by-form v-model="formData" :form-items="formItems" @submit="handleSubmit" />
</template>

<script>
export default {
  data() {
    return {
      formData: {},
      formItems: [
        {
          field: 'user',
          type: 'commonSelector',
          label: '用户选择',
          placeholder: '请选择用户',
          selectorType: 'select', // 可选值:select、enhancedSelect、checkbox、border
          multiple: false, // 是否多选
          options: [
            { id: 1, name: '张三', initial: 'Z', status: 1 },
            { id: 2, name: '李四', initial: 'L', status: 1 },
            { id: 3, name: '王五', initial: 'W', status: 0 }
          ]
        },
        {
          field: 'departments',
          type: 'commonSelector',
          label: '部门选择',
          placeholder: '请选择部门',
          selectorType: 'checkbox', // 展开式选择器
          multiple: true, // 多选
          loadOptions: () => {
            // 异步加载数据
            return new Promise(resolve => {
              setTimeout(() => {
                resolve([
                  { id: 1, name: '研发部', initial: 'Y', status: 1 },
                  { id: 2, name: '市场部', initial: 'S', status: 1 },
                  { id: 3, name: '财务部', initial: 'C', status: 1 }
                ])
              }, 1000)
            })
          },
          otherOptions: {
            showSearchBar: true, // 显示搜索栏
            pagination: true, // 启用分页
            pageSize: 50, // 每页显示数量
            needShowLoading: true // 显示加载状态
          }
        },
        {
          field: 'projectType',
          type: 'commonSelector',
          label: '项目类型',
          placeholder: '请选择项目类型',
          selectorType: 'border', // 带边框的展开式选择器
          showSuffixInput: true, // 显示后置输入框
          suffixInputPlaceholder: '请输入备注',
          suffixInputField: 'projectRemark', // 后置输入框绑定的字段名
          options: [
            { id: 'type1', name: '类型一' },
            { id: 'type2', name: '类型二' },
            { id: 'type3', name: '类型三' }
          ]
        },
        {
          type: 'formButtons'
        }
      ]
    }
  },
  methods: {
    handleSubmit(formData) {
      console.log('表单数据:', formData)
      // 可以获取到 formData.projectType 和 formData.projectRemark
    }
  }
}
</script>

commonSelector 配置选项:

参数 说明 类型 默认值
selectorType 选择器类型(select/enhancedSelect/checkbox/border) string 'select'
multiple 是否多选 boolean false
options 选项数据 array []
loadOptions 异步加载数据的函数 function null
otherOptions.showSearchBar 是否显示搜索栏 boolean false
otherOptions.pagination 是否启用分页 boolean false
otherOptions.pageSize 每页显示数量 number 50
otherOptions.needShowLoading 是否显示加载状态 boolean false
otherOptions.forceNoExpand 是否强制不展开 boolean false
reserveKeyword 是否保留搜索关键词 boolean true
showSuffixInput 是否显示后置输入框 boolean false
suffixInputPlaceholder 后置输入框占位符 string '请输入'
suffixInputField 后置输入框绑定的字段名 string -
suffixInputOptions 后置输入框的配置选项 object {}
showSuffixBatchInput 是否显示批量输入框 boolean false
suffixBatchInputPopoverTitle 后置批量输入弹窗的标题 String '批量输入'
suffixBatchInputPopoverWidth 后置批量输入弹窗宽度 String/Number '300'

reserveKeyword 说明:

  • 当设置为 true(默认值)时,选择器会保留用户输入的搜索关键词,在展开状态下显示搜索框和已输入的关键词
  • 当设置为 false 时,选择器不会保留搜索关键词,每次展开都是空白状态
  • 这个配置适用于需要保持搜索状态的场景,提升用户体验

selectorType: 'enhancedSelect' 时,支持以下附加配置(透传到 ByCommonSelector):

参数 说明 类型 默认值
enhancedAllOptions 全量选项(用于默认值回显与对象映射) array []
enhancedTitleKey 标题字段名 string 'name'
enhancedDescriptionKey 描述字段名 string 'mobile'
enhancedDisabledKey 置灰字段名(0 置灰) string 'status'
enhancedDescriptionDisplay 是否展示描述 boolean true
enhancedCollapseTags 多选是否折叠标签 boolean false
enhancedDisabledCanSelect 置灰项是否仍可选 boolean false

示例(结合表单使用增强下拉):

<by-form
  v-model="formData"
  :form-items="[
    {
      field: 'userId',
      type: 'commonSelector',
      label: '用户',
      selectorType: 'enhancedSelect',
      placeholder: '请输入用户名,手机号搜索',
      options: enhancedSearchResults,
      enhancedAllOptions: allUsers,
      enhancedTitleKey: 'name',
      enhancedDescriptionKey: 'mobile'
    }
  ]"
  @enhanced-search="({ query, item }) => fetchUsers(query, item)"
/>

注意:通用选择器(commonSelector)基于 ByCommonSelector 组件实现,更多高级配置请参考 ByCommonSelector 文档

最后更新时间: 8/29/2025, 3:05:41 PM