bug 记录 - 使用 el-dialog 的 before-close 的坑 - 教程
需求说明
- 弹窗中内嵌一个 form 表单

- 原始代码
<script setup lang="ts"
>
import {
reactive, ref
}
from "vue"
import type {
FormRules
}
from 'element-plus'
const ruleFormRef = ref(
)
interface RuleForm {
name: string
region: number |
null
}
const ruleForm = reactive<RuleForm>
({
name: ''
,
region:
null
,
}
)
const rules = reactive<FormRules<RuleForm>>
({
name: [
{
required: true
, message: '请填写姓名'
, trigger: 'blur'
}
,
]
,
region: [
{
required: true
, message: '请选择区域编码'
, trigger: 'change'
}
,
]
}
)
const dialogVisible = ref(false
)
;
function handelDialogPop(type: string
) {
if (type == "open"
) {
dialogVisible.value = true
;
// 开启弹窗
}
else
if (type == "submit"
) {
ruleFormRef.value.validate((valid: any, fields: any
) =>
{
if (valid) {
console.log('提交成功'
)
// 关闭弹窗
ruleFormRef.value.resetFields(
)
;
dialogVisible.value = false
;
}
else {
console.log('error submit!'
, fields)
}
}
)
}
else
if (type == "cancel"
) {
// 关闭弹窗
ruleFormRef.value.resetFields(
)
;
dialogVisible.value = false
}
}
</script>
<template>
<div class="dataBox"
>
<el-button type="primary"
@click
="handelDialogPop('open')"
>开启弹窗
</el-button>
<el-dialog v-model="dialogVisible"
title="弹窗"
width="500"
>
<el-form ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="auto"
>
<el-form-item label="姓名"
prop="name"
>
<el-input v-model="ruleForm.name"
/>
</el-form-item>
<el-form-item label="区域"
prop="region"
>
<el-select v-model="ruleForm.region"
placeholder="区域编码"
>
<el-option label="第一区"
:value="1"
/>
<el-option label="第二区"
:value="2"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer"
>
<el-button type="primary"
plain @click
="handelDialogPop('cancel')"
>取消
</el-button>
<el-button type="primary"
@click
="handelDialogPop('submit')"
>提交
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
- 点击取消按钮,或者提交通过校验时,先执行了 form 表单的 resetFields 事件。此代码会将表单的值重置为初始值,并且移除所有校验。这样可以保证下次点开弹窗时,不会保留上次操作 form 的痕迹。

- 为了省事儿,我把所有对 dialog 的操作都写进了 handelDialogPop 函数里,传入 type 来区分是什么事件(这里就是出问题的关键)
发现问题
手动点击关闭按钮,或者点击 model 空白区域时,弹窗被关闭。未执行 form 表单的 resetFields 方法,所以再次打开时,弹窗保留了上次操作的痕迹(form 表单未重置)

因此需要监听 dialog 的关闭事件,官方提供了一个方法,before-close

<el-dialog v-model="dialogVisible"
title="弹窗"
width="500"
:before-close="handelDialogPop('cancel')"
>
...
- 问题出现了,一进入页面时,直接抛错。报错信息可看出,before-close 被触发了


问题解决
- 文档中表明,before-close 传参,done 说明会执行。

- 重新为 before-close 封装一个函数

完整代码
<script setup lang="ts"
>
import {
reactive, ref
}
from "vue"
import type {
FormRules
}
from 'element-plus'
const ruleFormRef = ref(
)
interface RuleForm {
name: string
region: number |
null
}
const ruleForm = reactive<RuleForm>
({
name: ''
,
region:
null
,
}
)
const rules = reactive<FormRules<RuleForm>>
({
name: [
{
required: true
, message: '请填写姓名'
, trigger: 'blur'
}
,
]
,
region: [
{
required: true
, message: '请选择区域编码'
, trigger: 'change'
}
,
]
}
)
const dialogVisible = ref(false
)
;
function beforeCloseDialog(
) {
console.log("执行了 beforeCloseDialog"
)
;
ruleFormRef.value.resetFields(
)
;
dialogVisible.value = false
}
function handelDialogPop(type: string
) {
if (type == "open"
) {
dialogVisible.value = true
}
else
if (type == "submit"
) {
ruleFormRef.value.validate((valid: any, fields: any
) =>
{
if (valid) {
console.log('提交成功'
)
beforeCloseDialog(
)
;
}
else {
console.log('error submit!'
, fields)
}
}
)
}
else
if (type == "cancel"
) {
// 关闭弹窗
beforeCloseDialog(
)
}
}
</script>
<template>
<div class="dataBox"
>
<el-button type="primary"
@click
="handelDialogPop('open')"
>开启弹窗
</el-button>
<el-dialog v-model="dialogVisible"
title="弹窗"
width="500"
:before-close="beforeCloseDialog"
>
<el-form ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="auto"
>
<el-form-item label="姓名"
prop="name"
>
<el-input v-model="ruleForm.name"
/>
</el-form-item>
<el-form-item label="区域"
prop="region"
>
<el-select v-model="ruleForm.region"
placeholder="区域编码"
>
<el-option label="第一区"
:value="1"
/>
<el-option label="第二区"
:value="2"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer"
>
<el-button type="primary"
plain @click
="handelDialogPop('cancel')"
>取消
</el-button>
<el-button type="primary"
@click
="handelDialogPop('submit')"
>提交
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
浙公网安备 33010602011771号