基于elementplus的弹窗嵌套表单进行二次封装
所见即所得:简单封装方便工作
ProForm.vue代码:
<!--
* @Author: 忆往昔
* @LastEditTime: 2024-01-6 14:36:00
* @email: 15871856064@163.com
-->
<template>
<div class="penk-form-container">
<el-dialog
v-model="visible1"
:fullscreen="props.fullscreen"
:draggable="props.draggable"
:title="props.title"
:width="props.width || '50%'"
>
<el-form
ref="ruleFormRef"
label-width="120px"
size="large"
:model="form"
:rules="props.formConfig.rules"
>
<template v-for="item in props.formConfig.formItemConfig" :key="item.prop">
<el-form-item
:label="item.label + ':'"
:style="{ display: item.hidden == true ? 'none' : '' }"
:prop="item.prop"
>
<!-- 输入框 -->
<el-input
v-if="item.type == 'input'"
v-model="form[item.prop]"
:placeholder="item.placeholder || ''"
:clearable="item.clearable"
:disabled="item.disabled"
:type="item.inputType"
:row="item.row"
:style="{ width: item.width + 'px' }"
/>
<!-- 下拉框 -->
<el-select
v-else-if="item.type == 'select'"
v-model="form[item.prop]"
:placeholder="item.placeholder"
:clearable="item.clearable"
:disabled="item.disabled"
:style="{ width: item.width + 'px' }"
>
<el-option
v-for="option in item.data"
:key="option.value"
:label="option.label"
:value="option.value"
:disabled="option.disabled"
/>
</el-select>
<!-- 多选框 -->
<el-checkbox-group
v-else-if="item.type == 'checkbox'"
v-model="form[item.prop]"
:placeholder="item.placeholder"
:clearable="item.clearable"
:disabled="item.disabled"
:style="{ width: item.width + 'px' }"
>
<el-checkbox
v-for="option in item.data"
:key="option.value"
:label="option.value"
:disabled="option.disabled"
>{{ option.label }}</el-checkbox
>
</el-checkbox-group>
<!-- 单选框 -->
<el-radio-group
v-else-if="item.type == 'radio'"
v-model="form[item.prop]"
:placeholder="item.placeholder"
:clearable="item.clearable"
:disabled="item.disabled"
:style="{ width: item.width + 'px' }"
>
<el-radio
:label="option.value"
size="large"
v-for="option in item.data"
:key="option.label"
>{{ option.label }}</el-radio
>
</el-radio-group>
</el-form-item>
</template>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible1 = false">取消</el-button>
<el-button type="primary" @click="confirm(ruleFormRef)"> 确定 </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, watch, defineEmits, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
let form = reactive({})
const visible1 = ref(true)
const ruleFormRef = ref()
const props = defineProps({
formData: {
type: Object,
default: () => {}
},
formConfig: {
type: Object,
default: () => {}
},
visible: {
type: Boolean,
default: false
},
width: {
type: String,
default: '520px'
},
title: {
type: String,
default: '新增'
},
fullscreen: {
type: Boolean,
default: false
},
draggable: {
type: Boolean,
default: false
},
'append-to-body': {
type: Boolean,
default: false
},
'close-on-click-modal': {
type: Boolean,
default: false
}
})
// 生成事件对象,数组中就是对象名
const emit = defineEmits(['update:visible', 'confirm'])
// 监听父组件的visible,用来简介控制el-dialog的弹框开关,一般是用于开
watch(
() => props.visible,
(n, o) => {
visible1.value = n
}
)
// 监听el-dialog显示状态,再通过@update:visible 通知父组件,一般是用于关
watch(visible1, (n, o) => {
emit('update:visible', n)
})
// 每次触发,就证明父组件点了修改或者添加的按钮,传递了一个新的formData
// 需要重新给form 赋值,并且,对该表单项进行重置
watch(
() => props.formData,
(n, o) => {
resetForm(ruleFormRef.value)
form = reactive(n)
}
)
// 确定按钮触发
const confirm = async (formEl) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
emit('confirm', form)
} else {
console.log('error submit!', fields)
ElMessage({
showClose: true,
message: '请完善表单信息!',
type: 'error'
})
}
})
}
// 重置表单
const resetForm = (formEl) => {
if (!formEl) return
formEl.resetFields()
}
onMounted(() => {
console.log(props.formConfig);
// 初始化 配置弹框是否可显示
visible1.value = props.visible
// 初始化 配置formData
props.formConfig.formItemConfig.map((item) => {
form[item.prop] = ''
})
})
</script>
<style lang="scss" scoped>
.penk-form-container {
.el-table-border {
border: 1px #eee solid;
}
:deep(.el-dialog__body) {
border-top: 1px solid #eee;
}
}
</style>
组件使用示例:
<template>
<MyTable
:tableData="tableData"
:columns="columns"
:total="total"
:currentPage="listQuery.pageNo"
:pageSize="listQuery.pageSize"
@changeTableData="changeTableData"
>
<!-- <template #check="{ slotProps }">
<el-tag class="ml-2" :type="slotProps.check ? 'success' : 'danger'">
{{ checkFilter(slotProps.check) }}
</el-tag>
</template> -->
<template #operator="{ slotProps }">
<el-button type="primary" @click="setData('edit', slotProps)">编辑</el-button>
<el-button type="primary" @click="handleAddItem">新增</el-button>
<el-button type="primary" @click="handleEditItem(slotProps)">修改</el-button>
<el-button type="danger" @click="handleDel(slotProps)">删除</el-button>
</template>
</MyTable>
<!-- 表单弹框 -->
<ProForm
:title="title"
:formConfig="formConfig"
:formData="formData"
v-model:visible="visible"
append-to-body
@confirm="saveItem"
/>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import MyTable from '@/components/MyTable/MyTable.vue'
import ProForm from '@/components/ProForm/ProForm.vue'
let listQuery = ref({
pageNo: 1,
pageSize: 10
})
const tableData = ref([
{ number: '001', numberplate: '京A12345', date: '2022-01-01', check: '正常', operator: '编辑' },
{ number: '002', numberplate: '京B67890', date: '2022-02-01', check: '正常', operator: '编辑' },
{ number: '003', numberplate: '京C24680', date: '2022-03-01', check: '故障', operator: '编辑' },
{ number: '004', numberplate: '京D13579', date: '2022-04-01', check: '正常', operator: '编辑' },
{ number: '005', numberplate: '京E97531', date: '2022-05-01', check: '正常', operator: '编辑' }
])
let total = ref(0)
/**
* prop:数据项列名
* label:列名展示名
* fixed:固定列 true/right/left
* width:列宽
* show-overflow-tooltip
* type:对应列的类型 selection / index / expand
* sortable:true/false
* selectable:Function
* formatter:格式化内容 function(row, column, cellValue, index)
**/
let columns = ref([
{ prop: 'number', label: '车牌自编号' },
{ prop: 'numberplate', label: '车牌号' },
{ prop: 'date', label: '出厂日期' },
{ prop: 'check', label: '车辆状态' },
{ prop: 'operator', label: '操作', fixed: 'right' }
])
onMounted(() => {})
const changeTableData = (pageNum, pageSize) => {
listQuery.value.pageNo = pageNum
listQuery.value.pageSize = pageSize
getCarList()
}
const visible = ref(false) // 控制弹窗开关
const title = ref('') // 弹窗标题
const formData = ref({}) // 表单数据
// 表单配置项
const formConfig = {
formItemConfig: [
{
label: '类型名',
prop: 'typeName',
type: 'input'
},
{
label: '父级类型名',
prop: 'parentId',
type: 'select',
data: []
}
],
rules: {
typeName: [
{
required: true,
message: '请输入类型名',
trigger: 'blur'
}
]
}
}
// 添加数据按钮
const handleAddItem = () => {
visible.value = true
title.value = '新增'
formData.value = {}
}
// 修改数据按钮
const handleEditItem = (row) => {
visible.value = true
title.value = '修改'
formData.value = row
}
// 表单提交
const saveItem = (form) => {
console.log('提交', form)
}
</script>