UseElForm - 表单
组件介绍
UseElForm 是基于 Element Plus 的 el-form 组件进行二次封装的高性能表单组件,旨在简化表单开发流程、统一表单配置范式、提升开发效率。该组件通过配置化的方式定义表单结构与交互逻辑,覆盖输入框、数字输入框、单选框、下拉选择器、级联选择器、日期选择器、时间选择器、开关等主流表单控件,支持行式表单(rowForm)和内联表单(inlineForm)两种展示模式,适配各类业务场景的表单开发需求。
核心亮点
- 配置化驱动开发,降低编码成本
- 一站式控件覆盖,适配全场景需求
- 字典映射自动化,简化选项渲染逻辑
- 灵活的布局与样式控制
- 精细化的交互与事件封装
- 插槽与扩展性兼容
解决痛点
- 原生 el-form 模板冗余问题
痛点:原生开发表单时,需重复编写 el-form/el-form-item/el-input 等嵌套标签,每个字段的模板结构高度相似,代码冗余且维护成本高。
解决方案:通过配置化驱动渲染表单,将重复的模板逻辑封装到组件内部,开发者仅需关注字段配置,无需编写模板。
- 校验规则重复编写与管理混乱
痛点:不同表单的相同类型字段(如手机号、邮箱)需重复编写校验规则,校验逻辑分散在各个表单组件中,难以统一维护。
解决方案:内置通用校验规则,支持全局注册自定义校验,校验规则与字段配置绑定,统一管理且可复用。
- 表单联动逻辑复杂且耦合度高
痛点:字段联动(如选择省份后加载城市、勾选某选项后显示额外字段)需手动监听 watch 或 change 事件,逻辑与模板耦合,易出错且难以维护。
解决方案:配置化定义联动规则,组件内部封装联动监听逻辑,业务侧仅需声明联动关系,无需编写监听代码。
- 自定义控件集成成本高
痛点:原生 el-form 集成自定义组件(如富文本、自定义上传)时,需手动处理值绑定、校验触发、状态同步等逻辑,适配成本高。
解决方案:提供自定义控件扩展入口,统一值绑定和校验触发逻辑,自定义组件可快速集成到表单中,无需适配底层逻辑。
- 表单状态与数据格式管理繁琐
痛点:表单禁用、只读等状态需手动控制每个字段,日期、数字等字段的格式转换需手动处理,易出现格式不一致问题。
解决方案:内置全局状态控制和数据格式化 / 反格式化能力,统一管理表单状态和数据格式,减少手动处理逻辑。
- 多端适配与布局调整效率低
痛点:原生表单需手动编写栅格布局代码适配不同屏幕,调整列数、间距时需逐个修改 el-col 属性。
解决方案:内置栅格配置项,一键设置表单列数、间距,自动适配多端布局,无需手动调整每个字段的布局属性。
使用
输入框
本例演示输入框的常用场景,包括:基础输入必填校验、单位外置、单位内置、自定义单位样式、图标前置、图标后置、金额格式化、手机号码自定义校验、身份证号码自定义校验、textarea多行文本等。其它诸如根据身份证号码自动解析年龄、性别、出生日期等联动实用功能请移步万有前端·iAdmin!
选择下拉框
本例演示选择下拉框的常用场景,包括:同步字典、异步字典、多选等。其它诸如根据选择下拉框选中的数据联动其它表单项等实用功能请移步万有前端·iAdmin!
级联选择器
本例演示级联选择器的常用场景,包括:懒加载、非懒加载字典、是否严格遵守父子节点不互相关联等。
Types
import type { DictMap, DictProps } from '@/types/dict'
/**
* inputConfig接口
*/
export interface InputConfig {
type?:
| 'text'
| 'textarea'
| 'number'
| 'password'
| 'email'
| 'search'
| 'tel'
| 'url'
prefixIcon?: string
suffixIcon?: string
clearable?: boolean
maxlength?: string
formatter?: string
parser?: string
autosize?: boolean | { minRows?: number; maxRows?: number }
rows?: number
resize?: string
showPassword?: boolean
placeholder?: string
disabled?: boolean
width?: string // 默认el-input的width为100% 可设置width为''或具体宽度值,为''则使用默认的el-input宽度
autoFocus?: boolean // 为true则对el-input使用v-focus聚焦指令
prefixContent?: string | object // el-input头部插槽内容
suffixContent?: string | object // el-input尾部插槽内容
prependContent?: string | object // el-input前置插槽内容
appendContent?: string | object // el-input后置插槽内容
unit?: string | object // 在el-input右外部显示单位
onInput?: (...args: any) => any // el-input的input事件
onKeyupEnter?: (...args: any) => any // el-input的keyup.enter事件
}
/**
* inputNumberConfig接口
*/
export interface InputNumberConfig {
min?: number
max?: number
step?: number
precision?: number
placeholder?: string
disabled?: boolean
disabledScientific?: boolean
unit?: string | object // 在el-input-number右外部显示单位
}
/**
* radioConfig接口
*/
export interface RadioConfig {
disabled?: boolean
options?: Array<{ label: string; value: string | number }> // el-radio的选项集
optionKey?: string // 当dictMap的key与formColumns的label不匹配时,通过optionKey指定dictMap的key值
props?: { value: string; label?: string } // el-radio的props配置项
reverse?: boolean // 是否反转单选框和标签的位置
onChange?: (...args: any) => any // el-radio的change事件
}
/**
* selectConfig接口
*/
export interface SelectConfig {
disabled?: boolean
multiple?: boolean
clearable?: boolean
placeholder?: string
options?: Array<{ label: string; value: string | number }> // el-select的选项集
optionKey?: string // 当dictMap的key与formColumns的label不匹配时,通过optionKey指定dictMap的key值
props?: { value: string; label?: string } // el-select的props配置项
reverse?: boolean // 是否反转单选框和标签的位置
width?: string // 默认el-select的width为100% 可设置width为''或具体宽度值,为''则使用默认的el-select宽度
onChange?: (...args: any) => any // el-select的change事件
}
/**
* cascaderConfig接口
*/
export interface CascaderConfig {
disabled?: boolean
clearable?: boolean
options?: Array<{ label: string; value: string | number }> //el-cascader的选项集
optionKey?: string // 当dictMap的key与formColumns的label不匹配时,通过optionKey指定dictMap的key值
props?: { value: string; label?: string } //el-cascader的props配置项
width?: string //默认el-cascader的width为100% 可设置width为''或具体宽度值,为''则使用默认的el-cascader宽度
onChange?: (...args: any) => any //el-select的change事件
}
/**
* datePickerConfig接口
*/
export interface DatePickerConfig {
type?:
| 'year'
| 'years'
| 'month'
| 'months'
| 'date'
| 'dates'
| 'datetime'
| 'week'
| 'datetimerange'
| 'daterange'
| 'monthrange'
| 'yearrange'
clearable?: boolean
disabledDate?: Function
placeholder?: string
startPlaceholder?: string
endPlaceholder?: string
rangeSeparator?: string
width?: string // 默认el-date-picker的width为100% 可设置width为''或具体宽度值,为''则使用默认的el-date-picker宽度
fieldProps?: string[] // 当type为daterange或datetimerange时,传递fieldProps属性可将fieldProps数组中的值与日期范围选择器选中值一一对应赋值给formModel
onCalendarChange?: Function // el-date-picker的calendar-change事件
onClear?: Function // el-date-picker的clear事件
onChange?: Function // el-date-picker的change事件
}
/**
* timePickerConfig接口
*/
export interface TimePickerConfig {
startPlaceholder?: string
endPlaceholder?: string
rangeSeparator?: string
isRange?: boolean
editable?: boolean
fieldProps?: string[] // 传递fieldProps属性可将fieldProps数组中的值与时间选择器选中值一一对应赋值给formModel
onChange?: (...args: any) => any //el-date-picker的change事件
}
/**
* timeSelectConfig接口
*/
export interface TimeSelectConfig {
startProp: string // 时间选择范围开始时间在formModel中的属性名
endProp: string // 时间选择范围结束时间在formModel中的属性名
}
/**
* switchConfig接口
*/
export interface SwitchConfig {
disabled?: boolean
activeValue?: string | number | boolean
inactiveValue?: string | number | boolean
onChange?: (...args: any) => any // el-switch的change事件
}
/**
* formColumn接口
*/
export interface FormColumn {
label: string //el-form-item的label
prop: string //el-form-item的prop
required?: boolean | object //是否为必填项 为object类型则为自定义校验
errorMessage?: string //必填项错误消息 如不指定则默认为“请输入xxx”或“请选择xxx”
span?: number //el-col的span
hideLabel?: boolean //为true则不显示label
labelWidth?: string //el-form-item的labelWidth
show?: boolean //为true则不显示当前项el-form-item
formItemClass?: string //el-form-item的class
slot?: string | boolean //slot为string类型则使用slot值作为具名插槽值 slot为boolean类型则使用prop值作为具名插槽值
inputConfig?: InputConfig //表单项为【输入框】的配置项
inputNumberConfig?: InputNumberConfig //表单项为【数字输入框】的配置项
selectConfig?: SelectConfig //表单项为【选择下拉框】的配置项
cascaderConfig?: CascaderConfig //表单项为【级联选择器】的配置项
datePickerConfig?: DatePickerConfig //表单项为【日期选择器】的配置项
timePickerConfig?: TimePickerConfig //表单项为【时间选择器】的配置项
timeSelectConfig?: TimeSelectConfig //表单项为【时间选择范围】的配置项
radioConfig?: RadioConfig //表单项为【单选框】的配置项
switchConfig?: SwitchConfig //表单项为【开关】的配置项
}
/**
* props接口
*/
export interface Props {
/**
* 表单列 必传
*/
formColumns: FormColumn[]
/**
* 表单数据 必传
*/
formModel: Record<string, unknown>
/**
* 表单模式 默认为rowForm
*/
formMode?: 'rowForm' | 'inlineForm'
/**
* 字典映射 一般数据结构为{ tableColumns[].label: Array<{ label: string, value: any }> },亦可自定义key,然后通过optionKey与其匹配
*/
dictMap?: DictMap
/**
* 字典属性 默认为{ value: 'value', label: 'label' },可通过全局配置进行设置
*/
dictProps?: DictProps
/**
* el-form-item宽度值
*/
formItemWidth?: string
/**
* label后缀
*/
labelSuffix?: string
/**
* label宽度
*/
labelWidth?: string
/**
* label定位
*/
labelPosition?: string
/**
* el-row的gutter值
*/
rowGutter?: number
/**
* el-col的span值
*/
colSpan?: 24 | 12 | 8 | 6 | 4 | 3 | 2 | 1
/**
* 是否禁用
*/
disabled?: boolean
/**
* 查询按钮loading 仅formMode为inlineForm有效
*/
queryLoading?: boolean
/**
* 是否显示底部border 仅formMode为inlineForm有效
*/
showBorberBottom?: boolean
}
/**
* emits接口
*/
export interface Emits {
/**
* 查询事件 仅formMode为inlineForm时支持
*/
(e: 'onQuery', val: Record<string, unknown> | any): void
}Props && Emits && Expose
const props = withDefaults(defineProps<Props>(), {
formMode: 'rowForm',
// 一般数据结构为{ formColumns[].label: Array<{ label: string, value: any }> },亦可自定义key,然后通过optionKey与其匹配
dictMap: () => ({}) as DictMap,
// 默认为{ value: 'value', label: 'label' } 为适配全局配置此处不再设置默认值
dictProps: () => ({}) as DictProps,
formItemWidth: '180px',
labelWidth: 'auto',
labelPosition: 'right',
rowGutter: 20,
colSpan: 12,
showBorberBottom: true
} satisfies DefaultsType<Props>)
// 仅formMode为inlineForm时支持
const emits = defineEmits<Emits>()
defineExpose({
validate,
resetFields,
clearValidate,
showInlineForm,
handleInlineFormDisplay
})