ProForm 表单
基于 el-form 进行封装的 JSON 配置化动态表单,属性、方法完全兼容,用于快速构建表单
基础用法
{
"delivery": true
}
<template>
<div>
<pro-form
ref="formRef"
label-width="100px"
label-suffix=":"
:model="form"
:gutter="20"
:fields="fields"
:rules="rules"
/>
<div style="white-space: pre-wrap">
{{ JSON.stringify(form, null, 2) }}
</div>
</div>
</template>
<script setup lang="tsx">
import { ref, computed, reactive } from 'vue'
import type { ProFormFields } from '@coderhd/pro-element-plus'
import type { FormInstance } from 'element-plus'
type Form = {
name?: string
region?: string
date1?: Date
date2?: Date
delivery?: boolean
type?: string[]
resource?: string
desc?: string
}
const form = reactive<Form>({
delivery: true,
})
const rules = reactive({
name: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' },
],
region: [{ required: true, message: '请选择活动区域', trigger: 'change' }],
date1: [
{ type: 'date', required: true, message: '请选择日期', trigger: 'change' },
],
date2: [
{ type: 'date', required: true, message: '请选择时间', trigger: 'change' },
],
type: [
{
type: 'array',
required: true,
message: '请至少选择一个活动性质',
trigger: 'change',
},
],
resource: [{ required: true, message: '请选择活动资源', trigger: 'change' }],
desc: [{ required: true, message: '请填写活动形式', trigger: 'blur' }],
})
const formRef = ref<FormInstance>()
const fields = computed<ProFormFields>(() => [
{
label: '活动名称',
prop: 'name',
required: true,
component: 'ElInput',
componentProps: {
placeholder: '请输入活动名称',
clearable: true,
},
colProps: {
span: 24,
},
},
{
label: '活动区域',
prop: 'region',
required: true,
component: 'ElSelect',
componentProps: {
placeholder: '请选择活动区域',
clearable: true,
options: [
{ label: '区域一', value: 'shanghai' },
{ label: '区域二', value: 'beijing' },
],
},
colProps: {
span: 24,
},
},
{
label: '活动时间',
required: true,
render: () => (
<el-row style="flex: 1;">
<pro-col span={11}>
<el-form-item prop="date1">
<el-date-picker
type="date"
v-model={form.date1}
placeholder="选择日期"
value-format="x"
style="width: 100%;"
/>
</el-form-item>
</pro-col>
<pro-col span={2} style="text-align: center;">
-
</pro-col>
<pro-col span={11}>
<el-form-item prop="date2">
<el-time-picker
v-model={form.date2}
placeholder="选择时间"
value-format="x"
style="width: 100%;"
/>
</el-form-item>
</pro-col>
</el-row>
),
colProps: {
span: 24,
},
},
{
label: '即时配送',
prop: 'delivery',
required: true,
component: 'ElSwitch',
componentProps: {
activeText: '是',
inactiveText: '否',
},
colProps: {
span: 24,
},
},
{
label: '活动性质',
prop: 'type',
required: true,
component: 'ElCheckboxGroup',
componentProps: {
options: [
{ label: '美食/餐厅线上活动', value: '1' },
{ label: '地推活动', value: '2' },
{ label: '线下主题活动', value: '3' },
{ label: '单纯品牌曝光', value: '4' },
],
},
colProps: {
span: 24,
},
},
{
label: '特殊资源',
prop: 'resource',
required: true,
component: 'ElRadioGroup',
componentProps: {
options: [
{ label: '线上品牌商赞助', value: '1' },
{ label: '线下场地免费', value: '2' },
],
},
colProps: {
span: 24,
},
},
{
label: '活动形式',
prop: 'desc',
component: 'ElInput',
componentProps: {
type: 'textarea',
autosize: {
minRows: 4,
maxRows: 6,
},
maxlength: 300,
showWordLimit: true,
placeholder: '请输入活动形式',
clearable: true,
},
colProps: {
span: 24,
},
},
{
render: () => (
<div>
<el-button type="primary" onClick={onSubmit}>
立即创建
</el-button>
<el-button onClick={onReset}>重置</el-button>
</div>
),
colProps: {
useGrid: false,
},
},
])
const onSubmit = () => {
formRef.value?.validate((valid) => {
if (valid) {
// eslint-disable-next-line no-console
console.log('submit!', form)
} else {
// eslint-disable-next-line no-console
console.log('error submit!')
}
})
}
const onReset = () => {
formRef.value?.resetFields()
}
</script>
<style scoped></style>Attributes
ProForm属性完全继承ElForm,更多属性参考ElementPlus Form Attributes
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| fields | ProFormFields | [] | 表单项 |
| gutter | number | 0 | 参考ElementPlus Row Attributes |
| justify | enum | start | 参考ElementPlus Row Attributes |
| align | enum | —— | 参考ElementPlus Row Attributes |
| tag | string | div | 参考ElementPlus Row Attributes |
Slots
| 插槽名 | 说明 |
|---|---|
| default | 默认插槽 |
Exposes
更多实例方法参考ElementPlus Form Methods
类型定义
ts
import type { ProColProps } from '../../col/src/types'
import type {
FormProps,
FormItemProps,
TimePickerDefaultProps,
RowProps,
InputInstance,
InputNumberInstance,
InputTagInstance,
DatePickerInstance,
TimeSelectInstance,
CheckboxInstance,
CheckboxGroupInstance,
RadioInstance,
RadioGroupInstance,
SelectInstance,
SwitchInstance,
FormItemProp,
} from 'element-plus'
import type { VNodeChild } from 'vue'
export interface ComponentNamesMap {
ElInput: 'ElInput'
ElInputNumber: 'ElInputNumber'
ElInputTag: 'ElInputTag'
ElDatePicker: 'ElDatePicker'
ElTimePicker: 'ElTimePicker'
ElTimeSelect: 'ElTimeSelect'
ElCheckbox: 'ElCheckbox'
ElCheckboxGroup: 'ElCheckboxGroup'
ElRadio: 'ElRadio'
ElRadioGroup: 'ElRadioGroup'
ElSelect: 'ElSelect'
ElSwitch: 'ElSwitch'
}
export interface ComponentPropsMap {
ElInput: InputInstance['$props']
ElInputNumber: InputNumberInstance['$props']
ElInputTag: InputTagInstance['$props']
ElDatePicker: DatePickerInstance['$props']
ElTimePicker: TimePickerDefaultProps
ElTimeSelect: TimeSelectInstance['$props']
ElCheckbox: CheckboxInstance['$props']
ElCheckboxGroup: CheckboxGroupInstance['$props']
ElRadio: RadioInstance['$props']
ElRadioGroup: RadioGroupInstance['$props']
ElSelect: SelectInstance['$props']
ElSwitch: SwitchInstance['$props']
}
export interface ComponentSlotsMap {
ElInput: InputInstance['$slots']
ElInputNumber: InputNumberInstance['$slots']
ElInputTag: InputTagInstance['$slots']
ElDatePicker: DatePickerInstance['$slots']
ElTimePicker: DatePickerInstance['$slots']
ElTimeSelect: TimeSelectInstance['$slots']
ElCheckbox: CheckboxInstance['$slots']
ElCheckboxGroup: CheckboxGroupInstance['$slots']
ElRadio: RadioInstance['$slots']
ElRadioGroup: RadioGroupInstance['$slots']
ElSelect: SelectInstance['$slots']
ElSwitch: SwitchInstance['$slots']
}
/**
* 内置如下组件`Props` `Slots`类型:
* - `ElInput`
* - `ElInputNumber`
* - `ElInputTag`
* - `ElDatePicker`
* - `ElTimePicker`
* - `ElTimeSelect`
* - `ElCheckbox`
* - `ElCheckboxGroup`
* - `ElRadio`
* - `ElRadioGroup`
* - `ElSelect`
* - `ElSwitch`
*/
export type ProFormField<
T extends keyof ComponentNamesMap = keyof ComponentNamesMap,
> = Partial<FormItemProps> & {
/**
* 组件名称
*/
component?: T
/**
* 组件属性
*/
componentProps?: ComponentPropsMap[T]
/**
* 组件插槽
*/
componentSlots?: ComponentSlotsMap[T]
/**
* 栅格布局
* @default 24
*/
colProps?: ProColProps
/**
* 是否独占一行
* @default false
*/
isNewLine?: boolean
/**
* 是否隐藏表单项
* @default false
*/
hidden?: (model?: Record<string, any>) => boolean | boolean
/**
* 自定义渲染
*/
render?: () => VNodeChild | VNodeChild
}
export type ProFormFields = {
[K in keyof ComponentNamesMap]: ProFormField<K>
}[keyof ComponentNamesMap][]
export type ProFormProps = Partial<FormProps> &
Partial<RowProps> & {
/**
* 表单项
*/
fields?: ProFormFields
}
export type ProFormEmits = {
(e: 'validate', prop: FormItemProp, isValid: boolean, message: string): void
}类型扩展
ts
// types/pro-form.d.ts
import type {
ComponentNamesMap,
ComponentPropsMap,
ComponentSlotsMap,
} from '@coderhd/pro-element-plus'
import type { ButtonInstance } from 'element-plus'
declare module '@coderhd/pro-element-plus' {
// 扩展 ElButton 的类型
export interface ComponentNamesMap {
ElButton: 'ElButton'
}
export interface ComponentPropsMap {
ElButton: ButtonInstance['$props']
}
export interface ComponentSlotsMap {
ElButton: ButtonInstance['$slots']
}
}