# 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'
定义自定义表单项 - 提供
header
和footer
插槽用于添加头部和底部内容 - 自定义插槽名称与
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 | {} |
# 注意事项
- 字段名唯一性:
formItems
中的field
必须唯一,否则会导致数据绑定冲突 - 展开收起逻辑:只有当
flexible.foldField
中的字段存在于formItems
中时,才会显示展开收起按钮 - 自定义插槽:使用
type: 'custom'
时,插槽名称必须与field
属性一致 - 数据初始化:建议在
mounted
生命周期中初始化表单数据,确保组件正常工作 - 验证规则:表单验证规则支持全局配置和单个字段配置,单个字段的验证规则优先级更高
- 响应式布局:
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 文档。