前言
今天实现一个基于element-plus表单组件的二次封装,什么是二次封装?查看以下表单,传统表单组件是不是用<el-form>嵌套几个<el-form-item>即可实现,那么一个表单可不可以实现,传入一个对象给封装组件,通过对象的type值来进行表单的实现。当一个项目有多个不同的表单内容时,能够实现代码的复用性、可读性。

点击提交校验效果:

传统写法:
javascript
<el-form :model="form" label-width="auto" style="max-width: 600px">
<el-form-item label="Activity name">
<el-input v-model="form.name" />
</el-form-item>
</el-form>
封装后写法(封装组件命名为:form-enhance):
javascript
const formConfig = [ { key: 'name', type: 'input'} ]
<form-enhance :formConfig=formConfig />
Vite+Vue3+elemplus-plus传统表单实现:
javascript
<!-- 原始表单 -->
<script setup>
import { ref } from 'vue'
const form = ref({
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: '',
})
const onSubmit = () => {
console.log('submit!')
}
</script>
<!-- 初始表单 -->
<template>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1"
style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="form.date2" xx` style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="form.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</template>
<style scoped></style>
Vite+Vue3+elemplus-plus二次封装表单实现:
FormEnhance..vue子组件
javascript
<template>
<el-form :model="formData" :label-width="labelWidth" ref="formRef">
<template v-for="(row, rowIndex) in formConfig" :key="rowIndex">
<el-row :gutter="20">
<template v-for="item in row" :key="item.key">
<el-col :span="item.span || 24">
<!-- 日期分隔符处理 -->
<template v-if="item.type === 'separator'">
<div class="form-separator">{{ item.content || '-' }}</div>
</template>
<!-- 表单项目处理 添加规则 -->
<el-form-item v-else :label="item.label" :prop="item.key" :rules="item.rules">
<!-- input输入框 -->
<el-input v-if="item.type === 'input'" v-model="formData[item.key]"
:placeholder="item.placeholder" clearable />
<!-- select选择器 -->
<el-select v-else-if="item.type === 'select'" v-model="formData[item.key]"
:placeholder="item.placeholder" clearable>
<el-option v-for="option in item.options" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
<!-- 日期选择器 -->
<el-date-picker v-else-if="item.type === 'date'" v-model="formData[item.key]" type="date"
:placeholder="item.placeholder" style="width: 100%" />
<!-- 时间选择器 -->
<el-time-picker v-else-if="item.type === 'time'" v-model="formData[item.key]"
:placeholder="item.placeholder" style="width: 100%" />
<!-- 开关 -->
<el-switch v-else-if="item.type === 'switch'" v-model="formData[item.key]" />
<!-- 复选框组 -->
<el-checkbox-group v-else-if="item.type === 'checkbox-group'" v-model="formData[item.key]">
<el-checkbox v-for="option in item.options" :key="option.value" :label="option.value">
{{ option.label }}
</el-checkbox>
</el-checkbox-group>
<!-- 单选框组 -->
<el-radio-group v-else-if="item.type === 'radio-group'" v-model="formData[item.key]">
<el-radio v-for="option in item.options" :key="option.value" :label="option.value">
{{ option.label }}
</el-radio>
</el-radio-group>
<!-- 文本域 -->
<el-input v-else-if="item.type === 'textarea'" v-model="formData[item.key]" type="textarea"
:rows="4" />
</el-form-item>
</el-col>
</template>
</el-row>
</template>
</el-form>
</template>
<script setup>
import { ref } from 'vue'
// 接收参数
defineProps({
formData: {
type: Object,
required: true
},
formConfig: {
type: Array,
required: true,
validator: value => value.every(row => Array.isArray(row))
},
labelWidth: {
type: String,
default: '80px'
}
})
// 提交表单的方法
const formRef = ref(null);
const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
console.log('表单提交成功:', props.formData)
} else {
console.error('请完善表单!')
return false;
}
})
}
// 重置表单的方法
const resetForm = () => {
// 清空校验信息
formRef.value.clearValidate();
}
// 暴露给父组件使用
defineExpose({
submitForm,
resetForm
})
</script>
<style lang="scss" scoped>
.form-separator {
text-align: center;
line-height: 32px;
height: 100%;
}
</style>
encapsulationForm.vue 父组件
javascript
<!-- 二次封装表单 -->
<script setup>
import { ref } from 'vue'
import FormEnhance from '../common/components/FormEnhance..vue'
const formEnhanceRef = ref(null);
// 触发子组件的submitForm方法
const handleSubmit = () => {
if (formEnhanceRef.value && typeof formEnhanceRef.value.submitForm === 'function') {
formEnhanceRef.value.submitForm();
} else {
console.error("---");
}
}
// 重置处理函数
const handleReset = () => {
if (formEnhanceRef.value && typeof formEnhanceRef.value.resetForm === 'function') {
// 清除验证信息
formEnhanceRef.value.resetForm();
// 重置表单数据
for (let key in resetData.value) {
formData.value[key] = resetData.value[key];
}
} else {
console.error("-----");
}
}
// 表单数据
const formData = ref({
name: '',//活动名称
region: '', //活动区域
date1: '', // 活动时间
date2: '', // 活动时间
delivery: false, // 开关
type: [], // 活动性质
resource: '', // 活动资源
desc: '' // 活动形式
})
// 重置表单数据
const resetData = ref({
name: '',//活动名称
region: '', //活动区域
date1: '', // 活动时间
date2: '', // 活动时间
delivery: false, // 开关
type: [], // 活动性质
resource: '', // 活动资源
desc: '' // 活动形式
})
// 表单配置
const formConfig = [
// 活动名称
[
{
key: 'name',
type: 'input',
label: '活动名称',
span: 24,
placeholder: '请输入活动名称',
rules: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
]
}
],
// 活动区域
[
{
key: 'region',
type: 'select',
label: '活动区域',
span: 24,
placeholder: '请选择活动区域',
options: [
{ label: '区域一', value: 'shanghai' },
{ label: '区域二', value: 'beijing' }
],
rules: [
{ required: true, message: '请选择活动区域', trigger: 'blur' },
]
}
],
// 活动时间 (日期+分隔符+时间)
[
{
key: 'date1',
type: 'date',
label: '活动时间',
span: 11,
placeholder: '选择日期',
rules: [{ required: true, message: '请选择活动时间', trigger: 'change' }]
},
{
type: 'separator',//分隔符
span: 2
},
{
key: 'date2',
type: 'time',
span: 11,
placeholder: '选择时间',
rules: [{ required: true, message: '请选择活动时间', trigger: 'change' }]
}
],
// 即时配送
[
{
key: 'delivery',
type: 'switch',
label: '即时配送',
span: 24
}
],
// 活动性质
[
{
key: 'type',
type: 'checkbox-group',
label: '活动性质',
span: 24,
options: [
{ label: '美食/餐厅线上活动', value: '美食/餐厅线上活动' },
{ label: '地推活动', value: '地推活动' },
{ label: '线下主题活动', value: '线下主题活动' },
{ label: '单纯品牌曝光', value: '单纯品牌曝光' }
],
rules: [
{ required: true, message: '请选择活动性质', trigger: 'blur' },
]
}
],
// 特殊资源
[
{
key: 'resource',
type: 'radio-group',
label: '特殊资源',
span: 24,
options: [
{ label: '线上品牌商赞助', value: '线上品牌商赞助' },
{ label: '线下场地免费', value: '线下场地免费' }
],
rules: [
{ required: true, message: '请选择', trigger: 'blur' },
]
}
],
// 活动形式
[
{
key: 'desc',
type: 'textarea',
label: '活动形式',
span: 24,
placeholder: '请输入活动形式',
rules: [
{ required: true, message: '请输入活动形式', trigger: 'blur' },
]
}
]
]
</script>
<template>
<div class="form">
<!-- 使用FormEnhance组件 -->
<FormEnhance ref="formEnhanceRef" :form-data="formData" :form-config="formConfig" />
<!-- 提交按钮 -->
<el-button type="primary" @click="handleSubmit">提交</el-button>
<!-- 重置表单 -->
<el-button type="default" @click="handleReset">重置</el-button>
</div>
</template>
扩展:父组件点击提交和重置时,触发子组件 submitForm, resetForm 方法
子组件:el-form记得绑定ref="formRef"
javascript
// 提交表单的方法
const formRef = ref(null);
const submitForm = () => {
formRef.value.validate((valid) => {
if (valid) {
console.log('表单提交成功:', props.formData)
} else {
console.error('请完善表单!')
return false;
}
})
}
// 重置表单的方法
const resetForm = () => {
// 清空校验信息
formRef.value.clearValidate();
}
// 暴露给父组件使用
defineExpose({
submitForm,
resetForm
})
父组件调用子组件暴露出的方法:
javascript
const formEnhanceRef = ref(null);
// 触发子组件的submitForm方法
const handleSubmit = () => {
if (formEnhanceRef.value && typeof formEnhanceRef.value.submitForm === 'function') {
formEnhanceRef.value.submitForm();
} else {
console.error("---");
}
}
// 重置处理函数
const handleReset = () => {
if (formEnhanceRef.value && typeof formEnhanceRef.value.resetForm === 'function') {
// 清除验证信息
formEnhanceRef.value.resetForm();
// 重置表单数据
for (let key in resetData.value) {
formData.value[key] = resetData.value[key];
}
} else {
console.error("-----");
}
}