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>
posted on 2025-06-08 00:30  ljbguanli  阅读(15)  评论(0)    收藏  举报