基础用法
formItems 建议使用 computed 属性,当表单项属性发生变化时,便于及时更新表单配置项。
示例
代码
<template>
<form-render :form-items="formItems" :form-data="formData" ref="formRenderRef" />
<div>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button type="primary" @click="handleReset">重置</el-button>
</div>
</template>
<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ElForm, ElMessage } from 'element-plus'
const ageLabel = ref('年龄')
const ageRequired = ref(true)
const formRenderRef = ref<InstanceType<typeof ElForm>>()
const formItems = computed(() => [
{
renderType: 'el-input',
itemProps: {
prop: 'name',
label: '姓名',
rules: [
{
required: true,
message: '请输入姓名',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入姓名'
},
comEvents: {
onBlur: () => {
if (!formData.value.name) {
ElMessage.error('请输入姓名')
}
}
}
},
{
renderType: 'el-input-number',
itemProps: {
prop: 'age',
label: ageLabel.value,
rules: [
{
required: ageRequired.value,
message: '请输入年龄',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入年龄',
style: {
width: '100%'
}
}
}
])
const formData = ref({
name: '',
age: 0
})
const handleSubmit = () => {
formRenderRef.value?.validate((valid) => {
if (valid) {
ElMessage.success('提交成功')
} else {
ElMessage.error('提交失败')
}
})
}
const handleReset = () => {
formRenderRef.value?.resetFields()
}
</script>
自定义组件
renderType 为自定义组件时,需要提前全局或局部注册该自定义组件。
示例
代码
<template>
<form-render :form-items="formItems" :form-data="formData" ref="formRenderRef" />
<div>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button type="primary" @click="handleReset">重置</el-button>
</div>
</template>
<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ElForm, ElMessage } from 'element-plus'
const formRenderRef = ref<InstanceType<typeof ElForm>>()
const formItems = computed(() => [
{
renderType: 'el-input',
itemProps: {
prop: 'name',
label: '姓名',
rules: [
{
required: true,
message: '请输入姓名',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入姓名'
}
},
{
renderType: 'custom-select',
itemProps: {
prop: 'sex',
label: '性别',
rules: [
{
required: true,
message: '请选择性别',
trigger: ['change']
}
]
},
comProps: {
placeholder: '请选择性别',
options: [
{
value: 'male',
label: '男'
},
{
value: 'female',
label: '女'
}
]
}
}
])
const formData = ref({
name: '',
sex: ''
})
const handleSubmit = () => {
formRenderRef.value?.validate((valid) => {
if (valid) {
ElMessage.success('提交成功')
} else {
ElMessage.error('提交失败')
}
})
}
const handleReset = () => {
formRenderRef.value?.resetFields()
}
</script>
CustomSelect.vue
代码
<template>
<el-select v-model="selectedValue" placeholder="请选择">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
</template>
<script setup>
import { ref, defineProps } from 'vue'
const props = defineProps({
options: {
type: Array,
default: () => [],
validator: (value) => {
return value.every((item) => item.hasOwnProperty('value') && item.hasOwnProperty('label'))
}
}
})
const selectedValue = ref('')
</script>
事件
Form 事件
给 form-render 组件增加 ref 属性,用于获取表单实例,调用表单方法。具体方法名参考 Form Exposes。
示例
代码
<template>
<form-render :form-items="formItems" :form-data="formData" ref="formRenderRef" />
<div>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button type="primary" @click="handleReset">重置</el-button>
</div>
</template>
<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ElForm, ElMessage } from 'element-plus'
const ageLabel = ref('年龄')
const ageRequired = ref(true)
const formRenderRef = ref<InstanceType<typeof ElForm>>()
const formItems = computed(() => [
{
renderType: 'el-input',
itemProps: {
prop: 'name',
label: '姓名',
rules: [
{
required: true,
message: '请输入姓名',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入姓名'
},
comEvents: {
onBlur: () => {
if (!formData.value.name) {
ElMessage.error('请输入姓名')
}
}
}
},
{
renderType: 'el-input-number',
itemProps: {
prop: 'age',
label: ageLabel.value,
rules: [
{
required: ageRequired.value,
message: '请输入年龄',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入年龄',
style: {
width: '100%'
}
}
}
])
const formData = ref({
name: '',
age: 0
})
const handleSubmit = () => {
formRenderRef.value?.validate((valid) => {
if (valid) {
ElMessage.success('提交成功')
} else {
ElMessage.error('提交失败')
}
})
}
const handleReset = () => {
formRenderRef.value?.resetFields()
}
</script>
FormItem 事件
获取表单实例后,调用 getField 方法获取表单项实例,调用表单项方法。具体方法名参考 FormItem Exposes。
示例
代码
<template>
<form-render :form-items="formItems" :form-data="formData" ref="formRenderRef" />
<div>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button type="primary" @click="handleClearAgeValidate">清空年龄字段校验</el-button>
</div>
</template>
<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ElForm, ElMessage } from 'element-plus'
const ageLabel = ref('年龄')
const ageRequired = ref(true)
const formRenderRef = ref<InstanceType<typeof ElForm>>()
const formItems = computed(() => [
{
renderType: 'el-input',
itemProps: {
prop: 'name',
label: '姓名',
rules: [
{
required: true,
message: '请输入姓名',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入姓名'
},
comEvents: {
onBlur: () => {
if (!formData.value.name) {
ElMessage.error('请输入姓名')
}
}
}
},
{
renderType: 'el-input-number',
itemProps: {
prop: 'age',
label: ageLabel.value,
rules: [
{
required: ageRequired.value,
message: '请输入年龄',
trigger: ['blur', 'change']
}
]
},
comProps: {
placeholder: '请输入年龄',
style: {
width: '100%'
}
}
}
])
const formData = ref({
name: '',
age: 0
})
const handleSubmit = () => {
formRenderRef.value?.validate((valid) => {
if (valid) {
ElMessage.success('提交成功')
} else {
ElMessage.error('提交失败')
}
})
}
const handleClearAgeValidate = () => {
const ageFieldRef = formRenderRef.value?.getField('age')
ageFieldRef?.clearValidate()
}
</script>
插槽
template 插槽
renderType 设置为 slot ,在 template 标签里编写插槽内容
示例
代码
<template>
<form-render :form-items="formItems" :form-data="formData" ref="formRenderRef">
<template #image>
<el-upload
v-model:file-list="formData.image"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
multiple
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
:limit="3"
:on-exceed="handleExceed"
>
<el-button type="primary">上传图片</el-button>
<template #tip>
<div class="el-upload__tip">jpg/png files with a size less than 500KB.</div>
</template>
</el-upload>
</template>
</form-render>
<div>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button type="primary" @click="handleReset">重置</el-button>
</div>
</template>
<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ElForm, ElMessage, ElMessageBox } from 'element-plus'
const formRenderRef = ref<InstanceType<typeof ElForm>>()
const formItems = computed(() => [
{
renderType: 'el-input',
itemProps: {
prop: 'name',
label: '姓名',
rules: [
{
required: true,
message: '请输入姓名',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入姓名'
}
},
{
renderType: 'custom-select',
itemProps: {
prop: 'sex',
label: '性别',
rules: [
{
required: true,
message: '请选择性别',
trigger: ['change']
}
]
},
comProps: {
placeholder: '请选择性别',
options: [
{
value: 'male',
label: '男'
},
{
value: 'female',
label: '女'
}
]
}
},
{
renderType: 'slot',
itemProps: {
prop: 'image',
label: '头像',
rules: [
{
required: true,
message: '请上传头像',
trigger: ['change']
}
]
}
}
])
const formData = ref({
name: '',
sex: '',
image: [
{
name: 'element-plus-logo.svg',
url: 'https://element-plus.org/images/element-plus-logo.svg'
},
{
name: 'element-plus-logo2.svg',
url: 'https://element-plus.org/images/element-plus-logo.svg'
}
]
})
const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
console.log(file, uploadFiles)
}
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
console.log(uploadFile)
}
const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
ElMessage.warning(
`The limit is 3, you selected ${files.length} files this time, add up to ${
files.length + uploadFiles.length
} totally`
)
}
const beforeRemove: UploadProps['beforeRemove'] = (uploadFile, uploadFiles) => {
return ElMessageBox.confirm(`Cancel the transfer of ${uploadFile.name} ?`).then(
() => true,
() => false
)
}
const handleSubmit = () => {
formRenderRef.value?.validate((valid) => {
if (valid) {
ElMessage.success('提交成功')
} else {
ElMessage.error('提交失败')
}
})
}
const handleReset = () => {
formRenderRef.value?.resetFields()
}
</script>
jsx 插槽
renderType 正常设置,comProps 中设置 slots 属性,值为插槽名称。
示例
代码
<template>
<form-render :form-items="formItems" :form-data="formData" ref="formRenderRef" />
<div>
<el-button type="primary" @click="handleSubmit">提交</el-button>
<el-button type="primary" @click="handleReset">重置</el-button>
</div>
</template>
<script setup lang="tsx">
import { computed, ref } from 'vue'
import { ElForm, ElMessage, ElMessageBox } from 'element-plus'
const formRenderRef = ref<InstanceType<typeof ElForm>>()
const formItems = computed(() => [
{
renderType: 'el-input',
itemProps: {
prop: 'name',
label: '姓名',
rules: [
{
required: true,
message: '请输入姓名',
trigger: ['blur']
}
]
},
comProps: {
placeholder: '请输入姓名'
}
},
{
renderType: 'custom-select',
itemProps: {
prop: 'sex',
label: '性别',
rules: [
{
required: true,
message: '请选择性别',
trigger: ['change']
}
]
},
comProps: {
placeholder: '请选择性别',
options: [
{
value: 'male',
label: '男'
},
{
value: 'female',
label: '女'
}
]
}
},
{
renderType: 'el-upload',
itemProps: {
prop: 'image',
label: '头像',
rules: [
{
required: true,
message: '请上传头像',
trigger: ['change']
}
]
},
comProps: {
action: 'https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15',
multiple: true,
modelName: 'fileList',
fileList: formData.value.image,
onPreview: handlePreview,
onRemove: handleRemove,
beforeRemove: beforeRemove,
onExceed: handleExceed,
limit: 3,
slots: {
default: () => (
<>
<el-button type="primary">{imageText.value}</el-button>
</>
)
}
}
}
])
const formData = ref({
name: '',
sex: '',
image: [
{
name: 'element-plus-logo.svg',
url: 'https://element-plus.org/images/element-plus-logo.svg'
},
{
name: 'element-plus-logo2.svg',
url: 'https://element-plus.org/images/element-plus-logo.svg'
}
]
})
const imageText = ref('上传头像')
const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
console.log(file, uploadFiles)
}
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
console.log(uploadFile)
}
const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
ElMessage.warning(
`The limit is 3, you selected ${files.length} files this time, add up to ${
files.length + uploadFiles.length
} totally`
)
}
const beforeRemove: UploadProps['beforeRemove'] = (uploadFile, uploadFiles) => {
return ElMessageBox.confirm(`Cancel the transfer of ${uploadFile.name} ?`).then(
() => true,
() => false
)
}
const handleSubmit = () => {
formRenderRef.value?.validate((valid) => {
if (valid) {
ElMessage.success('提交成功')
} else {
ElMessage.error('提交失败')
}
})
}
const handleReset = () => {
formRenderRef.value?.resetFields()
}
</script>
使用
jsx插槽时,需安装@vitejs/plugin-vue-jsx插件,script标签需设置lang=tsx
API
Form 属性
| 属性 | 释义 | 说明 |
|---|---|---|
formItems | 表单配置项 | 默认 [] |
formData | 表单数据 | 默认 {} |
baseColSpan | 基础列宽度 | 默认 24 |
其他属性参考 el-form
FormItem 属性
| 属性 | 释义 | 说明 |
|---|---|---|
renderType | 表单项组件类型 | 可以为 element-plus 组件,如(el-input,el-select 等),也可以为自定义组件 |
visible | 表单项是否显示 | 默认 true |
colProps | el-col 属性 | 参考 el-col |
itemProps | el-form-item 属性 | 参考 el-form-item |
comProps | 组件属性 | 参考 el-input、el-select 或自定义组件等自身属性 |
comEvents | 组件事件 | 参考 el-input、el-select 或自定义组件等自身事件,如 onBlur,onChange 等 |